agmem 0.1.1__py3-none-any.whl → 0.1.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.
Files changed (80) hide show
  1. {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/METADATA +20 -3
  2. agmem-0.1.2.dist-info/RECORD +86 -0
  3. memvcs/__init__.py +1 -1
  4. memvcs/cli.py +35 -31
  5. memvcs/commands/__init__.py +9 -9
  6. memvcs/commands/add.py +77 -76
  7. memvcs/commands/blame.py +46 -53
  8. memvcs/commands/branch.py +13 -33
  9. memvcs/commands/checkout.py +27 -32
  10. memvcs/commands/clean.py +18 -23
  11. memvcs/commands/clone.py +4 -1
  12. memvcs/commands/commit.py +40 -39
  13. memvcs/commands/daemon.py +81 -76
  14. memvcs/commands/decay.py +77 -0
  15. memvcs/commands/diff.py +56 -57
  16. memvcs/commands/distill.py +74 -0
  17. memvcs/commands/fsck.py +55 -61
  18. memvcs/commands/garden.py +28 -37
  19. memvcs/commands/graph.py +41 -48
  20. memvcs/commands/init.py +16 -24
  21. memvcs/commands/log.py +25 -40
  22. memvcs/commands/merge.py +16 -28
  23. memvcs/commands/pack.py +129 -0
  24. memvcs/commands/pull.py +4 -1
  25. memvcs/commands/push.py +4 -2
  26. memvcs/commands/recall.py +145 -0
  27. memvcs/commands/reflog.py +13 -22
  28. memvcs/commands/remote.py +1 -0
  29. memvcs/commands/repair.py +66 -0
  30. memvcs/commands/reset.py +23 -33
  31. memvcs/commands/resurrect.py +82 -0
  32. memvcs/commands/search.py +3 -4
  33. memvcs/commands/serve.py +2 -1
  34. memvcs/commands/show.py +66 -36
  35. memvcs/commands/stash.py +34 -34
  36. memvcs/commands/status.py +27 -35
  37. memvcs/commands/tag.py +23 -47
  38. memvcs/commands/test.py +30 -44
  39. memvcs/commands/timeline.py +111 -0
  40. memvcs/commands/tree.py +26 -27
  41. memvcs/commands/verify.py +59 -0
  42. memvcs/commands/when.py +115 -0
  43. memvcs/core/access_index.py +167 -0
  44. memvcs/core/config_loader.py +3 -1
  45. memvcs/core/consistency.py +214 -0
  46. memvcs/core/decay.py +185 -0
  47. memvcs/core/diff.py +158 -143
  48. memvcs/core/distiller.py +277 -0
  49. memvcs/core/gardener.py +164 -132
  50. memvcs/core/hooks.py +48 -14
  51. memvcs/core/knowledge_graph.py +134 -138
  52. memvcs/core/merge.py +248 -171
  53. memvcs/core/objects.py +95 -96
  54. memvcs/core/pii_scanner.py +147 -146
  55. memvcs/core/refs.py +132 -115
  56. memvcs/core/repository.py +174 -164
  57. memvcs/core/schema.py +155 -113
  58. memvcs/core/staging.py +60 -65
  59. memvcs/core/storage/__init__.py +20 -18
  60. memvcs/core/storage/base.py +74 -70
  61. memvcs/core/storage/gcs.py +70 -68
  62. memvcs/core/storage/local.py +42 -40
  63. memvcs/core/storage/s3.py +105 -110
  64. memvcs/core/temporal_index.py +112 -0
  65. memvcs/core/test_runner.py +101 -93
  66. memvcs/core/vector_store.py +41 -35
  67. memvcs/integrations/mcp_server.py +1 -3
  68. memvcs/integrations/web_ui/server.py +25 -26
  69. memvcs/retrieval/__init__.py +22 -0
  70. memvcs/retrieval/base.py +54 -0
  71. memvcs/retrieval/pack.py +128 -0
  72. memvcs/retrieval/recaller.py +105 -0
  73. memvcs/retrieval/strategies.py +314 -0
  74. memvcs/utils/__init__.py +3 -3
  75. memvcs/utils/helpers.py +52 -52
  76. agmem-0.1.1.dist-info/RECORD +0 -67
  77. {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/WHEEL +0 -0
  78. {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/entry_points.txt +0 -0
  79. {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/licenses/LICENSE +0 -0
  80. {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,314 @@
1
+ """
2
+ Recall strategies: recency, importance, similarity, hybrid.
3
+ """
4
+
5
+ import fnmatch
6
+ from datetime import datetime
7
+ from pathlib import Path
8
+ from typing import List, Any, Optional
9
+
10
+ from .base import RetrievalStrategy, RecallResult
11
+ from ..core.constants import MEMORY_TYPES
12
+
13
+
14
+ def _matches_exclude(path: str, exclude: List[str]) -> bool:
15
+ """Return True if path matches any exclude pattern."""
16
+ if not exclude:
17
+ return False
18
+ for pattern in exclude:
19
+ if fnmatch.fnmatch(path, pattern):
20
+ return True
21
+ if fnmatch.fnmatch(path, f"*/{pattern}"):
22
+ return True
23
+ return False
24
+
25
+
26
+ class RecencyStrategy(RetrievalStrategy):
27
+ """Sort by commit timestamp / last_updated (newest first)."""
28
+
29
+ def __init__(self, repo: Any):
30
+ self.repo = repo
31
+
32
+ def recall(
33
+ self,
34
+ context: str,
35
+ limit: int,
36
+ exclude: List[str],
37
+ **kwargs: Any,
38
+ ) -> List[RecallResult]:
39
+ """Recall by recency - scan current/ and sort by mtime or frontmatter."""
40
+ results = []
41
+ current_dir = self.repo.current_dir
42
+ if not current_dir.exists():
43
+ return []
44
+
45
+ for subdir in MEMORY_TYPES:
46
+ dir_path = current_dir / subdir
47
+ if not dir_path.exists():
48
+ continue
49
+ for f in dir_path.rglob("*"):
50
+ if not f.is_file() or f.suffix.lower() not in (".md", ".txt"):
51
+ continue
52
+ try:
53
+ rel_path = str(f.relative_to(current_dir))
54
+ except ValueError:
55
+ continue
56
+ if _matches_exclude(rel_path, exclude):
57
+ continue
58
+ try:
59
+ content = f.read_text(encoding="utf-8", errors="replace")
60
+ except Exception:
61
+ continue
62
+
63
+ # Use mtime as recency proxy
64
+ mtime = f.stat().st_mtime
65
+ ts = datetime.fromtimestamp(mtime).isoformat() + "Z"
66
+
67
+ results.append(
68
+ RecallResult(
69
+ path=rel_path,
70
+ content=content[:2000] + ("..." if len(content) > 2000 else ""),
71
+ relevance_score=1.0 / (1.0 + mtime), # newer = higher
72
+ source={"indexed_at": ts, "commit_hash": None, "author": None},
73
+ importance=None,
74
+ )
75
+ )
76
+
77
+ # Sort by mtime descending (newest first)
78
+ results.sort(key=lambda r: r.source.get("indexed_at", ""), reverse=True)
79
+ return results[:limit]
80
+
81
+
82
+ class ImportanceStrategy(RetrievalStrategy):
83
+ """Sort by importance from commit metadata."""
84
+
85
+ def __init__(self, repo: Any):
86
+ self.repo = repo
87
+
88
+ def recall(
89
+ self,
90
+ context: str,
91
+ limit: int,
92
+ exclude: List[str],
93
+ **kwargs: Any,
94
+ ) -> List[RecallResult]:
95
+ """Recall by importance - use commit metadata and frontmatter."""
96
+ from ..core.objects import Commit, Blob, Tree
97
+ from ..core.schema import FrontmatterParser
98
+
99
+ results = []
100
+ head = self.repo.get_head_commit()
101
+ if not head:
102
+ return []
103
+
104
+ tree = self.repo.get_commit_tree(head.store(self.repo.object_store))
105
+ if not tree:
106
+ return []
107
+
108
+ commit_importance = head.metadata.get("importance", 0.5)
109
+
110
+ def collect_files(entries: list, prefix: str = "") -> None:
111
+ for entry in entries:
112
+ # Support both hierarchical trees and flat trees (entry.path = parent dir)
113
+ path = (
114
+ f"{prefix}/{entry.path}/{entry.name}".replace("//", "/").lstrip("/")
115
+ if prefix or entry.path
116
+ else entry.name
117
+ )
118
+ if entry.obj_type == "tree":
119
+ subtree = Tree.load(self.repo.object_store, entry.hash)
120
+ if subtree:
121
+ collect_files(subtree.entries, path)
122
+ else:
123
+ if _matches_exclude(path, exclude):
124
+ continue
125
+ blob = Blob.load(self.repo.object_store, entry.hash)
126
+ if not blob:
127
+ continue
128
+ try:
129
+ content = blob.content.decode("utf-8", errors="replace")
130
+ except Exception:
131
+ continue
132
+ fm, body = FrontmatterParser.parse(content)
133
+ importance = None
134
+ if fm and fm.importance is not None:
135
+ importance = fm.importance
136
+ elif fm and fm.confidence_score is not None:
137
+ importance = fm.confidence_score
138
+ else:
139
+ importance = commit_importance
140
+
141
+ results.append(
142
+ RecallResult(
143
+ path=path,
144
+ content=content[:2000] + ("..." if len(content) > 2000 else ""),
145
+ relevance_score=float(importance) if importance else 0.5,
146
+ source={
147
+ "commit_hash": head.store(self.repo.object_store),
148
+ "author": head.author,
149
+ "indexed_at": head.timestamp,
150
+ },
151
+ importance=float(importance) if importance else None,
152
+ )
153
+ )
154
+
155
+ collect_files(tree.entries)
156
+ results.sort(key=lambda r: r.relevance_score, reverse=True)
157
+ return results[:limit]
158
+
159
+
160
+ class SimilarityStrategy(RetrievalStrategy):
161
+ """Use vector store for embedding similarity."""
162
+
163
+ def __init__(self, repo: Any, vector_store: Any):
164
+ self.repo = repo
165
+ self.vector_store = vector_store
166
+
167
+ def recall(
168
+ self,
169
+ context: str,
170
+ limit: int,
171
+ exclude: List[str],
172
+ **kwargs: Any,
173
+ ) -> List[RecallResult]:
174
+ """Recall by semantic similarity to context."""
175
+ raw = self.vector_store.search_with_provenance(context, limit=limit * 2)
176
+ results = []
177
+ for item in raw:
178
+ path = item.get("path", "")
179
+ if _matches_exclude(path, exclude):
180
+ continue
181
+ results.append(
182
+ RecallResult(
183
+ path=path,
184
+ content=item.get("content", ""),
185
+ relevance_score=item.get("similarity", 1.0 - item.get("distance", 0)),
186
+ source={
187
+ "commit_hash": item.get("commit_hash"),
188
+ "author": item.get("author"),
189
+ "indexed_at": item.get("indexed_at"),
190
+ "blob_hash": item.get("blob_hash"),
191
+ },
192
+ importance=None,
193
+ )
194
+ )
195
+ if len(results) >= limit:
196
+ break
197
+ return results
198
+
199
+
200
+ class HybridStrategy(RetrievalStrategy):
201
+ """Weighted combo of similarity, recency, importance."""
202
+
203
+ def __init__(
204
+ self,
205
+ repo: Any,
206
+ vector_store: Optional[Any] = None,
207
+ weights: Optional[dict] = None,
208
+ ):
209
+ self.repo = repo
210
+ self.vector_store = vector_store
211
+ self.weights = weights or {
212
+ "similarity": 0.4,
213
+ "recency": 0.3,
214
+ "importance": 0.3,
215
+ }
216
+
217
+ def recall(
218
+ self,
219
+ context: str,
220
+ limit: int,
221
+ exclude: List[str],
222
+ **kwargs: Any,
223
+ ) -> List[RecallResult]:
224
+ """Combine strategies with configurable weights."""
225
+ from ..core.schema import FrontmatterParser
226
+
227
+ # Collect candidates from all sources
228
+ path_to_result: dict = {}
229
+
230
+ # Similarity (if vector store available)
231
+ if self.vector_store:
232
+ sim = SimilarityStrategy(self.repo, self.vector_store)
233
+ for r in sim.recall(context, limit * 2, exclude):
234
+ path_to_result[r.path] = {
235
+ "result": r,
236
+ "sim_score": r.relevance_score,
237
+ "rec_score": 0.5,
238
+ "imp_score": r.importance or 0.5,
239
+ }
240
+
241
+ # Recency and importance from current/
242
+ current_dir = self.repo.current_dir
243
+ if current_dir.exists():
244
+ import time
245
+
246
+ head = self.repo.get_head_commit()
247
+ commit_imp = head.metadata.get("importance", 0.5) if head else 0.5
248
+
249
+ for subdir in MEMORY_TYPES:
250
+ dir_path = current_dir / subdir
251
+ if not dir_path.exists():
252
+ continue
253
+ for f in dir_path.rglob("*"):
254
+ if not f.is_file() or f.suffix.lower() not in (".md", ".txt"):
255
+ continue
256
+ try:
257
+ rel_path = str(f.relative_to(current_dir))
258
+ except ValueError:
259
+ continue
260
+ if _matches_exclude(rel_path, exclude):
261
+ continue
262
+ try:
263
+ content = f.read_text(encoding="utf-8", errors="replace")
264
+ except Exception:
265
+ continue
266
+
267
+ mtime = f.stat().st_mtime
268
+ rec_score = 1.0 - (time.time() - mtime) / (86400 * 30) # normalize to ~30 days
269
+ rec_score = max(0, min(1, rec_score))
270
+
271
+ fm, _ = FrontmatterParser.parse(content)
272
+ imp_score = 0.5
273
+ if fm and fm.importance is not None:
274
+ imp_score = fm.importance
275
+ elif fm and fm.confidence_score is not None:
276
+ imp_score = fm.confidence_score
277
+ else:
278
+ imp_score = commit_imp
279
+
280
+ if rel_path in path_to_result:
281
+ path_to_result[rel_path]["rec_score"] = rec_score
282
+ path_to_result[rel_path]["imp_score"] = imp_score
283
+ else:
284
+ path_to_result[rel_path] = {
285
+ "result": RecallResult(
286
+ path=rel_path,
287
+ content=content[:2000] + ("..." if len(content) > 2000 else ""),
288
+ relevance_score=0,
289
+ source={
290
+ "indexed_at": datetime.fromtimestamp(mtime).isoformat() + "Z"
291
+ },
292
+ importance=imp_score,
293
+ ),
294
+ "sim_score": 0.5,
295
+ "rec_score": rec_score,
296
+ "imp_score": imp_score,
297
+ }
298
+
299
+ # Compute hybrid score
300
+ w = self.weights
301
+ scored = []
302
+ for path, data in path_to_result.items():
303
+ score = (
304
+ w.get("similarity", 0.33) * data["sim_score"]
305
+ + w.get("recency", 0.33) * data["rec_score"]
306
+ + w.get("importance", 0.33) * data["imp_score"]
307
+ )
308
+ r = data["result"]
309
+ r.relevance_score = score
310
+ r.importance = data.get("imp_score")
311
+ scored.append(r)
312
+
313
+ scored.sort(key=lambda x: x.relevance_score, reverse=True)
314
+ return scored[:limit]
memvcs/utils/__init__.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from .helpers import find_repo_root, format_timestamp, shorten_hash
4
4
 
5
5
  __all__ = [
6
- 'find_repo_root',
7
- 'format_timestamp',
8
- 'shorten_hash',
6
+ "find_repo_root",
7
+ "format_timestamp",
8
+ "shorten_hash",
9
9
  ]
memvcs/utils/helpers.py CHANGED
@@ -9,42 +9,42 @@ from typing import Optional
9
9
  def find_repo_root(start_path: Optional[Path] = None) -> Optional[Path]:
10
10
  """
11
11
  Find the repository root by looking for .mem directory.
12
-
12
+
13
13
  Args:
14
14
  start_path: Path to start searching from (default: current directory)
15
-
15
+
16
16
  Returns:
17
17
  Path to repository root or None if not found
18
18
  """
19
19
  if start_path is None:
20
- start_path = Path('.').resolve()
21
-
20
+ start_path = Path(".").resolve()
21
+
22
22
  current = start_path
23
-
23
+
24
24
  while current != current.parent:
25
- if (current / '.mem').exists():
25
+ if (current / ".mem").exists():
26
26
  return current
27
27
  current = current.parent
28
-
28
+
29
29
  return None
30
30
 
31
31
 
32
- def format_timestamp(timestamp_str: str, format_str: str = '%Y-%m-%d %H:%M:%S') -> str:
32
+ def format_timestamp(timestamp_str: str, format_str: str = "%Y-%m-%d %H:%M:%S") -> str:
33
33
  """
34
34
  Format an ISO timestamp string.
35
-
35
+
36
36
  Args:
37
37
  timestamp_str: ISO format timestamp
38
38
  format_str: Output format string
39
-
39
+
40
40
  Returns:
41
41
  Formatted timestamp string
42
42
  """
43
43
  try:
44
44
  # Handle 'Z' suffix
45
- if timestamp_str.endswith('Z'):
45
+ if timestamp_str.endswith("Z"):
46
46
  timestamp_str = timestamp_str[:-1]
47
-
47
+
48
48
  dt = datetime.fromisoformat(timestamp_str)
49
49
  return dt.strftime(format_str)
50
50
  except (ValueError, TypeError):
@@ -54,11 +54,11 @@ def format_timestamp(timestamp_str: str, format_str: str = '%Y-%m-%d %H:%M:%S')
54
54
  def shorten_hash(hash_id: str, length: int = 8) -> str:
55
55
  """
56
56
  Shorten a hash for display.
57
-
57
+
58
58
  Args:
59
59
  hash_id: Full hash string
60
60
  length: Length of shortened hash
61
-
61
+
62
62
  Returns:
63
63
  Shortened hash
64
64
  """
@@ -70,18 +70,18 @@ def shorten_hash(hash_id: str, length: int = 8) -> str:
70
70
  def human_readable_size(size_bytes: int) -> str:
71
71
  """
72
72
  Convert bytes to human readable format.
73
-
73
+
74
74
  Args:
75
75
  size_bytes: Size in bytes
76
-
76
+
77
77
  Returns:
78
78
  Human readable string (e.g., "1.5 MB")
79
79
  """
80
80
  if size_bytes < 1024:
81
81
  return f"{size_bytes} B"
82
- elif size_bytes < 1024 ** 2:
82
+ elif size_bytes < 1024**2:
83
83
  return f"{size_bytes / 1024:.1f} KB"
84
- elif size_bytes < 1024 ** 3:
84
+ elif size_bytes < 1024**3:
85
85
  return f"{size_bytes / (1024 ** 2):.1f} MB"
86
86
  else:
87
87
  return f"{size_bytes / (1024 ** 3):.1f} GB"
@@ -90,89 +90,89 @@ def human_readable_size(size_bytes: int) -> str:
90
90
  def parse_memory_type(filepath: str) -> str:
91
91
  """
92
92
  Parse memory type from file path.
93
-
93
+
94
94
  Args:
95
95
  filepath: Path to memory file
96
-
96
+
97
97
  Returns:
98
98
  Memory type ('episodic', 'semantic', 'procedural', 'unknown')
99
99
  """
100
100
  path_lower = filepath.lower()
101
-
102
- if 'episodic' in path_lower:
103
- return 'episodic'
104
- elif 'semantic' in path_lower:
105
- return 'semantic'
106
- elif 'procedural' in path_lower or 'workflow' in path_lower:
107
- return 'procedural'
108
- elif 'checkpoint' in path_lower:
109
- return 'checkpoint'
110
- elif 'summary' in path_lower:
111
- return 'summary'
112
-
113
- return 'unknown'
101
+
102
+ if "episodic" in path_lower:
103
+ return "episodic"
104
+ elif "semantic" in path_lower:
105
+ return "semantic"
106
+ elif "procedural" in path_lower or "workflow" in path_lower:
107
+ return "procedural"
108
+ elif "checkpoint" in path_lower:
109
+ return "checkpoint"
110
+ elif "summary" in path_lower:
111
+ return "summary"
112
+
113
+ return "unknown"
114
114
 
115
115
 
116
116
  def is_binary_content(content: bytes) -> bool:
117
117
  """
118
118
  Check if content appears to be binary.
119
-
119
+
120
120
  Args:
121
121
  content: Content bytes to check
122
-
122
+
123
123
  Returns:
124
124
  True if content appears binary
125
125
  """
126
126
  # Check for null bytes
127
- if b'\x00' in content:
127
+ if b"\x00" in content:
128
128
  return True
129
-
129
+
130
130
  # Check for high ratio of non-printable characters
131
131
  if len(content) == 0:
132
132
  return False
133
-
134
- text_chars = bytearray({7, 8, 9, 10, 12, 13, 27} | set(range(0x20, 0x100)) - {0x7f})
133
+
134
+ text_chars = bytearray({7, 8, 9, 10, 12, 13, 27} | set(range(0x20, 0x100)) - {0x7F})
135
135
  non_text = sum(1 for byte in content if byte not in text_chars)
136
-
136
+
137
137
  return non_text / len(content) > 0.30
138
138
 
139
139
 
140
140
  def sanitize_filename(filename: str) -> str:
141
141
  """
142
142
  Sanitize a filename for safe use.
143
-
143
+
144
144
  Args:
145
145
  filename: Original filename
146
-
146
+
147
147
  Returns:
148
148
  Sanitized filename
149
149
  """
150
150
  # Remove or replace unsafe characters
151
151
  unsafe_chars = '<>:"/\\|?*'
152
152
  for char in unsafe_chars:
153
- filename = filename.replace(char, '_')
154
-
153
+ filename = filename.replace(char, "_")
154
+
155
155
  # Remove leading/trailing whitespace and dots
156
- filename = filename.strip(' .')
157
-
156
+ filename = filename.strip(" .")
157
+
158
158
  # Ensure not empty
159
159
  if not filename:
160
- filename = 'unnamed'
161
-
160
+ filename = "unnamed"
161
+
162
162
  return filename
163
163
 
164
164
 
165
165
  def generate_session_id() -> str:
166
166
  """
167
167
  Generate a unique session ID.
168
-
168
+
169
169
  Returns:
170
170
  Session ID string
171
171
  """
172
172
  from datetime import datetime
173
173
  import uuid
174
-
175
- timestamp = datetime.utcnow().strftime('%Y%m%d-%H%M%S')
174
+
175
+ timestamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
176
176
  short_uuid = str(uuid.uuid4())[:8]
177
-
177
+
178
178
  return f"session-{timestamp}-{short_uuid}"
@@ -1,67 +0,0 @@
1
- agmem-0.1.1.dist-info/licenses/LICENSE,sha256=X_S6RBErW-F0IDbM3FAEoDB-zxExFnl2m8640rTXphM,1067
2
- memvcs/__init__.py,sha256=Gs0A8GAivdcePvlse8yWE3t6-vutFO9tWl5dh8lun6I,193
3
- memvcs/cli.py,sha256=ImQKXb423bHZ2iPr3GndHVojx2KcTuX8rXHwJV1cku0,5364
4
- memvcs/commands/__init__.py,sha256=lPKiWp-ywEGk1JPK0DeiHSublDwwSD1pU_LyPT-2BhY,510
5
- memvcs/commands/add.py,sha256=n0J0N_5Mk4uNMtsEt2podLqSKeenaOBRNWMUb9gsq70,8874
6
- memvcs/commands/base.py,sha256=yWvIYuofRxbHXvChlSd_DL_hJMaQdbZwa2XBDWj5Bio,634
7
- memvcs/commands/blame.py,sha256=NbaaL3kt9K2zRvYWX6mh-NmXNt5ZOdacSzHDmGY0_Oo,5874
8
- memvcs/commands/branch.py,sha256=7ocWZVn-WJ1c9pR9Z493ytd_VE6CY6Lakgl5lIzoNeE,3418
9
- memvcs/commands/checkout.py,sha256=8-fVF9HC5b0dkyO1u0wkGLUwGXrRBc8eSIDD9XBcnjI,3310
10
- memvcs/commands/clean.py,sha256=SXQqnd31KwmuIFUc2tBVm8ZjZ_3bP2mhbOR9cPBdbIs,2090
11
- memvcs/commands/clone.py,sha256=YYYURUiW850CHDgctlM4_ysQlPeh35BrS-UG2LSwWZ0,2872
12
- memvcs/commands/commit.py,sha256=SmeU0MDIMSYQe9PHNZzOLEK1duvflqWdRMrQXkQ6zGM,6380
13
- memvcs/commands/daemon.py,sha256=nTaWx19MN1IR4u293yna8fuwhHRiYstykSq_3zoUFPc,8385
14
- memvcs/commands/diff.py,sha256=TxfeqQS84rG2wHRff_WxdwjsNBKRnMkkX4B-7rsVG9Q,5410
15
- memvcs/commands/fsck.py,sha256=kvJYO0Kr073qZwGtvVqL1c7n7E34QuNzSc-HG3GpWZQ,6890
16
- memvcs/commands/garden.py,sha256=P8rvC6xYu6q_8VfXEUvtOa2Wez3jHLGGArGeAbn_o4Y,3496
17
- memvcs/commands/graph.py,sha256=caPyoo-myqmvtg_HEBUGBgQEnNFQXnCIkiNte4zQhqs,4993
18
- memvcs/commands/init.py,sha256=2TfBniqqJ6PsyHSIgBmkdtpF-kU9UCsc-V4Ct4BSumM,1767
19
- memvcs/commands/log.py,sha256=tY0Hrn2xkC1SWG_DT2VGbdK-W-oajrM_1r9NVLoEq5k,3141
20
- memvcs/commands/mcp.py,sha256=PMfwVD6uHltN58Jh7IOiS1w7oND42tg14QKRCJNudmY,1740
21
- memvcs/commands/merge.py,sha256=qUsJelBynpdv63tL9Oga3t29AnUQCMMJo_CNl3rNvaw,2631
22
- memvcs/commands/pull.py,sha256=Sk0zfCloyksYbMGCSM9z91pH1gZJ-KLKZasckQhrNd4,2082
23
- memvcs/commands/push.py,sha256=bCHuxrrBwRNhVDh9GVwhRICtaNLk_a_47EHix4Z66BQ,5081
24
- memvcs/commands/reflog.py,sha256=AtfJ2dzhsgJVvdQlHU5LUEiAW310QI8yWeUD7GmLoco,1256
25
- memvcs/commands/remote.py,sha256=sTXf-r6w4OsZgB68ffW9jUtP1xOL8p-kttxvApZNs08,1760
26
- memvcs/commands/reset.py,sha256=vvHgSb79zVJizWyH-XN6u5jHK2e_gqrNI0JoIUi22es,2991
27
- memvcs/commands/search.py,sha256=rg-cQfUDl6aNRFa64szpPbqzw508sL9a2u8YtHBhSRM,5324
28
- memvcs/commands/serve.py,sha256=mhfsULAtU5Gxe43RVo94RRYT1ui4Zmg5Ptatj5rNIUc,1396
29
- memvcs/commands/show.py,sha256=525-T_na_B3gX6lmFJ05Q4675XNyEd7FFrVl63X2X7Q,3932
30
- memvcs/commands/stash.py,sha256=aLeeOLUXcFHQYzsYsi9KIg5e_8VFANHMAEvzaqTOgsg,3293
31
- memvcs/commands/status.py,sha256=P02DFM2-gIf8-dkslzpnj6xNmpxhqmf8bOhHkxA3srw,3647
32
- memvcs/commands/tag.py,sha256=UCTggFnzHXVMBYjX8usz58duqg4xyOHnIUdVNyoAlWQ,3409
33
- memvcs/commands/test.py,sha256=xAIzN60U1xL1TieIXOQBsvTRRfZfElVqxEqqHUn72VU,4235
34
- memvcs/commands/tree.py,sha256=GzA7RYH3bYgSg9QmztYpis6EZWEt6fzwBltoQjaukf4,5059
35
- memvcs/core/__init__.py,sha256=dkIC-4tS0GhwV2mZIbofEe8xR8uiFwrxslGf1aXwhYg,493
36
- memvcs/core/config_loader.py,sha256=ebljEMDyVJjQdlpP8if10Whg0I3DfMUBiuAl7S5NVNE,8264
37
- memvcs/core/constants.py,sha256=WUjAb50BFcF0mbFi_GNteDLCxLihmViBm9Fb-JMPmbM,220
38
- memvcs/core/diff.py,sha256=wZynRRAF08HyQ_SCcseC0vlmnkoaqoQfQWne3w1o__M,13390
39
- memvcs/core/gardener.py,sha256=Fr_Zpo_3eZAtA_9zXVT_PpAHfhZkp2-ukLn69FV93rA,16335
40
- memvcs/core/hooks.py,sha256=3PWqebAt2c6nPw7ZX3epcb5FGLJLrwxh_UMrQeFTyr0,4679
41
- memvcs/core/knowledge_graph.py,sha256=Ntm4My73Ov3u9YKEgwvDonUVwewx-svCDJD4hGA0hPc,13572
42
- memvcs/core/merge.py,sha256=i_X-0ye14r62dvlxRWZVkRbIvxd_MtfQSYwuZQEYaCA,17041
43
- memvcs/core/objects.py,sha256=MvWhQ-L74Rl2lf0rnJE-N3qo78dWGoclJSQinTloNPg,10289
44
- memvcs/core/pii_scanner.py,sha256=MOycqGTuLJaCNGkaMyMH1ju8gPxQTyLAONoIML7gHKU,11141
45
- memvcs/core/refs.py,sha256=1-ELwSXWmqdivD_967zb3hw5V3gIiujyn4eRGf8e1u8,16831
46
- memvcs/core/remote.py,sha256=MhQTfxpzmH0mAMb7hoQJrTOAoqX0tqZxx1Yq5Q5niS8,10117
47
- memvcs/core/repository.py,sha256=fZ-UUh9EK9nmM8dk9y4TeipkhgGEp5JqDizR6QAEVe4,18119
48
- memvcs/core/schema.py,sha256=oiStwqD1crbQJf86yJTMI50efd2SaDG3RIPyUxmcxEk,14322
49
- memvcs/core/staging.py,sha256=EvACqotgi-LKgOdZr6-8Ud1Lkjnflam0KAzpq8eAAp0,7499
50
- memvcs/core/test_runner.py,sha256=QfEPMjBebM4L4COn9p0XqMcq1Grvij5rOXByUWAcEAg,11823
51
- memvcs/core/vector_store.py,sha256=Z_C1VZy3Ytv9dfEaqgE6zCb8nNabLaIsDcc1ATstDRI,10546
52
- memvcs/core/storage/__init__.py,sha256=b2MLjyFgE6L6JAFoyEldxsrR16FGO65qAtxgRj5XFcM,1959
53
- memvcs/core/storage/base.py,sha256=hHPXuJPR5X1bh7xYAqACHYRfzU4CmPx9trT5tgRghdI,10384
54
- memvcs/core/storage/gcs.py,sha256=mjcuQHiK6goQ3opRDE6Ky2fSEA9W-MNTOShlGXhY0cM,10953
55
- memvcs/core/storage/local.py,sha256=CHi3Ot0-u-pCJJOWKW3IP_UIkdz32QAkHcJl1DxatHY,6193
56
- memvcs/core/storage/s3.py,sha256=rPxZ7avw5KXMSrJrsA2YpM6gVv7Qhn9IQjfoApZIyxE,14230
57
- memvcs/integrations/__init__.py,sha256=hVtJoFaXt6ErAZwctcSBDZLXRHFs1CNgtltIBQiroQ0,103
58
- memvcs/integrations/mcp_server.py,sha256=-si5ymayhiRTIfNJwc4EEp4kudav28x8RjzIEDN-n2c,9091
59
- memvcs/integrations/web_ui/__init__.py,sha256=MQIfgDKDgPctlcTUjwkwueS_MDsDssVRmIUnpECGS0k,51
60
- memvcs/integrations/web_ui/server.py,sha256=yqokrs6T9l4vAWdRHKMSFLUIkodTJFWihw5Aq_dhGPg,12782
61
- memvcs/utils/__init__.py,sha256=h74jw3O37su7BFxp52IcZmVReLfd8yDcuk4VzBHbd_s,185
62
- memvcs/utils/helpers.py,sha256=4k7Jdm-8vCWDASW2kST2vZs-vA9HX8UvqoCwIGsq49g,4273
63
- agmem-0.1.1.dist-info/METADATA,sha256=8ovwtZcCCNfSeQA6IH5HfAY0MzQgeqxBo1BfRZIkLIU,25844
64
- agmem-0.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
65
- agmem-0.1.1.dist-info/entry_points.txt,sha256=at7eWycgjqOo1wbUMECnXUsNo3gpCkJTU71OzrGLHu0,42
66
- agmem-0.1.1.dist-info/top_level.txt,sha256=HtMMsKuwLKLOdgF1GxqQztqFM54tTJctVdJuOec6B-4,7
67
- agmem-0.1.1.dist-info/RECORD,,
File without changes