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
memvcs/commands/fsck.py CHANGED
@@ -10,44 +10,39 @@ from ..commands.base import require_repo
10
10
 
11
11
  class FsckCommand:
12
12
  """Check and repair repository consistency."""
13
-
14
- name = 'fsck'
15
- help = 'Check and repair repository consistency (remove dangling vectors)'
16
-
13
+
14
+ name = "fsck"
15
+ help = "Check and repair repository consistency (remove dangling vectors)"
16
+
17
17
  @staticmethod
18
18
  def add_arguments(parser: argparse.ArgumentParser):
19
19
  parser.add_argument(
20
- '--dry-run',
21
- action='store_true',
22
- help='Show what would be done without making changes'
20
+ "--dry-run", action="store_true", help="Show what would be done without making changes"
23
21
  )
22
+ parser.add_argument("--verbose", "-v", action="store_true", help="Show detailed output")
24
23
  parser.add_argument(
25
- '--verbose', '-v',
26
- action='store_true',
27
- help='Show detailed output'
24
+ "--fix",
25
+ action="store_true",
26
+ help="Actually remove dangling entries (required to make changes)",
28
27
  )
29
- parser.add_argument(
30
- '--fix',
31
- action='store_true',
32
- help='Actually remove dangling entries (required to make changes)'
33
- )
34
-
28
+
35
29
  @staticmethod
36
30
  def execute(args) -> int:
37
31
  repo, code = require_repo()
38
32
  if code != 0:
39
33
  return code
40
-
34
+
41
35
  print("Running file system consistency check...")
42
-
36
+
43
37
  issues_found = 0
44
38
  issues_fixed = 0
45
-
39
+
46
40
  # Check vector store for dangling entries
47
41
  try:
48
42
  from ..core.vector_store import VectorStore
49
- vs = VectorStore(repo.root / '.mem')
50
-
43
+
44
+ vs = VectorStore(repo.root / ".mem")
45
+
51
46
  vector_issues, vector_fixed = FsckCommand._check_vectors(
52
47
  repo, vs, args.dry_run, args.verbose, args.fix
53
48
  )
@@ -58,64 +53,62 @@ class FsckCommand:
58
53
  print("Vector store not available, skipping vector check")
59
54
  except Exception as e:
60
55
  print(f"Warning: Vector store check failed: {e}")
61
-
56
+
62
57
  # Check object store integrity
63
58
  obj_issues, obj_fixed = FsckCommand._check_objects(
64
59
  repo, args.dry_run, args.verbose, args.fix
65
60
  )
66
61
  issues_found += obj_issues
67
62
  issues_fixed += obj_fixed
68
-
63
+
69
64
  # Check refs integrity
70
- ref_issues, ref_fixed = FsckCommand._check_refs(
71
- repo, args.dry_run, args.verbose, args.fix
72
- )
65
+ ref_issues, ref_fixed = FsckCommand._check_refs(repo, args.dry_run, args.verbose, args.fix)
73
66
  issues_found += ref_issues
74
67
  issues_fixed += ref_fixed
75
-
68
+
76
69
  # Print summary
77
70
  print()
78
71
  print("=" * 40)
79
72
  print("FSCK Summary")
80
73
  print("=" * 40)
81
74
  print(f"Issues found: {issues_found}")
82
-
75
+
83
76
  if args.fix:
84
77
  print(f"Issues fixed: {issues_fixed}")
85
78
  elif issues_found > 0:
86
79
  print("\nRun with --fix to repair issues")
87
-
80
+
88
81
  if issues_found == 0:
89
82
  print("Repository is healthy!")
90
-
83
+
91
84
  return 0 if issues_found == 0 else 1
92
-
85
+
93
86
  @staticmethod
94
87
  def _check_vectors(repo, vs, dry_run: bool, verbose: bool, fix: bool) -> tuple:
95
88
  """Check for dangling vector entries."""
96
89
  print("\nChecking vector store...")
97
-
98
- current_dir = repo.root / 'current'
90
+
91
+ current_dir = repo.root / "current"
99
92
  entries = vs.get_all_entries()
100
-
93
+
101
94
  dangling = []
102
-
95
+
103
96
  for entry in entries:
104
- path = entry['path']
97
+ path = entry["path"]
105
98
  full_path = current_dir / path
106
-
99
+
107
100
  if not full_path.exists():
108
101
  dangling.append(entry)
109
102
  if verbose:
110
103
  print(f" Dangling: {path} (rowid: {entry['rowid']})")
111
-
104
+
112
105
  if dangling:
113
106
  print(f" Found {len(dangling)} dangling vector entries")
114
-
107
+
115
108
  if fix and not dry_run:
116
109
  fixed = 0
117
110
  for entry in dangling:
118
- if vs.delete_entry(entry['rowid']):
111
+ if vs.delete_entry(entry["rowid"]):
119
112
  fixed += 1
120
113
  print(f" Removed {fixed} dangling entries")
121
114
  return len(dangling), fixed
@@ -123,22 +116,22 @@ class FsckCommand:
123
116
  print(" (dry-run: no changes made)")
124
117
  else:
125
118
  print(" Vector store is consistent")
126
-
119
+
127
120
  return len(dangling), 0
128
-
121
+
129
122
  @staticmethod
130
123
  def _check_objects(repo, dry_run: bool, verbose: bool, fix: bool) -> tuple:
131
124
  """Check object store integrity."""
132
125
  print("\nChecking object store...")
133
-
126
+
134
127
  issues = 0
135
-
128
+
136
129
  # Check if all referenced blobs exist
137
- for obj_type in ['blob', 'tree', 'commit', 'tag']:
138
- obj_dir = repo.root / '.mem' / 'objects' / obj_type
130
+ for obj_type in ["blob", "tree", "commit", "tag"]:
131
+ obj_dir = repo.root / ".mem" / "objects" / obj_type
139
132
  if not obj_dir.exists():
140
133
  continue
141
-
134
+
142
135
  for prefix_dir in obj_dir.iterdir():
143
136
  if not prefix_dir.is_dir():
144
137
  continue
@@ -146,6 +139,7 @@ class FsckCommand:
146
139
  try:
147
140
  # Try to read and decompress
148
141
  import zlib
142
+
149
143
  compressed = obj_file.read_bytes()
150
144
  zlib.decompress(compressed)
151
145
  except Exception as e:
@@ -153,51 +147,51 @@ class FsckCommand:
153
147
  if verbose:
154
148
  hash_id = prefix_dir.name + obj_file.name
155
149
  print(f" Corrupted {obj_type}: {hash_id[:8]}...")
156
-
150
+
157
151
  if issues == 0:
158
152
  print(" Object store is consistent")
159
153
  else:
160
154
  print(f" Found {issues} corrupted objects")
161
-
155
+
162
156
  return issues, 0 # Object repair not implemented
163
-
157
+
164
158
  @staticmethod
165
159
  def _check_refs(repo, dry_run: bool, verbose: bool, fix: bool) -> tuple:
166
160
  """Check refs integrity."""
167
161
  print("\nChecking refs...")
168
-
162
+
169
163
  issues = 0
170
-
164
+
171
165
  # Check if HEAD points to valid commit
172
166
  head = repo.refs.get_head()
173
- if head['type'] == 'branch':
174
- branch_commit = repo.refs.get_branch_commit(head['value'])
167
+ if head["type"] == "branch":
168
+ branch_commit = repo.refs.get_branch_commit(head["value"])
175
169
  if not branch_commit:
176
170
  issues += 1
177
171
  if verbose:
178
172
  print(f" HEAD branch '{head['value']}' has no commit")
179
- elif not repo.object_store.exists(branch_commit, 'commit'):
173
+ elif not repo.object_store.exists(branch_commit, "commit"):
180
174
  issues += 1
181
175
  if verbose:
182
176
  print(f" HEAD points to missing commit: {branch_commit[:8]}")
183
- elif head['type'] == 'detached':
184
- if not repo.object_store.exists(head['value'], 'commit'):
177
+ elif head["type"] == "detached":
178
+ if not repo.object_store.exists(head["value"], "commit"):
185
179
  issues += 1
186
180
  if verbose:
187
181
  print(f" Detached HEAD points to missing commit")
188
-
182
+
189
183
  # Check all branches
190
184
  branches = repo.refs.list_branches()
191
185
  for branch in branches:
192
186
  commit_hash = repo.refs.get_branch_commit(branch)
193
- if commit_hash and not repo.object_store.exists(commit_hash, 'commit'):
187
+ if commit_hash and not repo.object_store.exists(commit_hash, "commit"):
194
188
  issues += 1
195
189
  if verbose:
196
190
  print(f" Branch '{branch}' points to missing commit")
197
-
191
+
198
192
  if issues == 0:
199
193
  print(" Refs are consistent")
200
194
  else:
201
195
  print(f" Found {issues} ref issues")
202
-
196
+
203
197
  return issues, 0
memvcs/commands/garden.py CHANGED
@@ -10,96 +10,87 @@ from ..core.gardener import Gardener, GardenerConfig
10
10
 
11
11
  class GardenCommand:
12
12
  """Run the Gardener reflection loop."""
13
-
14
- name = 'garden'
15
- help = 'Synthesize episodic memories into semantic insights'
16
-
13
+
14
+ name = "garden"
15
+ help = "Synthesize episodic memories into semantic insights"
16
+
17
17
  @staticmethod
18
18
  def add_arguments(parser: argparse.ArgumentParser):
19
19
  parser.add_argument(
20
- '--force',
21
- action='store_true',
22
- help='Run even if episode threshold not met'
20
+ "--force", action="store_true", help="Run even if episode threshold not met"
23
21
  )
24
22
  parser.add_argument(
25
- '--threshold',
23
+ "--threshold",
26
24
  type=int,
27
25
  default=50,
28
- help='Number of episodes before auto-triggering (default: 50)'
29
- )
30
- parser.add_argument(
31
- '--dry-run',
32
- action='store_true',
33
- help='Show what would be done without making changes'
26
+ help="Number of episodes before auto-triggering (default: 50)",
34
27
  )
35
28
  parser.add_argument(
36
- '--no-commit',
37
- action='store_true',
38
- help='Do not auto-commit generated insights'
29
+ "--dry-run", action="store_true", help="Show what would be done without making changes"
39
30
  )
40
31
  parser.add_argument(
41
- '--llm',
42
- choices=['openai', 'none'],
43
- default='none',
44
- help='LLM provider for summarization (default: none)'
32
+ "--no-commit", action="store_true", help="Do not auto-commit generated insights"
45
33
  )
46
34
  parser.add_argument(
47
- '--model',
48
- help='LLM model to use (e.g., gpt-3.5-turbo)'
35
+ "--llm",
36
+ choices=["openai", "none"],
37
+ default="none",
38
+ help="LLM provider for summarization (default: none)",
49
39
  )
50
-
40
+ parser.add_argument("--model", help="LLM model to use (e.g., gpt-3.5-turbo)")
41
+
51
42
  @staticmethod
52
43
  def execute(args) -> int:
53
44
  repo, code = require_repo()
54
45
  if code != 0:
55
46
  return code
56
-
47
+
57
48
  # Build config
58
49
  config = GardenerConfig(
59
50
  threshold=args.threshold,
60
51
  auto_commit=not args.no_commit,
61
- llm_provider=args.llm if args.llm != 'none' else None,
62
- llm_model=args.model
52
+ llm_provider=args.llm if args.llm != "none" else None,
53
+ llm_model=args.model,
63
54
  )
64
-
55
+
65
56
  # Create gardener
66
57
  gardener = Gardener(repo, config)
67
-
58
+
68
59
  # Show status
69
60
  episode_count = gardener.get_episode_count()
70
61
  print(f"Episodic files: {episode_count}/{config.threshold}")
71
-
62
+
72
63
  if args.dry_run:
73
64
  if gardener.should_run() or args.force:
74
65
  episodes = gardener.load_episodes()
75
66
  clusters = gardener.cluster_episodes(episodes)
76
-
67
+
77
68
  print(f"\nWould process {len(episodes)} episodes into {len(clusters)} clusters:")
78
69
  for cluster in clusters:
79
70
  print(f" - {cluster.topic}: {len(cluster.episodes)} episodes")
80
-
71
+
81
72
  print("\nRun without --dry-run to execute.")
82
73
  else:
83
74
  print("\nThreshold not met. Use --force to run anyway.")
84
75
  return 0
85
-
76
+
86
77
  # Run gardener
87
78
  if not gardener.should_run() and not args.force:
88
79
  print("\nThreshold not met. Use --force to run anyway.")
89
80
  return 0
90
-
81
+
91
82
  print("\nRunning Gardener...")
92
83
  result = gardener.run(force=args.force)
93
-
84
+
94
85
  if result.success:
95
86
  print(f"\nGardener completed:")
96
87
  print(f" Clusters found: {result.clusters_found}")
97
88
  print(f" Insights generated: {result.insights_generated}")
98
89
  print(f" Episodes archived: {result.episodes_archived}")
99
-
90
+
100
91
  if result.commit_hash:
101
92
  print(f" Commit: {result.commit_hash[:8]}")
102
-
93
+
103
94
  print(f"\n{result.message}")
104
95
  return 0
105
96
  else:
memvcs/commands/graph.py CHANGED
@@ -11,109 +11,102 @@ from ..commands.base import require_repo
11
11
 
12
12
  class GraphCommand:
13
13
  """Visualize connections between memory files."""
14
-
15
- name = 'graph'
16
- help = 'Visualize the knowledge graph of memory files'
17
-
14
+
15
+ name = "graph"
16
+ help = "Visualize the knowledge graph of memory files"
17
+
18
18
  @staticmethod
19
19
  def add_arguments(parser: argparse.ArgumentParser):
20
+ parser.add_argument("--output", "-o", help="Output file for graph data (JSON)")
20
21
  parser.add_argument(
21
- '--output', '-o',
22
- help='Output file for graph data (JSON)'
23
- )
24
- parser.add_argument(
25
- '--format',
26
- choices=['json', 'd3', 'summary'],
27
- default='summary',
28
- help='Output format (default: summary)'
22
+ "--format",
23
+ choices=["json", "d3", "summary"],
24
+ default="summary",
25
+ help="Output format (default: summary)",
29
26
  )
30
27
  parser.add_argument(
31
- '--no-similarity',
32
- action='store_true',
33
- help='Skip similarity-based edges (faster)'
28
+ "--no-similarity", action="store_true", help="Skip similarity-based edges (faster)"
34
29
  )
35
30
  parser.add_argument(
36
- '--threshold',
31
+ "--threshold",
37
32
  type=float,
38
33
  default=0.7,
39
- help='Similarity threshold for edges (default: 0.7)'
34
+ help="Similarity threshold for edges (default: 0.7)",
40
35
  )
41
36
  parser.add_argument(
42
- '--serve',
43
- action='store_true',
44
- help='Start web server to view interactive graph'
37
+ "--serve", action="store_true", help="Start web server to view interactive graph"
45
38
  )
46
-
39
+
47
40
  @staticmethod
48
41
  def execute(args) -> int:
49
42
  repo, code = require_repo()
50
43
  if code != 0:
51
44
  return code
52
-
45
+
53
46
  # Try to get vector store for similarity
54
47
  vector_store = None
55
48
  if not args.no_similarity:
56
49
  try:
57
50
  from ..core.vector_store import VectorStore
58
- vector_store = VectorStore(repo.root / '.mem')
51
+
52
+ vector_store = VectorStore(repo.root / ".mem")
59
53
  except ImportError:
60
54
  print("Note: Vector store not available, skipping similarity edges")
61
-
55
+
62
56
  # Build graph
63
57
  from ..core.knowledge_graph import KnowledgeGraphBuilder
64
-
58
+
65
59
  builder = KnowledgeGraphBuilder(repo, vector_store)
66
-
60
+
67
61
  print("Building knowledge graph...")
68
62
  graph_data = builder.build_graph(
69
- include_similarity=not args.no_similarity,
70
- similarity_threshold=args.threshold
63
+ include_similarity=not args.no_similarity, similarity_threshold=args.threshold
71
64
  )
72
-
65
+
73
66
  if args.serve:
74
67
  return GraphCommand._serve_graph(repo, graph_data)
75
-
76
- if args.format == 'summary':
68
+
69
+ if args.format == "summary":
77
70
  GraphCommand._print_summary(graph_data, builder)
78
-
79
- elif args.format == 'json':
71
+
72
+ elif args.format == "json":
80
73
  output = graph_data.to_json()
81
74
  if args.output:
82
75
  Path(args.output).write_text(output)
83
76
  print(f"Graph data written to: {args.output}")
84
77
  else:
85
78
  print(output)
86
-
87
- elif args.format == 'd3':
79
+
80
+ elif args.format == "d3":
88
81
  output = builder.export_for_d3()
89
82
  if args.output:
90
83
  Path(args.output).write_text(output)
91
84
  print(f"D3 graph data written to: {args.output}")
92
85
  else:
93
86
  print(output)
94
-
87
+
95
88
  return 0
96
-
89
+
97
90
  @staticmethod
98
91
  def _print_summary(graph_data, builder):
99
92
  """Print a text summary of the graph."""
100
93
  meta = graph_data.metadata
101
-
94
+
102
95
  print("\nKnowledge Graph Summary")
103
96
  print("=" * 40)
104
97
  print(f"Total files: {meta['total_nodes']}")
105
98
  print(f"Total connections: {meta['total_edges']}")
106
-
99
+
107
100
  print("\nBy Memory Type:")
108
- for mtype, count in meta['memory_types'].items():
101
+ for mtype, count in meta["memory_types"].items():
109
102
  if count > 0:
110
103
  print(f" {mtype}: {count}")
111
-
104
+
112
105
  print("\nBy Edge Type:")
113
- for etype, count in meta['edge_types'].items():
106
+ for etype, count in meta["edge_types"].items():
114
107
  if count > 0:
115
108
  print(f" {etype}: {count}")
116
-
109
+
117
110
  # Find isolated nodes
118
111
  isolated = builder.find_isolated_nodes()
119
112
  if isolated:
@@ -122,16 +115,16 @@ class GraphCommand:
122
115
  print(f" - {path}")
123
116
  if len(isolated) > 5:
124
117
  print(f" ... and {len(isolated) - 5} more")
125
-
118
+
126
119
  # Find potential contradictions
127
120
  contradictions = builder.find_potential_contradictions()
128
121
  if contradictions:
129
122
  print(f"\nPotential contradictions: {len(contradictions)}")
130
123
  for path1, path2, sim in contradictions[:3]:
131
124
  print(f" - {path1} <-> {path2} (similarity: {sim:.2%})")
132
-
125
+
133
126
  print("\nUse --format d3 --output graph.json to export for visualization")
134
-
127
+
135
128
  @staticmethod
136
129
  def _serve_graph(repo, graph_data):
137
130
  """Start web server to view interactive graph."""
@@ -142,10 +135,10 @@ class GraphCommand:
142
135
  print("Error: Web server requires fastapi and uvicorn.")
143
136
  print("Install with: pip install agmem[web]")
144
137
  return 1
145
-
138
+
146
139
  print("Starting graph visualization server...")
147
140
  print("Open http://localhost:8080/graph in your browser")
148
-
141
+
149
142
  app = create_app(repo.root)
150
143
  uvicorn.run(app, host="127.0.0.1", port=8080)
151
144
  return 0
memvcs/commands/init.py CHANGED
@@ -10,49 +10,41 @@ from ..core.repository import Repository
10
10
 
11
11
  class InitCommand:
12
12
  """Initialize a new agmem repository."""
13
-
14
- name = 'init'
15
- help = 'Initialize a new memory repository'
16
-
13
+
14
+ name = "init"
15
+ help = "Initialize a new memory repository"
16
+
17
17
  @staticmethod
18
18
  def add_arguments(parser: argparse.ArgumentParser):
19
19
  parser.add_argument(
20
- 'path',
21
- nargs='?',
22
- default='.',
23
- help='Directory to initialize repository in (default: current directory)'
20
+ "path",
21
+ nargs="?",
22
+ default=".",
23
+ help="Directory to initialize repository in (default: current directory)",
24
24
  )
25
+ parser.add_argument("--author-name", default="Agent", help="Default author name")
25
26
  parser.add_argument(
26
- '--author-name',
27
- default='Agent',
28
- help='Default author name'
27
+ "--author-email", default="agent@example.com", help="Default author email"
29
28
  )
30
- parser.add_argument(
31
- '--author-email',
32
- default='agent@example.com',
33
- help='Default author email'
34
- )
35
-
29
+
36
30
  @staticmethod
37
31
  def execute(args) -> int:
38
32
  path = Path(args.path).resolve()
39
-
33
+
40
34
  try:
41
35
  repo = Repository.init(
42
- path=path,
43
- author_name=args.author_name,
44
- author_email=args.author_email
36
+ path=path, author_name=args.author_name, author_email=args.author_email
45
37
  )
46
-
38
+
47
39
  print(f"Initialized empty agmem repository in {repo.mem_dir}")
48
40
  print(f"Author: {args.author_name} <{args.author_email}>")
49
41
  print(f"\nNext steps:")
50
42
  print(f" 1. Add memory files to {repo.current_dir}/")
51
43
  print(f" 2. Run 'agmem add <file>' to stage changes")
52
44
  print(f" 3. Run 'agmem commit -m \"message\"' to save snapshot")
53
-
45
+
54
46
  return 0
55
-
47
+
56
48
  except ValueError as e:
57
49
  print(f"Error: {e}")
58
50
  return 1