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.
- {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/METADATA +20 -3
- agmem-0.1.2.dist-info/RECORD +86 -0
- memvcs/__init__.py +1 -1
- memvcs/cli.py +35 -31
- memvcs/commands/__init__.py +9 -9
- memvcs/commands/add.py +77 -76
- 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 +4 -1
- memvcs/commands/commit.py +40 -39
- memvcs/commands/daemon.py +81 -76
- memvcs/commands/decay.py +77 -0
- memvcs/commands/diff.py +56 -57
- memvcs/commands/distill.py +74 -0
- memvcs/commands/fsck.py +55 -61
- memvcs/commands/garden.py +28 -37
- memvcs/commands/graph.py +41 -48
- memvcs/commands/init.py +16 -24
- memvcs/commands/log.py +25 -40
- memvcs/commands/merge.py +16 -28
- memvcs/commands/pack.py +129 -0
- memvcs/commands/pull.py +4 -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/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 +59 -0
- memvcs/commands/when.py +115 -0
- memvcs/core/access_index.py +167 -0
- memvcs/core/config_loader.py +3 -1
- memvcs/core/consistency.py +214 -0
- memvcs/core/decay.py +185 -0
- memvcs/core/diff.py +158 -143
- memvcs/core/distiller.py +277 -0
- memvcs/core/gardener.py +164 -132
- memvcs/core/hooks.py +48 -14
- memvcs/core/knowledge_graph.py +134 -138
- memvcs/core/merge.py +248 -171
- memvcs/core/objects.py +95 -96
- memvcs/core/pii_scanner.py +147 -146
- memvcs/core/refs.py +132 -115
- memvcs/core/repository.py +174 -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 +112 -0
- memvcs/core/test_runner.py +101 -93
- memvcs/core/vector_store.py +41 -35
- 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.2.dist-info}/WHEEL +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/entry_points.txt +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {agmem-0.1.1.dist-info → agmem-0.1.2.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agmem
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Agentic Memory Version Control System - Git for AI agent memories
|
|
5
5
|
Home-page: https://github.com/vivek-tiwari-vt/agmem
|
|
6
6
|
Author: agmem Team
|
|
@@ -16,7 +16,6 @@ Classifier: Intended Audience :: Developers
|
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -30,7 +29,7 @@ Requires-Dist: PyYAML>=6.0.0
|
|
|
30
29
|
Provides-Extra: dev
|
|
31
30
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
32
31
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
33
|
-
Requires-Dist: black
|
|
32
|
+
Requires-Dist: black==24.10.0; extra == "dev"
|
|
34
33
|
Requires-Dist: flake8>=5.0.0; extra == "dev"
|
|
35
34
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
36
35
|
Provides-Extra: mcp
|
|
@@ -53,6 +52,12 @@ Provides-Extra: daemon
|
|
|
53
52
|
Requires-Dist: watchdog>=3.0.0; extra == "daemon"
|
|
54
53
|
Provides-Extra: graph
|
|
55
54
|
Requires-Dist: networkx>=3.0; extra == "graph"
|
|
55
|
+
Provides-Extra: pack
|
|
56
|
+
Requires-Dist: tiktoken>=0.5.0; extra == "pack"
|
|
57
|
+
Provides-Extra: distill
|
|
58
|
+
Requires-Dist: openai>=1.0.0; extra == "distill"
|
|
59
|
+
Provides-Extra: verify
|
|
60
|
+
Requires-Dist: openai>=1.0.0; extra == "verify"
|
|
56
61
|
Provides-Extra: all
|
|
57
62
|
Requires-Dist: mcp>=1.0.0; extra == "all"
|
|
58
63
|
Requires-Dist: sqlite-vec>=0.1.0; extra == "all"
|
|
@@ -72,6 +77,7 @@ Dynamic: requires-python
|
|
|
72
77
|
|
|
73
78
|
# agmem - Agentic Memory Version Control System
|
|
74
79
|
|
|
80
|
+
[](https://pypi.org/project/agmem/)
|
|
75
81
|
[](https://www.python.org/downloads/)
|
|
76
82
|
[](https://opensource.org/licenses/MIT)
|
|
77
83
|
[](https://github.com/psf/black)
|
|
@@ -109,6 +115,8 @@ agmem solves all of these problems with a familiar Git-like interface.
|
|
|
109
115
|
|
|
110
116
|
### Installation
|
|
111
117
|
|
|
118
|
+
**From PyPI** ([pypi.org/project/agmem](https://pypi.org/project/agmem/)):
|
|
119
|
+
|
|
112
120
|
```bash
|
|
113
121
|
pip install agmem
|
|
114
122
|
```
|
|
@@ -639,6 +647,15 @@ Or connect via MCP and call `memory_add` from your agent.
|
|
|
639
647
|
3. Write via `agmem add` + `agmem commit` or MCP `memory_add`
|
|
640
648
|
4. Optional: Use `agmem search` for semantic retrieval
|
|
641
649
|
|
|
650
|
+
## Links
|
|
651
|
+
|
|
652
|
+
- **PyPI:** [pypi.org/project/agmem](https://pypi.org/project/agmem/) — `pip install agmem`
|
|
653
|
+
|
|
654
|
+
**GitHub repo (About):** Use this description and topics in your repo’s **About** (gear → Description & topics):
|
|
655
|
+
|
|
656
|
+
- **Description:** Git for AI agent memories. Version control for episodic logs, semantic knowledge, and procedural workflows.
|
|
657
|
+
- **Topics:** `ai` `agent` `memory` `version-control` `git` `vcs` `llm` `python`
|
|
658
|
+
|
|
642
659
|
## Contributing
|
|
643
660
|
|
|
644
661
|
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
agmem-0.1.2.dist-info/licenses/LICENSE,sha256=X_S6RBErW-F0IDbM3FAEoDB-zxExFnl2m8640rTXphM,1067
|
|
2
|
+
memvcs/__init__.py,sha256=mXwHTSlUPWo4ERqJLGJnxmxtGQQHPSbXb4IpO61l04M,193
|
|
3
|
+
memvcs/cli.py,sha256=0bIdOVz23ZON4i8LoAsepiII-DpiGTGysllXFwmG0GI,5771
|
|
4
|
+
memvcs/commands/__init__.py,sha256=A2D6xWaO6epU7iV4QSvqvF5TspnwRyDN7NojmGatPrE,510
|
|
5
|
+
memvcs/commands/add.py,sha256=5Bia5nLfaREyp-ujqReDOyZu6zF5WveQk_N8XkWmqnM,8511
|
|
6
|
+
memvcs/commands/base.py,sha256=yWvIYuofRxbHXvChlSd_DL_hJMaQdbZwa2XBDWj5Bio,634
|
|
7
|
+
memvcs/commands/blame.py,sha256=2tEXyXpAebm_zQFAyw-6d3K09Lnh1GVLYGp6htlEmI0,5605
|
|
8
|
+
memvcs/commands/branch.py,sha256=ghsK4tnGe7XApxQSgou7V0BASBC8PL8nQs_yBt0notQ,3150
|
|
9
|
+
memvcs/commands/checkout.py,sha256=xaYZSbCQ-MyLWPtwA2FdH6WqGMI3oF3R2JmCufGBVFg,3182
|
|
10
|
+
memvcs/commands/clean.py,sha256=e0OhSQdHfFnOPTRbyKbM8IcX4yJD5n_kaBKjIeoaRBo,1973
|
|
11
|
+
memvcs/commands/clone.py,sha256=EAeojcUpRyCj1tVLR5zqnbkdF6Cvpza0_gyjZoCHysw,2895
|
|
12
|
+
memvcs/commands/commit.py,sha256=W4ulVZuEETJh1SHpscaQfNjyQMqeIE0AYZIbMbTrsq4,6801
|
|
13
|
+
memvcs/commands/daemon.py,sha256=B9_a7DFXMde9Fphpo7J9-osXqYCby-KfvITObJ3VqIo,8589
|
|
14
|
+
memvcs/commands/decay.py,sha256=QcgOTMJZxrfw_AOz94YHA3LGoNXRMDn69TxWlUrpSw4,2421
|
|
15
|
+
memvcs/commands/diff.py,sha256=KcgD57_fae4uvQ8G9ZbXmLpAYYIDiWiBuVcjsDtyE1U,5480
|
|
16
|
+
memvcs/commands/distill.py,sha256=Inl6igvjewGTT1L4nH48PIi8_oUtlFgJwq1gUTosI9E,2171
|
|
17
|
+
memvcs/commands/fsck.py,sha256=PQWEoqmGKhjZEEMYBf1pnORz8j-YaOLFojmQkND3m3Q,6545
|
|
18
|
+
memvcs/commands/garden.py,sha256=0ZbohharxBC6-n1Y2Cgpyfpwuzlq_vmWi3Yu0pQRQBA,3269
|
|
19
|
+
memvcs/commands/graph.py,sha256=MDi6bK2w0OrpK5VOE8XXw5gQX7BuD7VzUyqJ5Ra9Bsg,4746
|
|
20
|
+
memvcs/commands/init.py,sha256=TsrLFLXwkDFT0opsYJTfwu0NIxLrNiiba5SpzRtxjDI,1614
|
|
21
|
+
memvcs/commands/log.py,sha256=eNlLs0-PS2nF0pMAMI8izKGUiEb2m3S0RB4Zh6cUQpE,2859
|
|
22
|
+
memvcs/commands/mcp.py,sha256=PMfwVD6uHltN58Jh7IOiS1w7oND42tg14QKRCJNudmY,1740
|
|
23
|
+
memvcs/commands/merge.py,sha256=kB9bXBagZrZYz1mozVGwelMTJ3ATm9QyINrE90FhXhA,2417
|
|
24
|
+
memvcs/commands/pack.py,sha256=rIDjMpxJG0oxrWnB3vCGHqviCITIeIbdy3nhuHVHzM8,3629
|
|
25
|
+
memvcs/commands/pull.py,sha256=qeEtBEuXo-BLsOqBU146V2lUK1WrCNp1d8z6qqWhhyU,2113
|
|
26
|
+
memvcs/commands/push.py,sha256=0abEdHkCMfHpH_Nmlw3OaU7Hzi0-RXF-cTVHpiSPw6k,5086
|
|
27
|
+
memvcs/commands/recall.py,sha256=7nwC4mFYpdjKWG-Cs3cpDLr5_SgYJ6HkVSXDOkFke5A,4592
|
|
28
|
+
memvcs/commands/reflog.py,sha256=j8Rxw_4jZuldS1k1g3wF2EItmPxBEmogWcbccOZrGkw,1117
|
|
29
|
+
memvcs/commands/remote.py,sha256=4PXDZjoU4YA4IbGrn_1KbFVCSVxVB_pVdI2nIn1NSbw,1761
|
|
30
|
+
memvcs/commands/repair.py,sha256=OBVa30Zc9rOjUw2GoiSAC6iZrnuCZN_J8nHpCnk5BzM,2312
|
|
31
|
+
memvcs/commands/reset.py,sha256=3TG7qOu2k1uji-TdSyXsdZ6LV2wqc2MB8aSJ6q71IGk,2778
|
|
32
|
+
memvcs/commands/resurrect.py,sha256=zi4ErN1jWVCn8I5rV4g_Dlbg1YadGEU6Xhc7srzlwfg,2503
|
|
33
|
+
memvcs/commands/search.py,sha256=NOMbkQmVurQ-_d7bZVf9vjOH6OgVPeErqpLZiSxsvBA,5322
|
|
34
|
+
memvcs/commands/serve.py,sha256=n8DroVRIQVm5UO2-o-9JU17pQYF-HYOMIJKycdRcBMs,1408
|
|
35
|
+
memvcs/commands/show.py,sha256=5YiIfY0368UB9sP9KE8J5O_rB2opdr8zrJswnLHgMCA,5268
|
|
36
|
+
memvcs/commands/stash.py,sha256=CD3mRWehcmfVRPGGpndUBdTT_ku4LC_rmSKPvTEOTAo,3193
|
|
37
|
+
memvcs/commands/status.py,sha256=O6BgzTiW3UHjXx6OKwH8X4g0hP0IlYDgr7As5RmeujU,3447
|
|
38
|
+
memvcs/commands/tag.py,sha256=CaCnA3JifVrdr8DfX4g0bp-_oRvagJkQFcI4bJbW1uM,3004
|
|
39
|
+
memvcs/commands/test.py,sha256=HZrpGZQhu9HnGZLjiq8TXi8jfOZqP-wc3bW6mgpP2yk,3926
|
|
40
|
+
memvcs/commands/timeline.py,sha256=xdOr2jz-_ArSPY-GxwXBloiwhfBzIfz4MAi-JEhP8H0,3666
|
|
41
|
+
memvcs/commands/tree.py,sha256=vdULq4vIXA_4gNfMnHn_Y78BwE0sJoeTBOnFJR3WsZ4,4927
|
|
42
|
+
memvcs/commands/verify.py,sha256=aH0FN_7xRulRV2oSLYSB4BiAw_U81IkZ5sFdBRmxdZ0,1858
|
|
43
|
+
memvcs/commands/when.py,sha256=MMQ15PFXFCTmjIq7dr0tC0XvGAdndMvckVnnWehc60Y,3692
|
|
44
|
+
memvcs/core/__init__.py,sha256=dkIC-4tS0GhwV2mZIbofEe8xR8uiFwrxslGf1aXwhYg,493
|
|
45
|
+
memvcs/core/access_index.py,sha256=HhacnzSUASzRV2jhDHkwRFoPS3rtqh9n9yE1VV7JXpk,5596
|
|
46
|
+
memvcs/core/config_loader.py,sha256=j-jgLDp2TRzWN9ZEZebfWSfatevBNYs0FEb3ud1SIR8,8277
|
|
47
|
+
memvcs/core/consistency.py,sha256=JUUlrGB8b2DMmozoP7KFNqd6nSLzKDZaHGbYyKlK_l8,7464
|
|
48
|
+
memvcs/core/constants.py,sha256=WUjAb50BFcF0mbFi_GNteDLCxLihmViBm9Fb-JMPmbM,220
|
|
49
|
+
memvcs/core/decay.py,sha256=ROGwnqngs7eJNkbKmwyOdij607m73vpmoJqzrIDLBzk,6581
|
|
50
|
+
memvcs/core/diff.py,sha256=koEHTLciIUxYKVJVuvmY0GDXMgDgGZP_qg5RayhF-iE,13226
|
|
51
|
+
memvcs/core/distiller.py,sha256=QBoTz3xFVepwGHOXVuIr5qfln2tkNo1CtcBpKIjsnqc,10337
|
|
52
|
+
memvcs/core/gardener.py,sha256=bFMyHU5H5-rYZIahT8j14ZOvBs5LSVhYZiTbyw7SQl4,16080
|
|
53
|
+
memvcs/core/hooks.py,sha256=XF9z8J5sWjAcuOyWQ2nuvEzK0UV8s4ThrcltaBZttzw,5448
|
|
54
|
+
memvcs/core/knowledge_graph.py,sha256=fjDZ-68tUHA6AZcn-p0d32r8X3SyrMME1OyuRPxtI_0,12875
|
|
55
|
+
memvcs/core/merge.py,sha256=eBdPd8loe7G6F8C3fMNdnm_kvlKgZ4JC5z4xnboteOI,19165
|
|
56
|
+
memvcs/core/objects.py,sha256=zlTcNHc3ehFnLm0UoI1Ct2gw5CU4moaRLhN8hZXm3p4,9943
|
|
57
|
+
memvcs/core/pii_scanner.py,sha256=T6gQ1APFrSDk980fjnv4ZMF-UztbJgmUFSwGrwWixEw,10802
|
|
58
|
+
memvcs/core/refs.py,sha256=4Nx2ZVRa_DzfUZ4O1AwzOHEjoGAEICJKqSd9GxaiD_g,16754
|
|
59
|
+
memvcs/core/remote.py,sha256=MhQTfxpzmH0mAMb7hoQJrTOAoqX0tqZxx1Yq5Q5niS8,10117
|
|
60
|
+
memvcs/core/repository.py,sha256=fu6ZxkF3RY7yV1FHRQ2gVOpxkwJzeffna2sZixd8puI,17894
|
|
61
|
+
memvcs/core/schema.py,sha256=_CrEWCdArc0yDJ04GT7fyvjHqkal7gegdFSsFOjVpBc,15287
|
|
62
|
+
memvcs/core/staging.py,sha256=dptdGi_74lhDkcGqGVU39ZyTkb25j-Rnkz0GWi83W1k,7221
|
|
63
|
+
memvcs/core/temporal_index.py,sha256=OmgfznlScItVf2sML7JOj_WaGtKJZMIsP818YKUlMAw,3554
|
|
64
|
+
memvcs/core/test_runner.py,sha256=7-0jCvji63JRbVfy3LNQWIQ7VL5weulOoG7SY1-YJbw,11496
|
|
65
|
+
memvcs/core/vector_store.py,sha256=JqyiPbznxEkuD1CIna5DKm0PwrlQ4tVARJpt6W0mESE,10599
|
|
66
|
+
memvcs/core/storage/__init__.py,sha256=yJE7bm5G7VlFLpSVFrrTkP4eOyQlWRPfBvEP9T5PW44,1901
|
|
67
|
+
memvcs/core/storage/base.py,sha256=IK4To8Cb-LHv5ltlaQLdB6LE-69euFK3hNqBtMCe7-g,9956
|
|
68
|
+
memvcs/core/storage/gcs.py,sha256=-cWuGw1jkFh-Xig-Abmwr9HGwjW5lWQJuF2xcAR1l78,10632
|
|
69
|
+
memvcs/core/storage/local.py,sha256=JAik9nta6RMe4mD7aMtgdFi8M4iZCeTqiP8pPisaO6U,6028
|
|
70
|
+
memvcs/core/storage/s3.py,sha256=tY5rfz8FfkRRNaHOPX7Wk6yXdBBBhKV0Ju2qnBtHxeU,13814
|
|
71
|
+
memvcs/integrations/__init__.py,sha256=hVtJoFaXt6ErAZwctcSBDZLXRHFs1CNgtltIBQiroQ0,103
|
|
72
|
+
memvcs/integrations/mcp_server.py,sha256=PxBYJnbzPs6bcFH6EmH5jQqbu_9Vy5eSAA8ruWTn2Q4,9061
|
|
73
|
+
memvcs/integrations/web_ui/__init__.py,sha256=MQIfgDKDgPctlcTUjwkwueS_MDsDssVRmIUnpECGS0k,51
|
|
74
|
+
memvcs/integrations/web_ui/server.py,sha256=4roJdX0xI3o-n3jZkOMnRScW4YUwpzE2dYZABDv6Iio,12751
|
|
75
|
+
memvcs/retrieval/__init__.py,sha256=IzzmYbE_hmkCmcwQqIUPca4vQh_tD--cB_l00i6uGxY,465
|
|
76
|
+
memvcs/retrieval/base.py,sha256=aCeWpb2EbSRE81Rn4maLzqPmLSKZOUrwmSSfTEFJ33U,1336
|
|
77
|
+
memvcs/retrieval/pack.py,sha256=4rrGP7oduPhAM9PYnW2_eNm4WpSDnleHEja-fjBtONc,4299
|
|
78
|
+
memvcs/retrieval/recaller.py,sha256=8KY-XjMUz5_vcKf46zI64uk1DEM__u7wM92ShukOtsY,3819
|
|
79
|
+
memvcs/retrieval/strategies.py,sha256=26yxQQubQfjxWQXknfVMxuzPHf2EcZxJg_B99BEdl5c,11458
|
|
80
|
+
memvcs/utils/__init__.py,sha256=8psUzz4Ntv2GzbRebkeVsoyC6Ck-FIwi0_lfYdj5oho,185
|
|
81
|
+
memvcs/utils/helpers.py,sha256=37zg_DcQ2y99b9NSLqxFkglHe13rJXKhFDpEbQ7iLhM,4121
|
|
82
|
+
agmem-0.1.2.dist-info/METADATA,sha256=uIzEeVVPQ36Kdy0NQ0ygJS9pvMSglfYSTo_oNjG5TsM,26608
|
|
83
|
+
agmem-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
84
|
+
agmem-0.1.2.dist-info/entry_points.txt,sha256=at7eWycgjqOo1wbUMECnXUsNo3gpCkJTU71OzrGLHu0,42
|
|
85
|
+
agmem-0.1.2.dist-info/top_level.txt,sha256=HtMMsKuwLKLOdgF1GxqQztqFM54tTJctVdJuOec6B-4,7
|
|
86
|
+
agmem-0.1.2.dist-info/RECORD,,
|
memvcs/__init__.py
CHANGED
memvcs/cli.py
CHANGED
|
@@ -49,6 +49,15 @@ from .commands.fsck import FsckCommand
|
|
|
49
49
|
from .commands.graph import GraphCommand
|
|
50
50
|
from .commands.daemon import DaemonCommand
|
|
51
51
|
from .commands.garden import GardenCommand
|
|
52
|
+
from .commands.recall import RecallCommand
|
|
53
|
+
from .commands.when import WhenCommand
|
|
54
|
+
from .commands.timeline import TimelineCommand
|
|
55
|
+
from .commands.pack import PackCommand
|
|
56
|
+
from .commands.distill import DistillCommand
|
|
57
|
+
from .commands.decay import DecayCommand
|
|
58
|
+
from .commands.resurrect import ResurrectCommand
|
|
59
|
+
from .commands.verify import VerifyCommand
|
|
60
|
+
from .commands.repair import RepairCommand
|
|
52
61
|
|
|
53
62
|
|
|
54
63
|
# List of available commands
|
|
@@ -82,14 +91,23 @@ COMMANDS = [
|
|
|
82
91
|
GraphCommand,
|
|
83
92
|
DaemonCommand,
|
|
84
93
|
GardenCommand,
|
|
94
|
+
RecallCommand,
|
|
95
|
+
WhenCommand,
|
|
96
|
+
TimelineCommand,
|
|
97
|
+
PackCommand,
|
|
98
|
+
DistillCommand,
|
|
99
|
+
DecayCommand,
|
|
100
|
+
ResurrectCommand,
|
|
101
|
+
VerifyCommand,
|
|
102
|
+
RepairCommand,
|
|
85
103
|
]
|
|
86
104
|
|
|
87
105
|
|
|
88
106
|
def create_parser() -> argparse.ArgumentParser:
|
|
89
107
|
"""Create the main argument parser."""
|
|
90
108
|
parser = argparse.ArgumentParser(
|
|
91
|
-
prog=
|
|
92
|
-
description=
|
|
109
|
+
prog="agmem",
|
|
110
|
+
description="agmem - Agentic Memory Version Control System",
|
|
93
111
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
94
112
|
epilog="""
|
|
95
113
|
Examples:
|
|
@@ -110,36 +128,21 @@ Examples:
|
|
|
110
128
|
agmem tree Show directory tree visually
|
|
111
129
|
|
|
112
130
|
For more information: https://github.com/vivek-tiwari-vt/agmem
|
|
113
|
-
"""
|
|
131
|
+
""",
|
|
114
132
|
)
|
|
115
|
-
|
|
116
|
-
parser.add_argument(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
parser.add_argument(
|
|
123
|
-
'--verbose',
|
|
124
|
-
action='store_true',
|
|
125
|
-
help='Enable verbose output'
|
|
126
|
-
)
|
|
127
|
-
|
|
133
|
+
|
|
134
|
+
parser.add_argument("--version", "-v", action="version", version="%(prog)s 0.1.0")
|
|
135
|
+
|
|
136
|
+
parser.add_argument("--verbose", action="store_true", help="Enable verbose output")
|
|
137
|
+
|
|
128
138
|
# Create subparsers for commands
|
|
129
|
-
subparsers = parser.add_subparsers(
|
|
130
|
-
|
|
131
|
-
help='Available commands',
|
|
132
|
-
metavar='COMMAND'
|
|
133
|
-
)
|
|
134
|
-
|
|
139
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands", metavar="COMMAND")
|
|
140
|
+
|
|
135
141
|
# Add each command
|
|
136
142
|
for cmd_class in COMMANDS:
|
|
137
|
-
cmd_parser = subparsers.add_parser(
|
|
138
|
-
cmd_class.name,
|
|
139
|
-
help=cmd_class.help
|
|
140
|
-
)
|
|
143
|
+
cmd_parser = subparsers.add_parser(cmd_class.name, help=cmd_class.help)
|
|
141
144
|
cmd_class.add_arguments(cmd_parser)
|
|
142
|
-
|
|
145
|
+
|
|
143
146
|
return parser
|
|
144
147
|
|
|
145
148
|
|
|
@@ -147,12 +150,12 @@ def main(args: List[str] = None) -> int:
|
|
|
147
150
|
"""Main entry point."""
|
|
148
151
|
parser = create_parser()
|
|
149
152
|
parsed_args = parser.parse_args(args)
|
|
150
|
-
|
|
153
|
+
|
|
151
154
|
# No command specified
|
|
152
155
|
if not parsed_args.command:
|
|
153
156
|
parser.print_help()
|
|
154
157
|
return 0
|
|
155
|
-
|
|
158
|
+
|
|
156
159
|
# Find and execute the command
|
|
157
160
|
for cmd_class in COMMANDS:
|
|
158
161
|
if cmd_class.name == parsed_args.command:
|
|
@@ -164,15 +167,16 @@ def main(args: List[str] = None) -> int:
|
|
|
164
167
|
except Exception as e:
|
|
165
168
|
if parsed_args.verbose:
|
|
166
169
|
import traceback
|
|
170
|
+
|
|
167
171
|
traceback.print_exc()
|
|
168
172
|
else:
|
|
169
173
|
print(f"Error: {e}")
|
|
170
174
|
return 1
|
|
171
|
-
|
|
175
|
+
|
|
172
176
|
# Unknown command
|
|
173
177
|
print(f"Unknown command: {parsed_args.command}")
|
|
174
178
|
return 1
|
|
175
179
|
|
|
176
180
|
|
|
177
|
-
if __name__ ==
|
|
181
|
+
if __name__ == "__main__":
|
|
178
182
|
sys.exit(main())
|
memvcs/commands/__init__.py
CHANGED
|
@@ -11,13 +11,13 @@ from .merge import MergeCommand
|
|
|
11
11
|
from .diff import DiffCommand
|
|
12
12
|
|
|
13
13
|
__all__ = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
"InitCommand",
|
|
15
|
+
"AddCommand",
|
|
16
|
+
"CommitCommand",
|
|
17
|
+
"StatusCommand",
|
|
18
|
+
"LogCommand",
|
|
19
|
+
"BranchCommand",
|
|
20
|
+
"CheckoutCommand",
|
|
21
|
+
"MergeCommand",
|
|
22
|
+
"DiffCommand",
|
|
23
23
|
]
|
memvcs/commands/add.py
CHANGED
|
@@ -10,84 +10,82 @@ from ..core.repository import Repository
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
# Default allowed file extensions for memory files
|
|
13
|
-
DEFAULT_ALLOWED_EXTENSIONS = {
|
|
13
|
+
DEFAULT_ALLOWED_EXTENSIONS = {".md", ".txt", ".json", ".yaml", ".yml"}
|
|
14
14
|
|
|
15
15
|
# Binary file signatures (magic bytes) to detect binary files
|
|
16
16
|
BINARY_SIGNATURES = [
|
|
17
|
-
b
|
|
18
|
-
b
|
|
19
|
-
b
|
|
20
|
-
b
|
|
21
|
-
b
|
|
22
|
-
b
|
|
23
|
-
b
|
|
24
|
-
b
|
|
25
|
-
b
|
|
17
|
+
b"\x89PNG", # PNG
|
|
18
|
+
b"\xff\xd8\xff", # JPEG
|
|
19
|
+
b"GIF8", # GIF
|
|
20
|
+
b"%PDF", # PDF
|
|
21
|
+
b"PK\x03\x04", # ZIP
|
|
22
|
+
b"\x1f\x8b", # GZIP
|
|
23
|
+
b"BM", # BMP
|
|
24
|
+
b"\x00\x00\x01\x00", # ICO
|
|
25
|
+
b"RIFF", # WAV, AVI, etc.
|
|
26
26
|
]
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class AddCommand:
|
|
30
30
|
"""Add files to the staging area."""
|
|
31
|
-
|
|
32
|
-
name =
|
|
33
|
-
help =
|
|
34
|
-
|
|
31
|
+
|
|
32
|
+
name = "add"
|
|
33
|
+
help = "Add memory files to staging area"
|
|
34
|
+
|
|
35
35
|
@staticmethod
|
|
36
36
|
def add_arguments(parser: argparse.ArgumentParser):
|
|
37
|
+
parser.add_argument("paths", nargs="+", help="Files or directories to stage")
|
|
37
38
|
parser.add_argument(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
"--all",
|
|
40
|
+
"-A",
|
|
41
|
+
action="store_true",
|
|
42
|
+
help="Stage all changes (including modifications and deletions)",
|
|
41
43
|
)
|
|
42
44
|
parser.add_argument(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
"--force",
|
|
46
|
+
"-f",
|
|
47
|
+
action="store_true",
|
|
48
|
+
help="Force add even if file type is not recommended",
|
|
46
49
|
)
|
|
47
50
|
parser.add_argument(
|
|
48
|
-
|
|
49
|
-
action=
|
|
50
|
-
help=
|
|
51
|
+
"--allow-binary",
|
|
52
|
+
action="store_true",
|
|
53
|
+
help="Allow staging binary files (not recommended)",
|
|
51
54
|
)
|
|
52
|
-
|
|
53
|
-
'--allow-binary',
|
|
54
|
-
action='store_true',
|
|
55
|
-
help='Allow staging binary files (not recommended)'
|
|
56
|
-
)
|
|
57
|
-
|
|
55
|
+
|
|
58
56
|
@staticmethod
|
|
59
57
|
def _is_binary_file(filepath: Path) -> bool:
|
|
60
58
|
"""Check if a file is binary by looking at magic bytes."""
|
|
61
59
|
try:
|
|
62
|
-
with open(filepath,
|
|
60
|
+
with open(filepath, "rb") as f:
|
|
63
61
|
header = f.read(16)
|
|
64
|
-
|
|
62
|
+
|
|
65
63
|
for signature in BINARY_SIGNATURES:
|
|
66
64
|
if header.startswith(signature):
|
|
67
65
|
return True
|
|
68
|
-
|
|
66
|
+
|
|
69
67
|
# Also check for null bytes (common in binary files)
|
|
70
|
-
if b
|
|
68
|
+
if b"\x00" in header:
|
|
71
69
|
return True
|
|
72
|
-
|
|
70
|
+
|
|
73
71
|
return False
|
|
74
72
|
except Exception:
|
|
75
73
|
return False
|
|
76
|
-
|
|
74
|
+
|
|
77
75
|
@staticmethod
|
|
78
76
|
def _is_allowed_extension(filepath: Path, config: dict) -> bool:
|
|
79
77
|
"""Check if file extension is in allowed list."""
|
|
80
|
-
allowed = config.get(
|
|
78
|
+
allowed = config.get("allowed_extensions", list(DEFAULT_ALLOWED_EXTENSIONS))
|
|
81
79
|
allowed_set = set(allowed)
|
|
82
|
-
|
|
80
|
+
|
|
83
81
|
ext = filepath.suffix.lower()
|
|
84
82
|
return ext in allowed_set or not ext # Allow files without extension
|
|
85
|
-
|
|
83
|
+
|
|
86
84
|
@staticmethod
|
|
87
85
|
def _validate_file(filepath: Path, config: dict, force: bool, allow_binary: bool) -> tuple:
|
|
88
86
|
"""
|
|
89
87
|
Validate a file for staging.
|
|
90
|
-
|
|
88
|
+
|
|
91
89
|
Returns:
|
|
92
90
|
Tuple of (is_valid, warning_message)
|
|
93
91
|
"""
|
|
@@ -96,13 +94,16 @@ class AddCommand:
|
|
|
96
94
|
if allow_binary:
|
|
97
95
|
return True, f"Warning: {filepath} appears to be binary"
|
|
98
96
|
else:
|
|
99
|
-
return
|
|
100
|
-
|
|
97
|
+
return (
|
|
98
|
+
False,
|
|
99
|
+
f"Rejected: {filepath} is a binary file. Use --allow-binary to override.",
|
|
100
|
+
)
|
|
101
|
+
|
|
101
102
|
# Check extension
|
|
102
103
|
if not AddCommand._is_allowed_extension(filepath, config):
|
|
103
|
-
ext = filepath.suffix or
|
|
104
|
-
allowed = config.get(
|
|
105
|
-
|
|
104
|
+
ext = filepath.suffix or "(no extension)"
|
|
105
|
+
allowed = config.get("allowed_extensions", list(DEFAULT_ALLOWED_EXTENSIONS))
|
|
106
|
+
|
|
106
107
|
if force:
|
|
107
108
|
return True, f"Warning: {filepath} has extension '{ext}' which may not be optimal"
|
|
108
109
|
else:
|
|
@@ -111,9 +112,9 @@ class AddCommand:
|
|
|
111
112
|
f" Recommended: {', '.join(sorted(allowed))}\n"
|
|
112
113
|
f" Use --force to override."
|
|
113
114
|
)
|
|
114
|
-
|
|
115
|
+
|
|
115
116
|
return True, None
|
|
116
|
-
|
|
117
|
+
|
|
117
118
|
@staticmethod
|
|
118
119
|
def execute(args) -> int:
|
|
119
120
|
repo, code = require_repo()
|
|
@@ -123,19 +124,19 @@ class AddCommand:
|
|
|
123
124
|
staged_count = 0
|
|
124
125
|
rejected_count = 0
|
|
125
126
|
config = repo.get_config()
|
|
126
|
-
|
|
127
|
+
|
|
127
128
|
for path_str in args.paths:
|
|
128
129
|
path = Path(path_str)
|
|
129
|
-
|
|
130
|
+
|
|
130
131
|
# Handle '.' to stage all
|
|
131
|
-
if path_str ==
|
|
132
|
+
if path_str == ".":
|
|
132
133
|
staged, rejected = AddCommand._stage_directory_with_validation(
|
|
133
134
|
repo, None, config, args.force, args.allow_binary
|
|
134
135
|
)
|
|
135
136
|
staged_count += staged
|
|
136
137
|
rejected_count += rejected
|
|
137
138
|
continue
|
|
138
|
-
|
|
139
|
+
|
|
139
140
|
# Resolve path relative to current/
|
|
140
141
|
if path.is_absolute():
|
|
141
142
|
try:
|
|
@@ -156,41 +157,41 @@ class AddCommand:
|
|
|
156
157
|
else:
|
|
157
158
|
print(f"Error: Path not found: {path}")
|
|
158
159
|
continue
|
|
159
|
-
|
|
160
|
+
|
|
160
161
|
full_path = repo.current_dir / rel_path
|
|
161
|
-
|
|
162
|
+
|
|
162
163
|
if not full_path.exists():
|
|
163
164
|
print(f"Error: Path not found: {path}")
|
|
164
165
|
continue
|
|
165
|
-
|
|
166
|
+
|
|
166
167
|
if full_path.is_file():
|
|
167
168
|
# Validate file
|
|
168
169
|
is_valid, message = AddCommand._validate_file(
|
|
169
170
|
full_path, config, args.force, args.allow_binary
|
|
170
171
|
)
|
|
171
|
-
|
|
172
|
+
|
|
172
173
|
if not is_valid:
|
|
173
174
|
print(message)
|
|
174
175
|
rejected_count += 1
|
|
175
176
|
continue
|
|
176
|
-
|
|
177
|
+
|
|
177
178
|
if message: # Warning
|
|
178
179
|
print(message)
|
|
179
|
-
|
|
180
|
+
|
|
180
181
|
try:
|
|
181
182
|
blob_hash = repo.stage_file(str(rel_path))
|
|
182
183
|
print(f" staged: {rel_path}")
|
|
183
184
|
staged_count += 1
|
|
184
185
|
except Exception as e:
|
|
185
186
|
print(f"Error staging {rel_path}: {e}")
|
|
186
|
-
|
|
187
|
+
|
|
187
188
|
elif full_path.is_dir():
|
|
188
189
|
staged, rejected = AddCommand._stage_directory_with_validation(
|
|
189
190
|
repo, str(rel_path), config, args.force, args.allow_binary
|
|
190
191
|
)
|
|
191
192
|
staged_count += staged
|
|
192
193
|
rejected_count += rejected
|
|
193
|
-
|
|
194
|
+
|
|
194
195
|
if staged_count > 0 or rejected_count > 0:
|
|
195
196
|
print(f"\nStaged {staged_count} file(s)")
|
|
196
197
|
if rejected_count > 0:
|
|
@@ -199,42 +200,42 @@ class AddCommand:
|
|
|
199
200
|
print("Run 'agmem commit -m \"message\"' to save snapshot")
|
|
200
201
|
else:
|
|
201
202
|
print("No files staged")
|
|
202
|
-
|
|
203
|
+
|
|
203
204
|
return 0
|
|
204
|
-
|
|
205
|
+
|
|
205
206
|
@staticmethod
|
|
206
|
-
def _stage_directory_with_validation(
|
|
207
|
+
def _stage_directory_with_validation(
|
|
208
|
+
repo, subdir: str, config: dict, force: bool, allow_binary: bool
|
|
209
|
+
) -> tuple:
|
|
207
210
|
"""
|
|
208
211
|
Stage a directory with file validation.
|
|
209
|
-
|
|
212
|
+
|
|
210
213
|
Returns:
|
|
211
214
|
Tuple of (staged_count, rejected_count)
|
|
212
215
|
"""
|
|
213
216
|
staged_count = 0
|
|
214
217
|
rejected_count = 0
|
|
215
|
-
|
|
218
|
+
|
|
216
219
|
if subdir:
|
|
217
220
|
dir_path = repo.current_dir / subdir
|
|
218
221
|
else:
|
|
219
222
|
dir_path = repo.current_dir
|
|
220
|
-
|
|
223
|
+
|
|
221
224
|
if not dir_path.exists():
|
|
222
225
|
return 0, 0
|
|
223
|
-
|
|
224
|
-
for file_path in dir_path.rglob(
|
|
226
|
+
|
|
227
|
+
for file_path in dir_path.rglob("*"):
|
|
225
228
|
if not file_path.is_file():
|
|
226
229
|
continue
|
|
227
|
-
|
|
230
|
+
|
|
228
231
|
# Skip hidden files and .mem directory
|
|
229
232
|
rel_to_current = file_path.relative_to(repo.current_dir)
|
|
230
|
-
if any(part.startswith(
|
|
233
|
+
if any(part.startswith(".") for part in rel_to_current.parts):
|
|
231
234
|
continue
|
|
232
|
-
|
|
235
|
+
|
|
233
236
|
# Validate file
|
|
234
|
-
is_valid, message = AddCommand._validate_file(
|
|
235
|
-
|
|
236
|
-
)
|
|
237
|
-
|
|
237
|
+
is_valid, message = AddCommand._validate_file(file_path, config, force, allow_binary)
|
|
238
|
+
|
|
238
239
|
if not is_valid:
|
|
239
240
|
if not force:
|
|
240
241
|
# Only print first few rejections to avoid spam
|
|
@@ -244,15 +245,15 @@ class AddCommand:
|
|
|
244
245
|
print(" ... (more files rejected)")
|
|
245
246
|
rejected_count += 1
|
|
246
247
|
continue
|
|
247
|
-
|
|
248
|
+
|
|
248
249
|
if message: # Warning
|
|
249
250
|
print(message)
|
|
250
|
-
|
|
251
|
+
|
|
251
252
|
try:
|
|
252
253
|
repo.stage_file(str(rel_to_current))
|
|
253
254
|
print(f" staged: {rel_to_current}")
|
|
254
255
|
staged_count += 1
|
|
255
256
|
except Exception as e:
|
|
256
257
|
print(f"Error staging {rel_to_current}: {e}")
|
|
257
|
-
|
|
258
|
+
|
|
258
259
|
return staged_count, rejected_count
|