basic-memory 0.7.0__py3-none-any.whl → 0.17.4__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 +5 -1
- basic_memory/alembic/alembic.ini +119 -0
- basic_memory/alembic/env.py +130 -20
- basic_memory/alembic/migrations.py +4 -9
- basic_memory/alembic/versions/314f1ea54dc4_add_postgres_full_text_search_support_.py +131 -0
- basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +51 -0
- basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py +120 -0
- basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py +112 -0
- basic_memory/alembic/versions/6830751f5fb6_merge_multiple_heads.py +24 -0
- basic_memory/alembic/versions/9d9c1cb7d8f5_add_mtime_and_size_columns_to_entity_.py +49 -0
- basic_memory/alembic/versions/a1b2c3d4e5f6_fix_project_foreign_keys.py +49 -0
- basic_memory/alembic/versions/a2b3c4d5e6f7_add_search_index_entity_cascade.py +56 -0
- basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +44 -0
- basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +113 -0
- basic_memory/alembic/versions/e7e1f4367280_add_scan_watermark_tracking_to_project.py +37 -0
- basic_memory/alembic/versions/f8a9b2c3d4e5_add_pg_trgm_for_fuzzy_link_resolution.py +239 -0
- basic_memory/alembic/versions/g9a0b3c4d5e6_add_external_id_to_project_and_entity.py +173 -0
- basic_memory/api/app.py +87 -20
- basic_memory/api/container.py +133 -0
- basic_memory/api/routers/__init__.py +4 -1
- basic_memory/api/routers/directory_router.py +84 -0
- basic_memory/api/routers/importer_router.py +152 -0
- basic_memory/api/routers/knowledge_router.py +180 -23
- basic_memory/api/routers/management_router.py +80 -0
- basic_memory/api/routers/memory_router.py +9 -64
- basic_memory/api/routers/project_router.py +460 -0
- basic_memory/api/routers/prompt_router.py +260 -0
- basic_memory/api/routers/resource_router.py +136 -11
- basic_memory/api/routers/search_router.py +5 -5
- basic_memory/api/routers/utils.py +169 -0
- basic_memory/api/template_loader.py +292 -0
- basic_memory/api/v2/__init__.py +35 -0
- basic_memory/api/v2/routers/__init__.py +21 -0
- basic_memory/api/v2/routers/directory_router.py +93 -0
- basic_memory/api/v2/routers/importer_router.py +181 -0
- basic_memory/api/v2/routers/knowledge_router.py +427 -0
- basic_memory/api/v2/routers/memory_router.py +130 -0
- basic_memory/api/v2/routers/project_router.py +359 -0
- basic_memory/api/v2/routers/prompt_router.py +269 -0
- basic_memory/api/v2/routers/resource_router.py +286 -0
- basic_memory/api/v2/routers/search_router.py +73 -0
- basic_memory/cli/app.py +80 -10
- basic_memory/cli/auth.py +300 -0
- basic_memory/cli/commands/__init__.py +15 -2
- basic_memory/cli/commands/cloud/__init__.py +6 -0
- basic_memory/cli/commands/cloud/api_client.py +127 -0
- basic_memory/cli/commands/cloud/bisync_commands.py +110 -0
- basic_memory/cli/commands/cloud/cloud_utils.py +108 -0
- basic_memory/cli/commands/cloud/core_commands.py +195 -0
- basic_memory/cli/commands/cloud/rclone_commands.py +397 -0
- basic_memory/cli/commands/cloud/rclone_config.py +110 -0
- basic_memory/cli/commands/cloud/rclone_installer.py +263 -0
- basic_memory/cli/commands/cloud/upload.py +240 -0
- basic_memory/cli/commands/cloud/upload_command.py +124 -0
- basic_memory/cli/commands/command_utils.py +99 -0
- basic_memory/cli/commands/db.py +87 -12
- basic_memory/cli/commands/format.py +198 -0
- basic_memory/cli/commands/import_chatgpt.py +47 -223
- basic_memory/cli/commands/import_claude_conversations.py +48 -171
- basic_memory/cli/commands/import_claude_projects.py +53 -160
- basic_memory/cli/commands/import_memory_json.py +55 -111
- basic_memory/cli/commands/mcp.py +67 -11
- basic_memory/cli/commands/project.py +889 -0
- basic_memory/cli/commands/status.py +52 -34
- basic_memory/cli/commands/telemetry.py +81 -0
- basic_memory/cli/commands/tool.py +341 -0
- basic_memory/cli/container.py +84 -0
- basic_memory/cli/main.py +14 -6
- basic_memory/config.py +580 -26
- basic_memory/db.py +285 -28
- basic_memory/deps/__init__.py +293 -0
- basic_memory/deps/config.py +26 -0
- basic_memory/deps/db.py +56 -0
- basic_memory/deps/importers.py +200 -0
- basic_memory/deps/projects.py +238 -0
- basic_memory/deps/repositories.py +179 -0
- basic_memory/deps/services.py +480 -0
- basic_memory/deps.py +16 -185
- basic_memory/file_utils.py +318 -54
- basic_memory/ignore_utils.py +297 -0
- basic_memory/importers/__init__.py +27 -0
- basic_memory/importers/base.py +100 -0
- basic_memory/importers/chatgpt_importer.py +245 -0
- basic_memory/importers/claude_conversations_importer.py +192 -0
- basic_memory/importers/claude_projects_importer.py +184 -0
- basic_memory/importers/memory_json_importer.py +128 -0
- basic_memory/importers/utils.py +61 -0
- basic_memory/markdown/entity_parser.py +182 -23
- basic_memory/markdown/markdown_processor.py +70 -7
- basic_memory/markdown/plugins.py +43 -23
- basic_memory/markdown/schemas.py +1 -1
- basic_memory/markdown/utils.py +38 -14
- basic_memory/mcp/async_client.py +135 -4
- basic_memory/mcp/clients/__init__.py +28 -0
- basic_memory/mcp/clients/directory.py +70 -0
- basic_memory/mcp/clients/knowledge.py +176 -0
- basic_memory/mcp/clients/memory.py +120 -0
- basic_memory/mcp/clients/project.py +89 -0
- basic_memory/mcp/clients/resource.py +71 -0
- basic_memory/mcp/clients/search.py +65 -0
- basic_memory/mcp/container.py +110 -0
- basic_memory/mcp/project_context.py +155 -0
- basic_memory/mcp/prompts/__init__.py +19 -0
- basic_memory/mcp/prompts/ai_assistant_guide.py +70 -0
- basic_memory/mcp/prompts/continue_conversation.py +62 -0
- basic_memory/mcp/prompts/recent_activity.py +188 -0
- basic_memory/mcp/prompts/search.py +57 -0
- basic_memory/mcp/prompts/utils.py +162 -0
- basic_memory/mcp/resources/ai_assistant_guide.md +283 -0
- basic_memory/mcp/resources/project_info.py +71 -0
- basic_memory/mcp/server.py +61 -9
- basic_memory/mcp/tools/__init__.py +33 -21
- basic_memory/mcp/tools/build_context.py +120 -0
- basic_memory/mcp/tools/canvas.py +152 -0
- basic_memory/mcp/tools/chatgpt_tools.py +190 -0
- basic_memory/mcp/tools/delete_note.py +249 -0
- basic_memory/mcp/tools/edit_note.py +325 -0
- basic_memory/mcp/tools/list_directory.py +157 -0
- basic_memory/mcp/tools/move_note.py +549 -0
- basic_memory/mcp/tools/project_management.py +204 -0
- basic_memory/mcp/tools/read_content.py +281 -0
- basic_memory/mcp/tools/read_note.py +265 -0
- basic_memory/mcp/tools/recent_activity.py +528 -0
- basic_memory/mcp/tools/search.py +377 -24
- basic_memory/mcp/tools/utils.py +402 -16
- basic_memory/mcp/tools/view_note.py +78 -0
- basic_memory/mcp/tools/write_note.py +230 -0
- basic_memory/models/__init__.py +3 -2
- basic_memory/models/knowledge.py +82 -17
- basic_memory/models/project.py +93 -0
- basic_memory/models/search.py +68 -8
- basic_memory/project_resolver.py +222 -0
- basic_memory/repository/__init__.py +2 -0
- basic_memory/repository/entity_repository.py +437 -8
- basic_memory/repository/observation_repository.py +36 -3
- basic_memory/repository/postgres_search_repository.py +451 -0
- basic_memory/repository/project_info_repository.py +10 -0
- basic_memory/repository/project_repository.py +140 -0
- basic_memory/repository/relation_repository.py +79 -4
- basic_memory/repository/repository.py +148 -29
- basic_memory/repository/search_index_row.py +95 -0
- basic_memory/repository/search_repository.py +79 -268
- basic_memory/repository/search_repository_base.py +241 -0
- basic_memory/repository/sqlite_search_repository.py +437 -0
- basic_memory/runtime.py +61 -0
- basic_memory/schemas/__init__.py +22 -9
- basic_memory/schemas/base.py +131 -12
- basic_memory/schemas/cloud.py +50 -0
- basic_memory/schemas/directory.py +31 -0
- basic_memory/schemas/importer.py +35 -0
- basic_memory/schemas/memory.py +194 -25
- basic_memory/schemas/project_info.py +213 -0
- basic_memory/schemas/prompt.py +90 -0
- basic_memory/schemas/request.py +56 -2
- basic_memory/schemas/response.py +85 -28
- basic_memory/schemas/search.py +36 -35
- basic_memory/schemas/sync_report.py +72 -0
- basic_memory/schemas/v2/__init__.py +27 -0
- basic_memory/schemas/v2/entity.py +133 -0
- basic_memory/schemas/v2/resource.py +47 -0
- basic_memory/services/__init__.py +2 -1
- basic_memory/services/context_service.py +451 -138
- basic_memory/services/directory_service.py +310 -0
- basic_memory/services/entity_service.py +636 -71
- basic_memory/services/exceptions.py +21 -0
- basic_memory/services/file_service.py +402 -33
- basic_memory/services/initialization.py +216 -0
- basic_memory/services/link_resolver.py +50 -56
- basic_memory/services/project_service.py +888 -0
- basic_memory/services/search_service.py +232 -37
- basic_memory/sync/__init__.py +4 -2
- basic_memory/sync/background_sync.py +26 -0
- basic_memory/sync/coordinator.py +160 -0
- basic_memory/sync/sync_service.py +1200 -109
- basic_memory/sync/watch_service.py +432 -135
- basic_memory/telemetry.py +249 -0
- basic_memory/templates/prompts/continue_conversation.hbs +110 -0
- basic_memory/templates/prompts/search.hbs +101 -0
- basic_memory/utils.py +407 -54
- basic_memory-0.17.4.dist-info/METADATA +617 -0
- basic_memory-0.17.4.dist-info/RECORD +193 -0
- {basic_memory-0.7.0.dist-info → basic_memory-0.17.4.dist-info}/WHEEL +1 -1
- {basic_memory-0.7.0.dist-info → basic_memory-0.17.4.dist-info}/entry_points.txt +1 -0
- basic_memory/alembic/README +0 -1
- basic_memory/cli/commands/sync.py +0 -206
- basic_memory/cli/commands/tools.py +0 -157
- basic_memory/mcp/tools/knowledge.py +0 -68
- basic_memory/mcp/tools/memory.py +0 -170
- basic_memory/mcp/tools/notes.py +0 -202
- basic_memory/schemas/discovery.py +0 -28
- basic_memory/sync/file_change_scanner.py +0 -158
- basic_memory/sync/utils.py +0 -31
- basic_memory-0.7.0.dist-info/METADATA +0 -378
- basic_memory-0.7.0.dist-info/RECORD +0 -82
- {basic_memory-0.7.0.dist-info → basic_memory-0.17.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""Unified project resolution across MCP, API, and CLI.
|
|
2
|
+
|
|
3
|
+
This module provides a single canonical implementation of project resolution
|
|
4
|
+
logic, eliminating duplicated decision trees across the codebase.
|
|
5
|
+
|
|
6
|
+
The resolution follows a three-tier hierarchy:
|
|
7
|
+
1. Constrained mode: BASIC_MEMORY_MCP_PROJECT env var (highest priority)
|
|
8
|
+
2. Explicit parameter: Project passed directly to operation
|
|
9
|
+
3. Default project: Used when default_project_mode=true (lowest priority)
|
|
10
|
+
|
|
11
|
+
In cloud mode, project is required unless discovery mode is explicitly allowed.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from enum import Enum, auto
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
from loguru import logger
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ResolutionMode(Enum):
|
|
23
|
+
"""How the project was resolved."""
|
|
24
|
+
|
|
25
|
+
CLOUD_EXPLICIT = auto() # Explicit project in cloud mode
|
|
26
|
+
CLOUD_DISCOVERY = auto() # Discovery mode allowed in cloud (no project)
|
|
27
|
+
ENV_CONSTRAINT = auto() # BASIC_MEMORY_MCP_PROJECT env var
|
|
28
|
+
EXPLICIT = auto() # Explicit project parameter
|
|
29
|
+
DEFAULT = auto() # default_project with default_project_mode=true
|
|
30
|
+
NONE = auto() # No resolution possible
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class ResolvedProject:
|
|
35
|
+
"""Result of project resolution.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
project: The resolved project name, or None if not resolved
|
|
39
|
+
mode: How the project was resolved
|
|
40
|
+
reason: Human-readable explanation of resolution
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
project: Optional[str]
|
|
44
|
+
mode: ResolutionMode
|
|
45
|
+
reason: str
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def is_resolved(self) -> bool:
|
|
49
|
+
"""Whether a project was successfully resolved."""
|
|
50
|
+
return self.project is not None
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def is_discovery_mode(self) -> bool:
|
|
54
|
+
"""Whether we're in discovery mode (no specific project)."""
|
|
55
|
+
return self.mode == ResolutionMode.CLOUD_DISCOVERY or (
|
|
56
|
+
self.mode == ResolutionMode.NONE and self.project is None
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class ProjectResolver:
|
|
62
|
+
"""Unified project resolution logic.
|
|
63
|
+
|
|
64
|
+
Resolves the effective project given requested project, environment
|
|
65
|
+
constraints, and configuration settings.
|
|
66
|
+
|
|
67
|
+
This is the single canonical implementation of project resolution,
|
|
68
|
+
used by MCP tools, API routes, and CLI commands.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
cloud_mode: Whether running in cloud mode (project required)
|
|
72
|
+
default_project_mode: Whether to use default project when not specified
|
|
73
|
+
default_project: The default project name
|
|
74
|
+
constrained_project: Optional env-constrained project override
|
|
75
|
+
(typically from BASIC_MEMORY_MCP_PROJECT)
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
cloud_mode: bool = False
|
|
79
|
+
default_project_mode: bool = False
|
|
80
|
+
default_project: Optional[str] = None
|
|
81
|
+
constrained_project: Optional[str] = None
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def from_env(
|
|
85
|
+
cls,
|
|
86
|
+
cloud_mode: bool = False,
|
|
87
|
+
default_project_mode: bool = False,
|
|
88
|
+
default_project: Optional[str] = None,
|
|
89
|
+
) -> "ProjectResolver":
|
|
90
|
+
"""Create resolver with constrained_project from environment.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
cloud_mode: Whether running in cloud mode
|
|
94
|
+
default_project_mode: Whether to use default project when not specified
|
|
95
|
+
default_project: The default project name
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
ProjectResolver configured with current environment
|
|
99
|
+
"""
|
|
100
|
+
constrained = os.environ.get("BASIC_MEMORY_MCP_PROJECT")
|
|
101
|
+
return cls(
|
|
102
|
+
cloud_mode=cloud_mode,
|
|
103
|
+
default_project_mode=default_project_mode,
|
|
104
|
+
default_project=default_project,
|
|
105
|
+
constrained_project=constrained,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def resolve(
|
|
109
|
+
self,
|
|
110
|
+
project: Optional[str] = None,
|
|
111
|
+
allow_discovery: bool = False,
|
|
112
|
+
) -> ResolvedProject:
|
|
113
|
+
"""Resolve project using the three-tier hierarchy.
|
|
114
|
+
|
|
115
|
+
Resolution order:
|
|
116
|
+
1. Cloud mode check (project required unless discovery allowed)
|
|
117
|
+
2. Constrained project from env var (highest priority in local mode)
|
|
118
|
+
3. Explicit project parameter
|
|
119
|
+
4. Default project if default_project_mode=true
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
project: Optional explicit project parameter
|
|
123
|
+
allow_discovery: If True, allows returning None in cloud mode
|
|
124
|
+
for discovery operations (e.g., recent_activity across projects)
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
ResolvedProject with project name, resolution mode, and reason
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
ValueError: If in cloud mode and no project specified (unless discovery allowed)
|
|
131
|
+
"""
|
|
132
|
+
# --- Cloud Mode Handling ---
|
|
133
|
+
# In cloud mode, project is required unless discovery is explicitly allowed
|
|
134
|
+
if self.cloud_mode:
|
|
135
|
+
if project:
|
|
136
|
+
logger.debug(f"Cloud mode: using explicit project '{project}'")
|
|
137
|
+
return ResolvedProject(
|
|
138
|
+
project=project,
|
|
139
|
+
mode=ResolutionMode.CLOUD_EXPLICIT,
|
|
140
|
+
reason=f"Explicit project in cloud mode: {project}",
|
|
141
|
+
)
|
|
142
|
+
elif allow_discovery:
|
|
143
|
+
logger.debug("Cloud mode: discovery mode allowed, no project required")
|
|
144
|
+
return ResolvedProject(
|
|
145
|
+
project=None,
|
|
146
|
+
mode=ResolutionMode.CLOUD_DISCOVERY,
|
|
147
|
+
reason="Discovery mode enabled in cloud",
|
|
148
|
+
)
|
|
149
|
+
else:
|
|
150
|
+
raise ValueError("No project specified. Project is required for cloud mode.")
|
|
151
|
+
|
|
152
|
+
# --- Local Mode: Three-Tier Hierarchy ---
|
|
153
|
+
|
|
154
|
+
# Priority 1: CLI constraint overrides everything
|
|
155
|
+
if self.constrained_project:
|
|
156
|
+
logger.debug(f"Using CLI constrained project: {self.constrained_project}")
|
|
157
|
+
return ResolvedProject(
|
|
158
|
+
project=self.constrained_project,
|
|
159
|
+
mode=ResolutionMode.ENV_CONSTRAINT,
|
|
160
|
+
reason=f"Environment constraint: BASIC_MEMORY_MCP_PROJECT={self.constrained_project}",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Priority 2: Explicit project parameter
|
|
164
|
+
if project:
|
|
165
|
+
logger.debug(f"Using explicit project parameter: {project}")
|
|
166
|
+
return ResolvedProject(
|
|
167
|
+
project=project,
|
|
168
|
+
mode=ResolutionMode.EXPLICIT,
|
|
169
|
+
reason=f"Explicit parameter: {project}",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Priority 3: Default project mode
|
|
173
|
+
if self.default_project_mode and self.default_project:
|
|
174
|
+
logger.debug(f"Using default project from config: {self.default_project}")
|
|
175
|
+
return ResolvedProject(
|
|
176
|
+
project=self.default_project,
|
|
177
|
+
mode=ResolutionMode.DEFAULT,
|
|
178
|
+
reason=f"Default project mode: {self.default_project}",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# No resolution possible
|
|
182
|
+
logger.debug("No project resolution possible")
|
|
183
|
+
return ResolvedProject(
|
|
184
|
+
project=None,
|
|
185
|
+
mode=ResolutionMode.NONE,
|
|
186
|
+
reason="No project specified and default_project_mode is disabled",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def require_project(
|
|
190
|
+
self,
|
|
191
|
+
project: Optional[str] = None,
|
|
192
|
+
error_message: Optional[str] = None,
|
|
193
|
+
) -> ResolvedProject:
|
|
194
|
+
"""Resolve project, raising an error if not resolved.
|
|
195
|
+
|
|
196
|
+
Convenience method for operations that require a project.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
project: Optional explicit project parameter
|
|
200
|
+
error_message: Custom error message if project not resolved
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
ResolvedProject (always with a non-None project)
|
|
204
|
+
|
|
205
|
+
Raises:
|
|
206
|
+
ValueError: If project could not be resolved
|
|
207
|
+
"""
|
|
208
|
+
result = self.resolve(project, allow_discovery=False)
|
|
209
|
+
if not result.is_resolved:
|
|
210
|
+
msg = error_message or (
|
|
211
|
+
"No project specified. Either set 'default_project_mode=true' in config, "
|
|
212
|
+
"or provide a 'project' argument."
|
|
213
|
+
)
|
|
214
|
+
raise ValueError(msg)
|
|
215
|
+
return result
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
__all__ = [
|
|
219
|
+
"ProjectResolver",
|
|
220
|
+
"ResolvedProject",
|
|
221
|
+
"ResolutionMode",
|
|
222
|
+
]
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from .entity_repository import EntityRepository
|
|
2
2
|
from .observation_repository import ObservationRepository
|
|
3
|
+
from .project_repository import ProjectRepository
|
|
3
4
|
from .relation_repository import RelationRepository
|
|
4
5
|
|
|
5
6
|
__all__ = [
|
|
6
7
|
"EntityRepository",
|
|
7
8
|
"ObservationRepository",
|
|
9
|
+
"ProjectRepository",
|
|
8
10
|
"RelationRepository",
|
|
9
11
|
]
|