basic-memory 0.5.0__py3-none-any.whl → 0.7.0__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 +1 -1
- basic_memory/api/app.py +7 -0
- basic_memory/api/routers/knowledge_router.py +0 -8
- basic_memory/api/routers/memory_router.py +26 -10
- basic_memory/api/routers/resource_router.py +14 -8
- basic_memory/api/routers/search_router.py +17 -9
- basic_memory/cli/app.py +1 -1
- basic_memory/cli/commands/db.py +11 -8
- basic_memory/cli/commands/import_chatgpt.py +31 -27
- basic_memory/cli/commands/import_claude_conversations.py +29 -27
- basic_memory/cli/commands/import_claude_projects.py +30 -29
- basic_memory/cli/commands/import_memory_json.py +28 -26
- basic_memory/cli/commands/status.py +8 -6
- basic_memory/cli/commands/sync.py +6 -3
- basic_memory/cli/commands/tools.py +157 -0
- basic_memory/cli/main.py +1 -4
- basic_memory/config.py +5 -0
- basic_memory/db.py +1 -0
- basic_memory/deps.py +5 -1
- basic_memory/mcp/tools/knowledge.py +26 -14
- basic_memory/mcp/tools/memory.py +48 -29
- basic_memory/mcp/tools/notes.py +66 -72
- basic_memory/mcp/tools/search.py +13 -4
- basic_memory/repository/search_repository.py +3 -0
- basic_memory/schemas/memory.py +3 -0
- basic_memory/schemas/request.py +1 -1
- basic_memory/schemas/search.py +2 -0
- basic_memory/services/context_service.py +14 -6
- basic_memory/services/search_service.py +3 -1
- basic_memory/sync/sync_service.py +98 -89
- basic_memory/utils.py +32 -4
- {basic_memory-0.5.0.dist-info → basic_memory-0.7.0.dist-info}/METADATA +2 -1
- {basic_memory-0.5.0.dist-info → basic_memory-0.7.0.dist-info}/RECORD +36 -35
- {basic_memory-0.5.0.dist-info → basic_memory-0.7.0.dist-info}/WHEEL +0 -0
- {basic_memory-0.5.0.dist-info → basic_memory-0.7.0.dist-info}/entry_points.txt +0 -0
- {basic_memory-0.5.0.dist-info → basic_memory-0.7.0.dist-info}/licenses/LICENSE +0 -0
basic_memory/mcp/tools/search.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Search tools for Basic Memory MCP server."""
|
|
2
2
|
|
|
3
|
+
import logfire
|
|
3
4
|
from loguru import logger
|
|
4
5
|
|
|
5
6
|
from basic_memory.mcp.server import mcp
|
|
@@ -11,7 +12,7 @@ from basic_memory.mcp.async_client import client
|
|
|
11
12
|
@mcp.tool(
|
|
12
13
|
description="Search across all content in basic-memory, including documents and entities",
|
|
13
14
|
)
|
|
14
|
-
async def search(query: SearchQuery) -> SearchResponse:
|
|
15
|
+
async def search(query: SearchQuery, page: int = 1, page_size: int = 10) -> SearchResponse:
|
|
15
16
|
"""Search across all content in basic-memory.
|
|
16
17
|
|
|
17
18
|
Args:
|
|
@@ -20,10 +21,18 @@ async def search(query: SearchQuery) -> SearchResponse:
|
|
|
20
21
|
- types: Optional list of content types to search ("document" or "entity")
|
|
21
22
|
- entity_types: Optional list of entity types to filter by
|
|
22
23
|
- after_date: Optional date filter for recent content
|
|
24
|
+
page: the page number of results to return (default 1)
|
|
25
|
+
page_size: the number of results to return per page (default 10)
|
|
23
26
|
|
|
24
27
|
Returns:
|
|
25
28
|
SearchResponse with search results and metadata
|
|
26
29
|
"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
with logfire.span("Searching for {query}", query=query): # pyright: ignore [reportGeneralTypeIssues]
|
|
31
|
+
logger.info(f"Searching for {query}")
|
|
32
|
+
response = await call_post(
|
|
33
|
+
client,
|
|
34
|
+
"/search/",
|
|
35
|
+
json=query.model_dump(),
|
|
36
|
+
params={"page": page, "page_size": page_size},
|
|
37
|
+
)
|
|
38
|
+
return SearchResponse.model_validate(response.json())
|
|
@@ -114,6 +114,7 @@ class SearchRepository:
|
|
|
114
114
|
after_date: Optional[datetime] = None,
|
|
115
115
|
entity_types: Optional[List[str]] = None,
|
|
116
116
|
limit: int = 10,
|
|
117
|
+
offset: int = 0,
|
|
117
118
|
) -> List[SearchIndexRow]:
|
|
118
119
|
"""Search across all indexed content with fuzzy matching."""
|
|
119
120
|
conditions = []
|
|
@@ -169,6 +170,7 @@ class SearchRepository:
|
|
|
169
170
|
|
|
170
171
|
# set limit on search query
|
|
171
172
|
params["limit"] = limit
|
|
173
|
+
params["offset"] = offset
|
|
172
174
|
|
|
173
175
|
# Build WHERE clause
|
|
174
176
|
where_clause = " AND ".join(conditions) if conditions else "1=1"
|
|
@@ -194,6 +196,7 @@ class SearchRepository:
|
|
|
194
196
|
WHERE {where_clause}
|
|
195
197
|
ORDER BY score ASC {order_by_clause}
|
|
196
198
|
LIMIT :limit
|
|
199
|
+
OFFSET :offset
|
|
197
200
|
"""
|
|
198
201
|
|
|
199
202
|
logger.debug(f"Search {sql} params: {params}")
|
basic_memory/schemas/memory.py
CHANGED
basic_memory/schemas/request.py
CHANGED
basic_memory/schemas/search.py
CHANGED
|
@@ -54,11 +54,13 @@ class ContextService:
|
|
|
54
54
|
types: Optional[List[SearchItemType]] = None,
|
|
55
55
|
depth: int = 1,
|
|
56
56
|
since: Optional[datetime] = None,
|
|
57
|
-
|
|
57
|
+
limit=10,
|
|
58
|
+
offset=0,
|
|
59
|
+
max_related: int = 10,
|
|
58
60
|
):
|
|
59
61
|
"""Build rich context from a memory:// URI."""
|
|
60
62
|
logger.debug(
|
|
61
|
-
f"Building context for URI: '{memory_url}' depth: '{depth}' since: '{since}'
|
|
63
|
+
f"Building context for URI: '{memory_url}' depth: '{depth}' since: '{since}' limit: '{limit}' offset: '{offset}' max_related: '{max_related}'"
|
|
62
64
|
)
|
|
63
65
|
|
|
64
66
|
if memory_url:
|
|
@@ -66,15 +68,21 @@ class ContextService:
|
|
|
66
68
|
# Pattern matching - use search
|
|
67
69
|
if "*" in path:
|
|
68
70
|
logger.debug(f"Pattern search for '{path}'")
|
|
69
|
-
primary = await self.search_repository.search(
|
|
71
|
+
primary = await self.search_repository.search(
|
|
72
|
+
permalink_match=path, limit=limit, offset=offset
|
|
73
|
+
)
|
|
70
74
|
|
|
71
75
|
# Direct lookup for exact path
|
|
72
76
|
else:
|
|
73
77
|
logger.debug(f"Direct lookup for '{path}'")
|
|
74
|
-
primary = await self.search_repository.search(
|
|
78
|
+
primary = await self.search_repository.search(
|
|
79
|
+
permalink=path, limit=limit, offset=offset
|
|
80
|
+
)
|
|
75
81
|
else:
|
|
76
82
|
logger.debug(f"Build context for '{types}'")
|
|
77
|
-
primary = await self.search_repository.search(
|
|
83
|
+
primary = await self.search_repository.search(
|
|
84
|
+
types=types, after_date=since, limit=limit, offset=offset
|
|
85
|
+
)
|
|
78
86
|
|
|
79
87
|
# Get type_id pairs for traversal
|
|
80
88
|
|
|
@@ -83,7 +91,7 @@ class ContextService:
|
|
|
83
91
|
|
|
84
92
|
# Find related content
|
|
85
93
|
related = await self.find_related(
|
|
86
|
-
type_id_pairs, max_depth=depth, since=since, max_results=
|
|
94
|
+
type_id_pairs, max_depth=depth, since=since, max_results=max_related
|
|
87
95
|
)
|
|
88
96
|
logger.debug(f"Found {len(related)} related results")
|
|
89
97
|
for r in related:
|
|
@@ -51,7 +51,7 @@ class SearchService:
|
|
|
51
51
|
|
|
52
52
|
logger.info("Reindex complete")
|
|
53
53
|
|
|
54
|
-
async def search(self, query: SearchQuery) -> List[SearchIndexRow]:
|
|
54
|
+
async def search(self, query: SearchQuery, limit=10, offset=0) -> List[SearchIndexRow]:
|
|
55
55
|
"""Search across all indexed content.
|
|
56
56
|
|
|
57
57
|
Supports three modes:
|
|
@@ -84,6 +84,8 @@ class SearchService:
|
|
|
84
84
|
types=query.types,
|
|
85
85
|
entity_types=query.entity_types,
|
|
86
86
|
after_date=after_date,
|
|
87
|
+
limit=limit,
|
|
88
|
+
offset=offset,
|
|
87
89
|
)
|
|
88
90
|
|
|
89
91
|
return results
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict
|
|
5
5
|
|
|
6
|
+
import logfire
|
|
6
7
|
from loguru import logger
|
|
7
8
|
from sqlalchemy.exc import IntegrityError
|
|
8
9
|
|
|
@@ -61,105 +62,113 @@ class SyncService:
|
|
|
61
62
|
|
|
62
63
|
async def sync(self, directory: Path) -> SyncReport:
|
|
63
64
|
"""Sync knowledge files with database."""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
|
|
66
|
+
with logfire.span("sync", directory=directory): # pyright: ignore [reportGeneralTypeIssues]
|
|
67
|
+
changes = await self.scanner.find_knowledge_changes(directory)
|
|
68
|
+
logger.info(f"Found {changes.total_changes} knowledge changes")
|
|
69
|
+
|
|
70
|
+
# Handle moves first
|
|
71
|
+
for old_path, new_path in changes.moves.items():
|
|
72
|
+
logger.debug(f"Moving entity: {old_path} -> {new_path}")
|
|
73
|
+
entity = await self.entity_repository.get_by_file_path(old_path)
|
|
74
|
+
if entity:
|
|
75
|
+
# Update file_path but keep the same permalink for link stability
|
|
76
|
+
updated = await self.entity_repository.update(
|
|
77
|
+
entity.id, {"file_path": new_path, "checksum": changes.checksums[new_path]}
|
|
78
|
+
)
|
|
79
|
+
# update search index
|
|
80
|
+
if updated:
|
|
81
|
+
await self.search_service.index_entity(updated)
|
|
82
|
+
|
|
83
|
+
# Handle deletions next
|
|
84
|
+
# remove rows from db for files no longer present
|
|
85
|
+
for path in changes.deleted:
|
|
86
|
+
await self.handle_entity_deletion(path)
|
|
87
|
+
|
|
88
|
+
# Parse files that need updating
|
|
89
|
+
parsed_entities: Dict[str, EntityMarkdown] = {}
|
|
90
|
+
|
|
91
|
+
for path in [*changes.new, *changes.modified]:
|
|
92
|
+
entity_markdown = await self.entity_parser.parse_file(directory / path)
|
|
93
|
+
parsed_entities[path] = entity_markdown
|
|
94
|
+
|
|
95
|
+
# First pass: Create/update entities
|
|
96
|
+
# entities will have a null checksum to indicate they are not complete
|
|
97
|
+
for path, entity_markdown in parsed_entities.items():
|
|
98
|
+
# Get unique permalink and update markdown if needed
|
|
99
|
+
permalink = await self.entity_service.resolve_permalink(
|
|
100
|
+
Path(path), markdown=entity_markdown
|
|
75
101
|
)
|
|
76
|
-
# update search index
|
|
77
|
-
if updated:
|
|
78
|
-
await self.search_service.index_entity(updated)
|
|
79
|
-
|
|
80
|
-
# Handle deletions next
|
|
81
|
-
# remove rows from db for files no longer present
|
|
82
|
-
for path in changes.deleted:
|
|
83
|
-
await self.handle_entity_deletion(path)
|
|
84
|
-
|
|
85
|
-
# Parse files that need updating
|
|
86
|
-
parsed_entities: Dict[str, EntityMarkdown] = {}
|
|
87
|
-
|
|
88
|
-
for path in [*changes.new, *changes.modified]:
|
|
89
|
-
entity_markdown = await self.entity_parser.parse_file(directory / path)
|
|
90
|
-
parsed_entities[path] = entity_markdown
|
|
91
|
-
|
|
92
|
-
# First pass: Create/update entities
|
|
93
|
-
# entities will have a null checksum to indicate they are not complete
|
|
94
|
-
for path, entity_markdown in parsed_entities.items():
|
|
95
|
-
# Get unique permalink and update markdown if needed
|
|
96
|
-
permalink = await self.entity_service.resolve_permalink(
|
|
97
|
-
Path(path), markdown=entity_markdown
|
|
98
|
-
)
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
if permalink != entity_markdown.frontmatter.permalink:
|
|
104
|
+
# Add/update permalink in frontmatter
|
|
105
|
+
logger.info(f"Adding permalink '{permalink}' to file: {path}")
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
# update markdown
|
|
108
|
+
entity_markdown.frontmatter.metadata["permalink"] = permalink
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
# update file frontmatter
|
|
111
|
+
updated_checksum = await file_utils.update_frontmatter(
|
|
112
|
+
directory / path, {"permalink": permalink}
|
|
113
|
+
)
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
# if the file is new, create an entity
|
|
116
|
-
if path in changes.new:
|
|
117
|
-
# Create entity with final permalink
|
|
118
|
-
logger.debug(f"Creating new entity_markdown: {path}")
|
|
119
|
-
await self.entity_service.create_entity_from_markdown(Path(path), entity_markdown)
|
|
120
|
-
# otherwise we need to update the entity and observations
|
|
121
|
-
else:
|
|
122
|
-
logger.debug(f"Updating entity_markdown: {path}")
|
|
123
|
-
await self.entity_service.update_entity_and_observations(
|
|
124
|
-
Path(path), entity_markdown
|
|
125
|
-
)
|
|
115
|
+
# Update checksum in changes report since file was modified
|
|
116
|
+
changes.checksums[path] = updated_checksum
|
|
126
117
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
# if the file is new, create an entity
|
|
119
|
+
if path in changes.new:
|
|
120
|
+
# Create entity with final permalink
|
|
121
|
+
logger.debug(f"Creating new entity_markdown: {path}")
|
|
122
|
+
await self.entity_service.create_entity_from_markdown(
|
|
123
|
+
Path(path), entity_markdown
|
|
124
|
+
)
|
|
125
|
+
# otherwise we need to update the entity and observations
|
|
126
|
+
else:
|
|
127
|
+
logger.debug(f"Updating entity_markdown: {path}")
|
|
128
|
+
await self.entity_service.update_entity_and_observations(
|
|
129
|
+
Path(path), entity_markdown
|
|
130
|
+
)
|
|
130
131
|
|
|
131
|
-
#
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
# Second pass
|
|
133
|
+
for path, entity_markdown in parsed_entities.items():
|
|
134
|
+
logger.debug(f"Updating relations for: {path}")
|
|
134
135
|
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
# Process relations
|
|
137
|
+
checksum = changes.checksums[path]
|
|
138
|
+
entity = await self.entity_service.update_entity_relations(
|
|
139
|
+
Path(path), entity_markdown
|
|
140
|
+
)
|
|
137
141
|
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
# add to search index
|
|
143
|
+
await self.search_service.index_entity(entity)
|
|
140
144
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
for relation in await self.relation_repository.find_unresolved_relations():
|
|
144
|
-
target_entity = await self.entity_service.link_resolver.resolve_link(relation.to_name)
|
|
145
|
-
# check we found a link that is not the source
|
|
146
|
-
if target_entity and target_entity.id != relation.from_id:
|
|
147
|
-
logger.debug(
|
|
148
|
-
f"Resolved forward reference: {relation.to_name} -> {target_entity.permalink}"
|
|
149
|
-
)
|
|
145
|
+
# Set final checksum to mark sync complete
|
|
146
|
+
await self.entity_repository.update(entity.id, {"checksum": checksum})
|
|
150
147
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
148
|
+
# Third pass: Try to resolve any forward references
|
|
149
|
+
logger.debug("Attempting to resolve forward references")
|
|
150
|
+
for relation in await self.relation_repository.find_unresolved_relations():
|
|
151
|
+
target_entity = await self.entity_service.link_resolver.resolve_link(
|
|
152
|
+
relation.to_name
|
|
153
|
+
)
|
|
154
|
+
# check we found a link that is not the source
|
|
155
|
+
if target_entity and target_entity.id != relation.from_id:
|
|
156
|
+
logger.debug(
|
|
157
|
+
f"Resolved forward reference: {relation.to_name} -> {target_entity.permalink}"
|
|
158
158
|
)
|
|
159
|
-
except IntegrityError:
|
|
160
|
-
logger.debug(f"Ignoring duplicate relation {relation}")
|
|
161
|
-
|
|
162
|
-
# update search index
|
|
163
|
-
await self.search_service.index_entity(target_entity)
|
|
164
159
|
|
|
165
|
-
|
|
160
|
+
try:
|
|
161
|
+
await self.relation_repository.update(
|
|
162
|
+
relation.id,
|
|
163
|
+
{
|
|
164
|
+
"to_id": target_entity.id,
|
|
165
|
+
"to_name": target_entity.title, # Update to actual title
|
|
166
|
+
},
|
|
167
|
+
)
|
|
168
|
+
except IntegrityError:
|
|
169
|
+
logger.debug(f"Ignoring duplicate relation {relation}")
|
|
170
|
+
|
|
171
|
+
# update search index
|
|
172
|
+
await self.search_service.index_entity(target_entity)
|
|
173
|
+
|
|
174
|
+
return changes
|
basic_memory/utils.py
CHANGED
|
@@ -9,8 +9,11 @@ from typing import Optional, Union
|
|
|
9
9
|
from loguru import logger
|
|
10
10
|
from unidecode import unidecode
|
|
11
11
|
|
|
12
|
+
import basic_memory
|
|
12
13
|
from basic_memory.config import config
|
|
13
14
|
|
|
15
|
+
import logfire
|
|
16
|
+
|
|
14
17
|
|
|
15
18
|
def generate_permalink(file_path: Union[Path, str]) -> str:
|
|
16
19
|
"""Generate a stable permalink from a file path.
|
|
@@ -61,19 +64,42 @@ def generate_permalink(file_path: Union[Path, str]) -> str:
|
|
|
61
64
|
return "/".join(clean_segments)
|
|
62
65
|
|
|
63
66
|
|
|
64
|
-
def setup_logging(
|
|
67
|
+
def setup_logging(
|
|
68
|
+
home_dir: Path = config.home, log_file: Optional[str] = None, console: bool = True
|
|
69
|
+
) -> None: # pragma: no cover
|
|
65
70
|
"""
|
|
66
71
|
Configure logging for the application.
|
|
72
|
+
:param home_dir: the root directory for the application
|
|
73
|
+
:param log_file: the name of the log file to write to
|
|
74
|
+
:param app: the fastapi application instance
|
|
75
|
+
:param console: whether to log to the console
|
|
67
76
|
"""
|
|
68
77
|
|
|
69
78
|
# Remove default handler and any existing handlers
|
|
70
79
|
logger.remove()
|
|
71
80
|
|
|
72
|
-
# Add file handler
|
|
73
|
-
if log_file:
|
|
81
|
+
# Add file handler if we are not running tests
|
|
82
|
+
if log_file and config.env != "test":
|
|
83
|
+
# enable pydantic logfire
|
|
84
|
+
logfire.configure(
|
|
85
|
+
code_source=logfire.CodeSource(
|
|
86
|
+
repository="https://github.com/basicmachines-co/basic-memory",
|
|
87
|
+
revision=basic_memory.__version__,
|
|
88
|
+
root_path="/src/basic_memory",
|
|
89
|
+
),
|
|
90
|
+
environment=config.env,
|
|
91
|
+
console=False,
|
|
92
|
+
)
|
|
93
|
+
logger.configure(handlers=[logfire.loguru_handler()])
|
|
94
|
+
|
|
95
|
+
# instrument code spans
|
|
96
|
+
logfire.instrument_sqlite3()
|
|
97
|
+
logfire.instrument_httpx()
|
|
98
|
+
|
|
99
|
+
# setup logger
|
|
74
100
|
log_path = home_dir / log_file
|
|
75
101
|
logger.add(
|
|
76
|
-
str(log_path),
|
|
102
|
+
str(log_path),
|
|
77
103
|
level=config.log_level,
|
|
78
104
|
rotation="100 MB",
|
|
79
105
|
retention="10 days",
|
|
@@ -85,3 +111,5 @@ def setup_logging(home_dir: Path = config.home, log_file: Optional[str] = None)
|
|
|
85
111
|
|
|
86
112
|
# Add stderr handler
|
|
87
113
|
logger.add(sys.stderr, level=config.log_level, backtrace=True, diagnose=True, colorize=True)
|
|
114
|
+
|
|
115
|
+
logger.info(f"ENV: '{config.env}' Log level: '{config.log_level}' Logging to {log_file}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basic-memory
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
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
|
|
@@ -15,6 +15,7 @@ Requires-Dist: dateparser>=1.2.0
|
|
|
15
15
|
Requires-Dist: fastapi[standard]>=0.115.8
|
|
16
16
|
Requires-Dist: greenlet>=3.1.1
|
|
17
17
|
Requires-Dist: icecream>=2.1.3
|
|
18
|
+
Requires-Dist: logfire[fastapi,httpx,sqlalchemy,sqlite3]>=3.6.0
|
|
18
19
|
Requires-Dist: loguru>=0.7.3
|
|
19
20
|
Requires-Dist: markdown-it-py>=3.0.0
|
|
20
21
|
Requires-Dist: mcp>=1.2.0
|
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
basic_memory/__init__.py,sha256=
|
|
2
|
-
basic_memory/config.py,sha256=
|
|
3
|
-
basic_memory/db.py,sha256=
|
|
4
|
-
basic_memory/deps.py,sha256=
|
|
1
|
+
basic_memory/__init__.py,sha256=2LnWS_j9nC8P5BSYmW2D9Ccx3xNj4gPQf_GElvfJcgU,122
|
|
2
|
+
basic_memory/config.py,sha256=lgihYA80A5uzSzUc3GE7aEWogndocv7J0uyYK1JCp68,1793
|
|
3
|
+
basic_memory/db.py,sha256=EVX3pgA2rah4tZpxy5wKvZSN8vVcrvo5l-hKjAXBb0U,5284
|
|
4
|
+
basic_memory/deps.py,sha256=8LkcfppQEJpiflYZxLk-SmQuL04qknbsdfzIkM_ctuY,5530
|
|
5
5
|
basic_memory/file_utils.py,sha256=gp7RCFWaddFnELIyTc1E19Rk8jJsrKshG2n8ZZR-kKA,5751
|
|
6
|
-
basic_memory/utils.py,sha256=
|
|
6
|
+
basic_memory/utils.py,sha256=SuAE8rVIGTcj9Yi2fVMhDbToVjfprU_iOiOr0U8aqIU,3352
|
|
7
7
|
basic_memory/alembic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
|
|
8
8
|
basic_memory/alembic/env.py,sha256=XqJVQhS41ba7NCPmmaSZ09_tbSLnwsY2bcpJpqx_ZTc,2107
|
|
9
9
|
basic_memory/alembic/migrations.py,sha256=CIbkMHEKZ60aDUhFGSQjv8kDNM7sazfvEYHGGcy1DBk,858
|
|
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
|
|
12
12
|
basic_memory/api/__init__.py,sha256=wCpj-21j1D0KzKl9Ql6unLBVFY0K1uGp_FeSZRKtqpk,72
|
|
13
|
-
basic_memory/api/app.py,sha256=
|
|
13
|
+
basic_memory/api/app.py,sha256=0vmDJDhKkRN1f7XDO3hqcUpXrLRmcHOH79O5x4hPtho,1573
|
|
14
14
|
basic_memory/api/routers/__init__.py,sha256=iviQ1QVYobC8huUuyRhEjcA0BDjrOUm1lXHXhJkxP9A,239
|
|
15
|
-
basic_memory/api/routers/knowledge_router.py,sha256=
|
|
16
|
-
basic_memory/api/routers/memory_router.py,sha256=
|
|
17
|
-
basic_memory/api/routers/resource_router.py,sha256=
|
|
18
|
-
basic_memory/api/routers/search_router.py,sha256=
|
|
15
|
+
basic_memory/api/routers/knowledge_router.py,sha256=LtZIXZ2cgqLesMMY8_xoyQm2WW4dnn3ZrASjZYeLMhA,5278
|
|
16
|
+
basic_memory/api/routers/memory_router.py,sha256=oBOyR-qpT8FAYvzENeBEWuWeGe6beD3GXUJ2SVhdRCw,5080
|
|
17
|
+
basic_memory/api/routers/resource_router.py,sha256=B3pd_5qJMgYro0CmLV3YIr0eol4eRtb78FYOPJzrPgA,4534
|
|
18
|
+
basic_memory/api/routers/search_router.py,sha256=WCLuAkEZ-DpwHU8RsnZg63_LDiSYbbLLlBb9Avbc2fA,1164
|
|
19
19
|
basic_memory/cli/__init__.py,sha256=arcKLAWRDhPD7x5t80MlviZeYzwHZ0GZigyy3NKVoGk,33
|
|
20
|
-
basic_memory/cli/app.py,sha256=
|
|
21
|
-
basic_memory/cli/main.py,sha256=
|
|
20
|
+
basic_memory/cli/app.py,sha256=7_HWUOW6oWncbwhuCJ5jC3z2WadSfkuTWiH_w_Rbhnk,465
|
|
21
|
+
basic_memory/cli/main.py,sha256=iVHi23ClA1hTvC5lq8dpGMmWObIjhA1QoWo_moX84os,434
|
|
22
22
|
basic_memory/cli/commands/__init__.py,sha256=OQGLaKTsOdPsp2INM_pHzmOlbVfdL0sytBNgvqTqCDY,159
|
|
23
|
-
basic_memory/cli/commands/db.py,sha256=
|
|
24
|
-
basic_memory/cli/commands/import_chatgpt.py,sha256=
|
|
25
|
-
basic_memory/cli/commands/import_claude_conversations.py,sha256=
|
|
26
|
-
basic_memory/cli/commands/import_claude_projects.py,sha256=
|
|
27
|
-
basic_memory/cli/commands/import_memory_json.py,sha256=
|
|
23
|
+
basic_memory/cli/commands/db.py,sha256=BW3VmoTKNfzkl85m9lyrx8lkk1IRb6wuAmrPKFQxNE8,906
|
|
24
|
+
basic_memory/cli/commands/import_chatgpt.py,sha256=py3q9iMlB85olQBsBcEpUt0X03hHvAmRy8iQl2dbbuc,8394
|
|
25
|
+
basic_memory/cli/commands/import_claude_conversations.py,sha256=_7n-nn1tbsaarwR25QXjYxSC_K2M0cXBTzthnCZ_4-w,7030
|
|
26
|
+
basic_memory/cli/commands/import_claude_projects.py,sha256=fvXu6wwlmfA2wJCcp8IoJnz3INefkVcFhqAX8KhnCtc,6851
|
|
27
|
+
basic_memory/cli/commands/import_memory_json.py,sha256=cS-1rxGYUC0-QsETIbA0QqbB1Cl74YcnoJRNCkMkM-o,5395
|
|
28
28
|
basic_memory/cli/commands/mcp.py,sha256=BPdThcufdriIvrDskc87a0oCC1BkZ0PZsgNao_-oNKk,611
|
|
29
|
-
basic_memory/cli/commands/status.py,sha256=
|
|
30
|
-
basic_memory/cli/commands/sync.py,sha256=
|
|
29
|
+
basic_memory/cli/commands/status.py,sha256=mnAnizd2l0OShTJyF9EGEdO7TeKDUgQVlHNXZwDDFuU,5845
|
|
30
|
+
basic_memory/cli/commands/sync.py,sha256=2Uj7Homfr403OCoPCq3rrC-OQfOhvoDqGH0F38pBQVw,7038
|
|
31
|
+
basic_memory/cli/commands/tools.py,sha256=NuLFckIW7tcRc7KUPm5ig6-iSGzTaCQiu8jXrBM8np8,5261
|
|
31
32
|
basic_memory/markdown/__init__.py,sha256=DdzioCWtDnKaq05BHYLgL_78FawEHLpLXnp-kPSVfIc,501
|
|
32
33
|
basic_memory/markdown/entity_parser.py,sha256=sJk8TRUd9cAaIjATiJn7dBQRorrYngRbd7MRVfc0Oc4,3781
|
|
33
34
|
basic_memory/markdown/markdown_processor.py,sha256=mV3pYoDTaQMEl1tA5n_XztBvNlYyH2SzKs4vnKdAet4,4952
|
|
@@ -38,10 +39,10 @@ basic_memory/mcp/__init__.py,sha256=dsDOhKqjYeIbCULbHIxfcItTbqudEuEg1Np86eq0GEQ,
|
|
|
38
39
|
basic_memory/mcp/async_client.py,sha256=vMN5nApPA428Oz4Siq2mNTiBjTcM5A5OSZTnX7_sDxE,234
|
|
39
40
|
basic_memory/mcp/server.py,sha256=L92Vit7llaKT9NlPZfxdp67C33niObmRH2QFyUhmnD0,355
|
|
40
41
|
basic_memory/mcp/tools/__init__.py,sha256=MHZmWw016N0qbtC3f186Jg1tPzh2g88_ZsCKJ0oyrrs,873
|
|
41
|
-
basic_memory/mcp/tools/knowledge.py,sha256=
|
|
42
|
-
basic_memory/mcp/tools/memory.py,sha256=
|
|
43
|
-
basic_memory/mcp/tools/notes.py,sha256=
|
|
44
|
-
basic_memory/mcp/tools/search.py,sha256=
|
|
42
|
+
basic_memory/mcp/tools/knowledge.py,sha256=JotFMQpMwidx0WLvOG4yWpwWwLmyp-PoO6bVjpQseYQ,2671
|
|
43
|
+
basic_memory/mcp/tools/memory.py,sha256=zRtwN8va9sEv6ao0dIAU63jDb49H_8IcFmZvPzypg2w,6180
|
|
44
|
+
basic_memory/mcp/tools/notes.py,sha256=6m7Xl9IN_8bkXSvV-vR8GqZZufMki5JjjWc6RlntDts,7424
|
|
45
|
+
basic_memory/mcp/tools/search.py,sha256=UFPBDzfZ60SrvAgvISO3Jt6WdNwEQKsvibQdPxC7dOg,1511
|
|
45
46
|
basic_memory/mcp/tools/utils.py,sha256=icm-Xyqw3GxooGYkXqjEjoZvIGy_Z3CPw-uUYBxR_YQ,4831
|
|
46
47
|
basic_memory/models/__init__.py,sha256=Bf0xXV_ryndogvZDiVM_Wb6iV2fHUxYNGMZNWNcZi0s,307
|
|
47
48
|
basic_memory/models/base.py,sha256=4hAXJ8CE1RnjKhb23lPd-QM7G_FXIdTowMJ9bRixspU,225
|
|
@@ -52,30 +53,30 @@ basic_memory/repository/entity_repository.py,sha256=VFLymzJ1W6AZru_s1S3U6nlqSprB
|
|
|
52
53
|
basic_memory/repository/observation_repository.py,sha256=BOcy4wARqCXu-thYyt7mPxt2A2C8TW0le3s_X9wrK6I,1701
|
|
53
54
|
basic_memory/repository/relation_repository.py,sha256=DwpTcn9z_1sZQcyMOUABz1k1VSwo_AU63x2zR7aerTk,2933
|
|
54
55
|
basic_memory/repository/repository.py,sha256=jUScHWOfcB2FajwVZ2Sbjtg-gSI2Y2rhiIaTULjvmn8,11321
|
|
55
|
-
basic_memory/repository/search_repository.py,sha256=
|
|
56
|
+
basic_memory/repository/search_repository.py,sha256=G5qnchUqhq8httnihOU77nA3mq3MNpTxqQAi96uBmRE,10122
|
|
56
57
|
basic_memory/schemas/__init__.py,sha256=eVxrtuPT7-9JIQ7UDx2J8t8xlS3u0iUkV_VLNbzvxo4,1575
|
|
57
58
|
basic_memory/schemas/base.py,sha256=epSauNNVZ2lRLATf-HIzqeberq4ZBTgxliNmjitAsWc,5538
|
|
58
59
|
basic_memory/schemas/delete.py,sha256=UAR2JK99WMj3gP-yoGWlHD3eZEkvlTSRf8QoYIE-Wfw,1180
|
|
59
60
|
basic_memory/schemas/discovery.py,sha256=6Y2tUiv9f06rFTsa8_wTH2haS2bhCfuQh0uW33hwdd8,876
|
|
60
|
-
basic_memory/schemas/memory.py,sha256=
|
|
61
|
-
basic_memory/schemas/request.py,sha256=
|
|
61
|
+
basic_memory/schemas/memory.py,sha256=BscZQOYw-dXq_qUz4qd3PrUI5618tRwNrYxKmIppU2Q,2924
|
|
62
|
+
basic_memory/schemas/request.py,sha256=58r9mPGc4Am9rR_zGzo-yqXcsrl5I6n3M5LjGK5gFFk,1626
|
|
62
63
|
basic_memory/schemas/response.py,sha256=lVYR31DTtSeFRddGWX_wQWnQgyiwX0LEpNJ4f4lKpTM,6440
|
|
63
|
-
basic_memory/schemas/search.py,sha256=
|
|
64
|
+
basic_memory/schemas/search.py,sha256=Yl7yPUEYADl4tHllTKCjIoe8ck4kVsVglIItnKN2Ei8,3319
|
|
64
65
|
basic_memory/services/__init__.py,sha256=oop6SKmzV4_NAYt9otGnupLGVCCKIVgxEcdRQWwh25I,197
|
|
65
|
-
basic_memory/services/context_service.py,sha256=
|
|
66
|
+
basic_memory/services/context_service.py,sha256=y2Kd9YRPdQbJ6uWcY71z2qCZZUt8Sb2Dy52dh2OMJxo,9651
|
|
66
67
|
basic_memory/services/entity_service.py,sha256=CoN1HVrjlT2JDaG3tfs6NixkZgJ4xbaEjABkv8hyGJ4,11784
|
|
67
68
|
basic_memory/services/exceptions.py,sha256=VGlCLd4UD2w5NWKqC7QpG4jOM_hA7jKRRM-MqvEVMNk,288
|
|
68
69
|
basic_memory/services/file_service.py,sha256=r4JfPY1wyenAH0Y-iq7vGHPwT616ayUWoLnvA1NuzpA,5695
|
|
69
70
|
basic_memory/services/link_resolver.py,sha256=GmUPTViW5JplQo4yJNaX18OGInqMitrxUeR4LQqUABA,4581
|
|
70
|
-
basic_memory/services/search_service.py,sha256=
|
|
71
|
+
basic_memory/services/search_service.py,sha256=0ZeK9CND4GQylRTG3LXxgTS-PVfn8dnDmxw75KR6dsk,7901
|
|
71
72
|
basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YNTag,336
|
|
72
73
|
basic_memory/sync/__init__.py,sha256=ko0xLQv1S5U7sAOmIP2XKl03akVPzoY-a9m3TFPcMh4,193
|
|
73
74
|
basic_memory/sync/file_change_scanner.py,sha256=4whJej6t9sxwUp1ox93efJ0bBHSnAr6STpk_PsKU6to,5784
|
|
74
|
-
basic_memory/sync/sync_service.py,sha256=
|
|
75
|
+
basic_memory/sync/sync_service.py,sha256=hx8aalnnFZB2T_fVRGN_6OlzTCmL0U0aUoPr8CPiB-o,7662
|
|
75
76
|
basic_memory/sync/utils.py,sha256=wz1Fe7Mb_M5N9vYRQnDKGODiMGcj5MEK16KVJ3eoQ9g,1191
|
|
76
77
|
basic_memory/sync/watch_service.py,sha256=CtKBrP1imI3ZSEgJl7Ffi-JZ_oDGKrhiyGgs41h5QYI,7563
|
|
77
|
-
basic_memory-0.
|
|
78
|
-
basic_memory-0.
|
|
79
|
-
basic_memory-0.
|
|
80
|
-
basic_memory-0.
|
|
81
|
-
basic_memory-0.
|
|
78
|
+
basic_memory-0.7.0.dist-info/METADATA,sha256=-G7gpth5p_edb7vSSMQdmDn5irZ7fJjOfdOV0qS-CDQ,10855
|
|
79
|
+
basic_memory-0.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
80
|
+
basic_memory-0.7.0.dist-info/entry_points.txt,sha256=IDQa_VmVTzmvMrpnjhEfM0S3F--XsVGEj3MpdJfuo-Q,59
|
|
81
|
+
basic_memory-0.7.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
82
|
+
basic_memory-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|