agmem 0.1.1__py3-none-any.whl → 0.1.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.
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/METADATA +157 -16
- agmem-0.1.3.dist-info/RECORD +105 -0
- memvcs/__init__.py +1 -1
- memvcs/cli.py +45 -31
- memvcs/commands/__init__.py +9 -9
- memvcs/commands/add.py +83 -76
- memvcs/commands/audit.py +59 -0
- memvcs/commands/blame.py +46 -53
- memvcs/commands/branch.py +13 -33
- memvcs/commands/checkout.py +27 -32
- memvcs/commands/clean.py +18 -23
- memvcs/commands/clone.py +11 -1
- memvcs/commands/commit.py +40 -39
- memvcs/commands/daemon.py +109 -76
- memvcs/commands/decay.py +77 -0
- memvcs/commands/diff.py +56 -57
- memvcs/commands/distill.py +90 -0
- memvcs/commands/federated.py +53 -0
- memvcs/commands/fsck.py +86 -61
- memvcs/commands/garden.py +40 -35
- memvcs/commands/gc.py +51 -0
- memvcs/commands/graph.py +41 -48
- memvcs/commands/init.py +16 -24
- memvcs/commands/log.py +25 -40
- memvcs/commands/merge.py +69 -27
- memvcs/commands/pack.py +129 -0
- memvcs/commands/prove.py +66 -0
- memvcs/commands/pull.py +31 -1
- memvcs/commands/push.py +4 -2
- memvcs/commands/recall.py +145 -0
- memvcs/commands/reflog.py +13 -22
- memvcs/commands/remote.py +1 -0
- memvcs/commands/repair.py +66 -0
- memvcs/commands/reset.py +23 -33
- memvcs/commands/resolve.py +130 -0
- memvcs/commands/resurrect.py +82 -0
- memvcs/commands/search.py +3 -4
- memvcs/commands/serve.py +2 -1
- memvcs/commands/show.py +66 -36
- memvcs/commands/stash.py +34 -34
- memvcs/commands/status.py +27 -35
- memvcs/commands/tag.py +23 -47
- memvcs/commands/test.py +30 -44
- memvcs/commands/timeline.py +111 -0
- memvcs/commands/tree.py +26 -27
- memvcs/commands/verify.py +110 -0
- memvcs/commands/when.py +115 -0
- memvcs/core/access_index.py +167 -0
- memvcs/core/audit.py +124 -0
- memvcs/core/config_loader.py +3 -1
- memvcs/core/consistency.py +214 -0
- memvcs/core/crypto_verify.py +280 -0
- memvcs/core/decay.py +185 -0
- memvcs/core/diff.py +158 -143
- memvcs/core/distiller.py +277 -0
- memvcs/core/encryption.py +169 -0
- memvcs/core/federated.py +86 -0
- memvcs/core/gardener.py +176 -145
- memvcs/core/hooks.py +48 -14
- memvcs/core/ipfs_remote.py +39 -0
- memvcs/core/knowledge_graph.py +135 -138
- memvcs/core/llm/__init__.py +10 -0
- memvcs/core/llm/anthropic_provider.py +50 -0
- memvcs/core/llm/base.py +27 -0
- memvcs/core/llm/factory.py +30 -0
- memvcs/core/llm/openai_provider.py +36 -0
- memvcs/core/merge.py +260 -170
- memvcs/core/objects.py +110 -101
- memvcs/core/pack.py +92 -0
- memvcs/core/pii_scanner.py +147 -146
- memvcs/core/privacy_budget.py +63 -0
- memvcs/core/refs.py +132 -115
- memvcs/core/remote.py +38 -0
- memvcs/core/repository.py +254 -164
- memvcs/core/schema.py +155 -113
- memvcs/core/staging.py +60 -65
- memvcs/core/storage/__init__.py +20 -18
- memvcs/core/storage/base.py +74 -70
- memvcs/core/storage/gcs.py +70 -68
- memvcs/core/storage/local.py +42 -40
- memvcs/core/storage/s3.py +105 -110
- memvcs/core/temporal_index.py +121 -0
- memvcs/core/test_runner.py +101 -93
- memvcs/core/trust.py +103 -0
- memvcs/core/vector_store.py +56 -36
- memvcs/core/zk_proofs.py +26 -0
- memvcs/integrations/mcp_server.py +1 -3
- memvcs/integrations/web_ui/server.py +25 -26
- memvcs/retrieval/__init__.py +22 -0
- memvcs/retrieval/base.py +54 -0
- memvcs/retrieval/pack.py +128 -0
- memvcs/retrieval/recaller.py +105 -0
- memvcs/retrieval/strategies.py +314 -0
- memvcs/utils/__init__.py +3 -3
- memvcs/utils/helpers.py +52 -52
- agmem-0.1.1.dist-info/RECORD +0 -67
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/WHEEL +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/entry_points.txt +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.3.dist-info}/top_level.txt +0 -0
memvcs/commands/checkout.py
CHANGED
|
@@ -10,27 +10,18 @@ from ..core.repository import Repository
|
|
|
10
10
|
|
|
11
11
|
class CheckoutCommand:
|
|
12
12
|
"""Switch branches or restore working tree files."""
|
|
13
|
-
|
|
14
|
-
name =
|
|
15
|
-
help =
|
|
16
|
-
|
|
13
|
+
|
|
14
|
+
name = "checkout"
|
|
15
|
+
help = "Switch branches or restore working tree files"
|
|
16
|
+
|
|
17
17
|
@staticmethod
|
|
18
18
|
def add_arguments(parser: argparse.ArgumentParser):
|
|
19
|
+
parser.add_argument("ref", help="Branch, tag, or commit to checkout")
|
|
20
|
+
parser.add_argument("-b", action="store_true", help="Create and checkout a new branch")
|
|
19
21
|
parser.add_argument(
|
|
20
|
-
|
|
21
|
-
help='Branch, tag, or commit to checkout'
|
|
22
|
+
"--force", "-f", action="store_true", help="Force checkout (discard local changes)"
|
|
22
23
|
)
|
|
23
|
-
|
|
24
|
-
'-b',
|
|
25
|
-
action='store_true',
|
|
26
|
-
help='Create and checkout a new branch'
|
|
27
|
-
)
|
|
28
|
-
parser.add_argument(
|
|
29
|
-
'--force', '-f',
|
|
30
|
-
action='store_true',
|
|
31
|
-
help='Force checkout (discard local changes)'
|
|
32
|
-
)
|
|
33
|
-
|
|
24
|
+
|
|
34
25
|
@staticmethod
|
|
35
26
|
def execute(args) -> int:
|
|
36
27
|
repo, code = require_repo()
|
|
@@ -40,24 +31,24 @@ class CheckoutCommand:
|
|
|
40
31
|
# Create and checkout new branch
|
|
41
32
|
if args.b:
|
|
42
33
|
branch_name = args.ref
|
|
43
|
-
|
|
34
|
+
|
|
44
35
|
# Check if branch already exists
|
|
45
36
|
if repo.refs.branch_exists(branch_name):
|
|
46
37
|
print(f"Error: A branch named '{branch_name}' already exists.")
|
|
47
38
|
return 1
|
|
48
|
-
|
|
39
|
+
|
|
49
40
|
# Get current HEAD commit
|
|
50
41
|
head = repo.refs.get_head()
|
|
51
|
-
if head[
|
|
52
|
-
current_commit = repo.refs.get_branch_commit(head[
|
|
42
|
+
if head["type"] == "branch":
|
|
43
|
+
current_commit = repo.refs.get_branch_commit(head["value"])
|
|
53
44
|
else:
|
|
54
|
-
current_commit = head[
|
|
55
|
-
|
|
45
|
+
current_commit = head["value"]
|
|
46
|
+
|
|
56
47
|
# Create branch
|
|
57
48
|
if not repo.refs.create_branch(branch_name, current_commit):
|
|
58
49
|
print(f"Error: Could not create branch '{branch_name}'")
|
|
59
50
|
return 1
|
|
60
|
-
|
|
51
|
+
|
|
61
52
|
# Switch to new branch
|
|
62
53
|
try:
|
|
63
54
|
repo.refs.set_head_branch(branch_name)
|
|
@@ -66,16 +57,16 @@ class CheckoutCommand:
|
|
|
66
57
|
except Exception as e:
|
|
67
58
|
print(f"Error switching to branch: {e}")
|
|
68
59
|
return 1
|
|
69
|
-
|
|
60
|
+
|
|
70
61
|
# Regular checkout
|
|
71
62
|
ref = args.ref
|
|
72
|
-
|
|
63
|
+
|
|
73
64
|
# Check if it's a branch
|
|
74
65
|
is_branch = repo.refs.branch_exists(ref)
|
|
75
|
-
|
|
66
|
+
|
|
76
67
|
try:
|
|
77
68
|
commit_hash = repo.checkout(ref, force=args.force)
|
|
78
|
-
|
|
69
|
+
|
|
79
70
|
if is_branch:
|
|
80
71
|
print(f"Switched to branch '{ref}'")
|
|
81
72
|
else:
|
|
@@ -83,16 +74,20 @@ class CheckoutCommand:
|
|
|
83
74
|
if repo.refs.tag_exists(ref):
|
|
84
75
|
print(f"Note: checking out '{ref}'.")
|
|
85
76
|
print()
|
|
86
|
-
print(
|
|
87
|
-
|
|
77
|
+
print(
|
|
78
|
+
"You are in 'detached HEAD' state. You can look around, make experimental"
|
|
79
|
+
)
|
|
80
|
+
print(
|
|
81
|
+
"changes and commit them, and you can discard any commits you make in this"
|
|
82
|
+
)
|
|
88
83
|
print("state without impacting any branches by switching back to a branch.")
|
|
89
84
|
else:
|
|
90
85
|
print(f"Note: checking out '{commit_hash[:8]}'.")
|
|
91
86
|
print()
|
|
92
87
|
print("You are in 'detached HEAD' state.")
|
|
93
|
-
|
|
88
|
+
|
|
94
89
|
return 0
|
|
95
|
-
|
|
90
|
+
|
|
96
91
|
except ValueError as e:
|
|
97
92
|
print(f"Error: {e}")
|
|
98
93
|
return 1
|
memvcs/commands/clean.py
CHANGED
|
@@ -12,52 +12,46 @@ from ..core.repository import Repository
|
|
|
12
12
|
|
|
13
13
|
class CleanCommand:
|
|
14
14
|
"""Remove untracked files from working directory."""
|
|
15
|
-
|
|
16
|
-
name =
|
|
17
|
-
help =
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
name = "clean"
|
|
17
|
+
help = "Remove untracked files from working directory"
|
|
18
|
+
|
|
19
19
|
@staticmethod
|
|
20
20
|
def add_arguments(parser: argparse.ArgumentParser):
|
|
21
21
|
parser.add_argument(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
parser.add_argument(
|
|
27
|
-
'-f', '--force',
|
|
28
|
-
action='store_true',
|
|
29
|
-
help='Required to actually remove files'
|
|
22
|
+
"-n",
|
|
23
|
+
"--dry-run",
|
|
24
|
+
action="store_true",
|
|
25
|
+
help="Show what would be removed without removing",
|
|
30
26
|
)
|
|
31
27
|
parser.add_argument(
|
|
32
|
-
|
|
33
|
-
action='store_true',
|
|
34
|
-
help='Remove untracked directories too'
|
|
28
|
+
"-f", "--force", action="store_true", help="Required to actually remove files"
|
|
35
29
|
)
|
|
36
|
-
|
|
30
|
+
parser.add_argument("-d", action="store_true", help="Remove untracked directories too")
|
|
31
|
+
|
|
37
32
|
@staticmethod
|
|
38
33
|
def execute(args) -> int:
|
|
39
34
|
repo, code = require_repo()
|
|
40
35
|
if code != 0:
|
|
41
36
|
return code
|
|
42
37
|
|
|
43
|
-
|
|
44
38
|
status = repo.get_status()
|
|
45
|
-
untracked = status.get(
|
|
46
|
-
|
|
39
|
+
untracked = status.get("untracked", [])
|
|
40
|
+
|
|
47
41
|
if not untracked:
|
|
48
42
|
print("Nothing to clean.")
|
|
49
43
|
return 0
|
|
50
|
-
|
|
44
|
+
|
|
51
45
|
if args.dry_run:
|
|
52
46
|
print("Would remove:")
|
|
53
47
|
for p in untracked:
|
|
54
48
|
print(f" {p}")
|
|
55
49
|
return 0
|
|
56
|
-
|
|
50
|
+
|
|
57
51
|
if not args.force:
|
|
58
52
|
print("Use -f to force removal of untracked files.")
|
|
59
53
|
return 1
|
|
60
|
-
|
|
54
|
+
|
|
61
55
|
removed = 0
|
|
62
56
|
for rel_path in untracked:
|
|
63
57
|
full_path = repo.current_dir / rel_path
|
|
@@ -68,9 +62,10 @@ class CleanCommand:
|
|
|
68
62
|
print(f"Removed {rel_path}")
|
|
69
63
|
elif args.d and full_path.is_dir():
|
|
70
64
|
import shutil
|
|
65
|
+
|
|
71
66
|
shutil.rmtree(full_path)
|
|
72
67
|
removed += 1
|
|
73
68
|
print(f"Removed {rel_path}/")
|
|
74
|
-
|
|
69
|
+
|
|
75
70
|
print(f"Removed {removed} file(s)")
|
|
76
71
|
return 0
|
memvcs/commands/clone.py
CHANGED
|
@@ -80,12 +80,22 @@ class CloneCommand:
|
|
|
80
80
|
|
|
81
81
|
# Set remote origin to source
|
|
82
82
|
import json
|
|
83
|
+
|
|
83
84
|
config_file = target / ".mem" / "config.json"
|
|
84
85
|
config = json.loads(config_file.read_text()) if config_file.exists() else {}
|
|
85
86
|
if "remotes" not in config:
|
|
86
87
|
config["remotes"] = {}
|
|
87
|
-
config["remotes"]["origin"] = {
|
|
88
|
+
config["remotes"]["origin"] = {
|
|
89
|
+
"url": url if url.startswith("file://") else f"file://{remote_path}"
|
|
90
|
+
}
|
|
88
91
|
config_file.write_text(json.dumps(config, indent=2))
|
|
89
92
|
|
|
93
|
+
# Copy remote's public key to .mem/keys/remotes/origin.pub for trust store
|
|
94
|
+
remote_keys = remote_mem / "keys" / "public.pem"
|
|
95
|
+
if remote_keys.exists():
|
|
96
|
+
keys_remotes = target / ".mem" / "keys" / "remotes"
|
|
97
|
+
keys_remotes.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
shutil.copy2(remote_keys, keys_remotes / "origin.pub")
|
|
99
|
+
|
|
90
100
|
print(f"Cloned into {target}")
|
|
91
101
|
return 0
|
memvcs/commands/commit.py
CHANGED
|
@@ -7,88 +7,82 @@ from datetime import datetime
|
|
|
7
7
|
|
|
8
8
|
from ..commands.base import require_repo
|
|
9
9
|
from ..core.schema import SchemaValidator
|
|
10
|
-
from ..core.hooks import run_pre_commit_hooks
|
|
10
|
+
from ..core.hooks import run_pre_commit_hooks, compute_suggested_importance
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class CommitCommand:
|
|
14
14
|
"""Create a commit from staged changes."""
|
|
15
|
-
|
|
16
|
-
name =
|
|
17
|
-
help =
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
name = "commit"
|
|
17
|
+
help = "Save staged changes as a memory snapshot"
|
|
18
|
+
|
|
19
19
|
@staticmethod
|
|
20
20
|
def add_arguments(parser: argparse.ArgumentParser):
|
|
21
21
|
parser.add_argument(
|
|
22
|
-
|
|
23
|
-
required=True,
|
|
24
|
-
help='Commit message describing the changes'
|
|
25
|
-
)
|
|
26
|
-
parser.add_argument(
|
|
27
|
-
'--author',
|
|
28
|
-
help='Override default author'
|
|
22
|
+
"-m", "--message", required=True, help="Commit message describing the changes"
|
|
29
23
|
)
|
|
24
|
+
parser.add_argument("--author", help="Override default author")
|
|
30
25
|
parser.add_argument(
|
|
31
|
-
|
|
32
|
-
action='store_true',
|
|
33
|
-
help='Skip pre-commit hooks and schema validation'
|
|
26
|
+
"--no-verify", action="store_true", help="Skip pre-commit hooks and schema validation"
|
|
34
27
|
)
|
|
28
|
+
parser.add_argument("--strict", action="store_true", help="Treat schema warnings as errors")
|
|
35
29
|
parser.add_argument(
|
|
36
|
-
|
|
37
|
-
action='store_true',
|
|
38
|
-
help='Treat schema warnings as errors'
|
|
30
|
+
"--run-tests", action="store_true", help="Run memory tests before committing"
|
|
39
31
|
)
|
|
40
32
|
parser.add_argument(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
"--importance",
|
|
34
|
+
type=float,
|
|
35
|
+
metavar="SCORE",
|
|
36
|
+
help="Importance score 0.0-1.0 for recall/decay weighting",
|
|
44
37
|
)
|
|
45
|
-
|
|
38
|
+
|
|
46
39
|
@staticmethod
|
|
47
40
|
def _get_blob_hash(file_info) -> str:
|
|
48
41
|
"""Get blob hash from StagedFile or dict (for hooks that pass either)."""
|
|
49
|
-
if hasattr(file_info,
|
|
42
|
+
if hasattr(file_info, "blob_hash"):
|
|
50
43
|
return file_info.blob_hash
|
|
51
44
|
if isinstance(file_info, dict):
|
|
52
|
-
return file_info.get(
|
|
53
|
-
return
|
|
45
|
+
return file_info.get("blob_hash") or file_info.get("hash") or ""
|
|
46
|
+
return ""
|
|
54
47
|
|
|
55
48
|
@staticmethod
|
|
56
49
|
def _validate_staged_files(repo, staged: dict, strict: bool) -> tuple:
|
|
57
50
|
"""
|
|
58
51
|
Validate staged files for schema compliance.
|
|
59
|
-
|
|
52
|
+
|
|
60
53
|
Returns:
|
|
61
54
|
Tuple of (success, validation_results)
|
|
62
55
|
"""
|
|
63
56
|
validation_results = {}
|
|
64
57
|
has_errors = False
|
|
65
|
-
|
|
58
|
+
|
|
66
59
|
for filepath, file_info in staged.items():
|
|
67
60
|
blob_hash = CommitCommand._get_blob_hash(file_info)
|
|
68
61
|
if not blob_hash:
|
|
69
62
|
continue
|
|
70
|
-
|
|
63
|
+
|
|
71
64
|
# Read content from object store
|
|
72
65
|
from ..core.objects import Blob
|
|
66
|
+
|
|
73
67
|
blob = Blob.load(repo.object_store, blob_hash)
|
|
74
68
|
if not blob:
|
|
75
69
|
continue
|
|
76
|
-
|
|
70
|
+
|
|
77
71
|
try:
|
|
78
|
-
content = blob.content.decode(
|
|
72
|
+
content = blob.content.decode("utf-8")
|
|
79
73
|
except UnicodeDecodeError:
|
|
80
74
|
# Skip binary files
|
|
81
75
|
continue
|
|
82
|
-
|
|
76
|
+
|
|
83
77
|
# Validate the file
|
|
84
78
|
result = SchemaValidator.validate(content, filepath, strict=strict)
|
|
85
79
|
validation_results[filepath] = result
|
|
86
|
-
|
|
80
|
+
|
|
87
81
|
if not result.valid:
|
|
88
82
|
has_errors = True
|
|
89
|
-
|
|
83
|
+
|
|
90
84
|
return not has_errors, validation_results
|
|
91
|
-
|
|
85
|
+
|
|
92
86
|
@staticmethod
|
|
93
87
|
def _print_validation_results(results: dict) -> None:
|
|
94
88
|
"""Print validation results in a readable format."""
|
|
@@ -126,6 +120,7 @@ class CommitCommand:
|
|
|
126
120
|
"""Run memory tests if available. Returns 1 on failure, 0 on success or skip."""
|
|
127
121
|
try:
|
|
128
122
|
from ..core.test_runner import TestRunner
|
|
123
|
+
|
|
129
124
|
test_runner = TestRunner(repo)
|
|
130
125
|
test_result = test_runner.run_all()
|
|
131
126
|
if not test_result.passed:
|
|
@@ -156,13 +151,19 @@ class CommitCommand:
|
|
|
156
151
|
if args.run_tests:
|
|
157
152
|
if CommitCommand._run_memory_tests(repo) != 0:
|
|
158
153
|
return 1
|
|
159
|
-
metadata = {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
154
|
+
metadata = {"files_changed": len(staged), "timestamp": datetime.utcnow().isoformat() + "Z"}
|
|
155
|
+
# Importance scoring: explicit --importance or auto from heuristics
|
|
156
|
+
if args.importance is not None:
|
|
157
|
+
if not (0.0 <= args.importance <= 1.0):
|
|
158
|
+
print("Error: --importance must be between 0.0 and 1.0")
|
|
159
|
+
return 1
|
|
160
|
+
metadata["importance"] = args.importance
|
|
161
|
+
else:
|
|
162
|
+
suggested = compute_suggested_importance(repo, staged, args.message, metadata)
|
|
163
|
+
metadata["importance"] = suggested
|
|
163
164
|
if args.author:
|
|
164
165
|
config = repo.get_config()
|
|
165
|
-
config[
|
|
166
|
+
config["author"]["name"] = args.author
|
|
166
167
|
repo.set_config(config)
|
|
167
168
|
try:
|
|
168
169
|
commit_hash = repo.commit(args.message, metadata)
|