memorysync-cli 1.0.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.
- memorysync_cli/__init__.py +13 -0
- memorysync_cli/__main__.py +9 -0
- memorysync_cli/_version.py +1 -0
- memorysync_cli/args.py +220 -0
- memorysync_cli/commands/__init__.py +6 -0
- memorysync_cli/commands/admin.py +354 -0
- memorysync_cli/commands/init.py +109 -0
- memorysync_cli/commands/memory.py +629 -0
- memorysync_cli/commands/source.py +132 -0
- memorysync_cli/commands/tooling.py +238 -0
- memorysync_cli/completions.py +150 -0
- memorysync_cli/config.py +147 -0
- memorysync_cli/credentials.py +259 -0
- memorysync_cli/errors.py +110 -0
- memorysync_cli/http.py +257 -0
- memorysync_cli/main.py +325 -0
- memorysync_cli/output.py +311 -0
- memorysync_cli/registry.json +612 -0
- memorysync_cli/registry.py +101 -0
- memorysync_cli-1.0.2.dist-info/METADATA +158 -0
- memorysync_cli-1.0.2.dist-info/RECORD +24 -0
- memorysync_cli-1.0.2.dist-info/WHEEL +4 -0
- memorysync_cli-1.0.2.dist-info/entry_points.txt +3 -0
- memorysync_cli-1.0.2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""The command tree, loaded from the Node CLI's registry.
|
|
2
|
+
|
|
3
|
+
There is no second copy of the command surface here, on purpose.
|
|
4
|
+
|
|
5
|
+
``registry.json`` is generated by ``sdk/cli/scripts/dump-registry.mjs`` from the
|
|
6
|
+
same ``commandTree()`` the Node CLI serves for ``help --json``. Both CLIs
|
|
7
|
+
therefore describe themselves from one declaration, and ``help --json`` is
|
|
8
|
+
identical between them by construction rather than by review.
|
|
9
|
+
|
|
10
|
+
That decision comes from watching the only competitor who ships two CLIs try the
|
|
11
|
+
other way. Mem0's documentation promises the npm and Python packages "provide
|
|
12
|
+
identical behavior: same commands, same options, same output formats". In
|
|
13
|
+
practice their Python CLI answers ``help --json`` with twelve commands and their
|
|
14
|
+
Node CLI answers with a name, a version and a description - no commands at all -
|
|
15
|
+
while the two packages sit on different version numbers. Hand-maintained parity
|
|
16
|
+
across two languages does not survive contact with a release schedule.
|
|
17
|
+
|
|
18
|
+
What this file does not guarantee is that the Python commands *behave* the same.
|
|
19
|
+
A shared registry keeps the description honest; the parity tests check that every
|
|
20
|
+
declared flag is actually accepted.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
from functools import lru_cache
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Any
|
|
29
|
+
|
|
30
|
+
_REGISTRY_PATH = Path(__file__).with_name("registry.json")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@lru_cache(maxsize=1)
|
|
34
|
+
def load() -> dict[str, Any]:
|
|
35
|
+
"""The whole generated tree.
|
|
36
|
+
|
|
37
|
+
Cached because the dispatcher, the help renderer and the completion writer all
|
|
38
|
+
ask for it, and re-reading a file for each would be a needless startup cost in
|
|
39
|
+
a tool that is expected to feel instant.
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
with _REGISTRY_PATH.open(encoding="utf-8") as handle:
|
|
43
|
+
return json.load(handle)
|
|
44
|
+
except FileNotFoundError: # pragma: no cover - packaging failure
|
|
45
|
+
raise RuntimeError(
|
|
46
|
+
"registry.json is missing from the installed package. "
|
|
47
|
+
"It is generated from the Node CLI by sdk/cli/scripts/dump-registry.mjs."
|
|
48
|
+
) from None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def command_tree() -> dict[str, Any]:
|
|
52
|
+
"""The payload ``help --json`` prints, minus the parts that are ours alone."""
|
|
53
|
+
tree = dict(load())
|
|
54
|
+
tree.pop("exit_codes", None)
|
|
55
|
+
return tree
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@lru_cache(maxsize=1)
|
|
59
|
+
def commands() -> dict[str, dict[str, Any]]:
|
|
60
|
+
"""Commands keyed by name, for dispatch and help lookup."""
|
|
61
|
+
return {entry["name"]: entry for entry in load()["commands"]}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@lru_cache(maxsize=1)
|
|
65
|
+
def global_flags() -> list[dict[str, Any]]:
|
|
66
|
+
return list(load()["global_flags"])
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@lru_cache(maxsize=1)
|
|
70
|
+
def formats() -> list[str]:
|
|
71
|
+
return list(load()["output_formats"])
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@lru_cache(maxsize=1)
|
|
75
|
+
def exit_codes() -> dict[str, int]:
|
|
76
|
+
return dict(load()["exit_codes"])
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def subcommands(name: str) -> dict[str, dict[str, Any]]:
|
|
80
|
+
"""Subcommands of one command, keyed by name. Empty when it has none."""
|
|
81
|
+
spec = commands().get(name) or {}
|
|
82
|
+
return {entry["name"]: entry for entry in spec.get("subcommands", [])}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def flags_for(name: str, sub: str | None = None) -> list[dict[str, Any]]:
|
|
86
|
+
"""Declared flags for a command, or for one of its subcommands.
|
|
87
|
+
|
|
88
|
+
Subcommands inherit the parent's flags: ``project list --output json`` has to
|
|
89
|
+
work, and the registry only declares ``--output`` once, on the parent.
|
|
90
|
+
"""
|
|
91
|
+
spec = commands().get(name)
|
|
92
|
+
if spec is None:
|
|
93
|
+
return []
|
|
94
|
+
|
|
95
|
+
declared = list(spec.get("flags", []))
|
|
96
|
+
if sub is not None:
|
|
97
|
+
for entry in spec.get("subcommands", []):
|
|
98
|
+
if entry["name"] == sub:
|
|
99
|
+
declared.extend(entry.get("flags", []))
|
|
100
|
+
break
|
|
101
|
+
return declared
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: memorysync-cli
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: MemorySync from your terminal. Zero dependencies.
|
|
5
|
+
Project-URL: Documentation, https://docs.memorysync.io/cli
|
|
6
|
+
Project-URL: Homepage, https://memorysync.io/cli
|
|
7
|
+
Author: MemorySync
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent-memory,ai-agents,cli,llm,long-term-memory,memory,memorysync,terminal
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# memorysync-cli (Python)
|
|
27
|
+
|
|
28
|
+
MemorySync from your terminal. Zero dependencies.
|
|
29
|
+
|
|
30
|
+
The same CLI as the npm package `memorysync-cli`, implemented in Python. Same 21
|
|
31
|
+
commands, same flags, same output formats, same exit codes. The two are
|
|
32
|
+
interchangeable, so you only need one.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pipx install memorysync-cli
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`pipx` is recommended because this is an application rather than a library. `pip
|
|
39
|
+
install` works too, but outside a virtual environment it fails on
|
|
40
|
+
externally-managed Pythons — Homebrew and most Linux distributions — with
|
|
41
|
+
`externally-managed-environment` ([PEP 668](https://peps.python.org/pep-0668/)).
|
|
42
|
+
|
|
43
|
+
Requires Python 3.9 or newer.
|
|
44
|
+
|
|
45
|
+
## Getting started
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
memorysync init # store a key, pick a default user
|
|
49
|
+
memorysync add "Prefers pnpm" --user alice
|
|
50
|
+
memorysync search "package manager" --user alice
|
|
51
|
+
memorysync quota # how much of the plan is left
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Both `memorysync` and `msync` are installed; `msync` is just shorter.
|
|
55
|
+
|
|
56
|
+
## Parity is enforced, not promised
|
|
57
|
+
|
|
58
|
+
Both CLIs read one generated command tree, so `help --json` is byte-identical
|
|
59
|
+
between them. The test suite runs both and compares stdout for every offline
|
|
60
|
+
command, including all four completion scripts, and compares exit codes for each
|
|
61
|
+
failure mode. A command added to one and not the other fails the build.
|
|
62
|
+
|
|
63
|
+
That matters because the alternative does not hold. Mem0 ships a Node and a Python
|
|
64
|
+
CLI and documents them as identical; their Python CLI answers `help --json` with
|
|
65
|
+
twelve commands while their Node CLI answers with a name, a version and a
|
|
66
|
+
description and no commands at all, and the two sit on different versions.
|
|
67
|
+
|
|
68
|
+
## Zero dependencies
|
|
69
|
+
|
|
70
|
+
`argparse`, `urllib.request` and `json` cover everything. Mem0's Python CLI depends
|
|
71
|
+
on httpx, rich and typer.
|
|
72
|
+
|
|
73
|
+
Every dependency is code on a customer's machine that they cannot audit on our
|
|
74
|
+
behalf, which matters more for a closed-source tool because nobody else is reading
|
|
75
|
+
our lockfile. A table and eight colours do not justify it.
|
|
76
|
+
|
|
77
|
+
## Agent mode
|
|
78
|
+
|
|
79
|
+
Pass `--json` (or `--agent`) before the command for one JSON envelope, no colour,
|
|
80
|
+
no spinners, errors as JSON with a non-zero exit:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
memorysync --json search "preferences" --user alice
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`data` is always a list, for every command. An agent parses one shape rather than
|
|
87
|
+
remembering which commands return an object.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
memorysync help --json # the whole command tree, for self-discovery
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Exit codes
|
|
94
|
+
|
|
95
|
+
A script can branch on the cause rather than parsing prose.
|
|
96
|
+
|
|
97
|
+
| Code | Meaning |
|
|
98
|
+
|------|---------|
|
|
99
|
+
| 0 | Success |
|
|
100
|
+
| 1 | Unclassified failure |
|
|
101
|
+
| 2 | Usage: unknown command, bad flag, bad value |
|
|
102
|
+
| 3 | Auth: missing, expired or revoked credentials |
|
|
103
|
+
| 4 | Quota: a plan limit is reached |
|
|
104
|
+
| 5 | Network: unreachable or timed out |
|
|
105
|
+
| 6 | Not found |
|
|
106
|
+
| 130 | Interrupted |
|
|
107
|
+
|
|
108
|
+
Code 4 earns its place. Over a plan limit the API returns success with an empty
|
|
109
|
+
result rather than an error, deliberately, so an assistant never narrates billing
|
|
110
|
+
state to an end user. From a terminal that silence is unhelpful, so the CLI reads
|
|
111
|
+
usage and turns it into a distinct code — otherwise an exhausted plan is
|
|
112
|
+
indistinguishable from an empty database.
|
|
113
|
+
|
|
114
|
+
## Where your key is stored
|
|
115
|
+
|
|
116
|
+
Never in the config file. In order: `MEMORYSYNC_API_KEY`, then the OS keychain,
|
|
117
|
+
then an owner-only encrypted file.
|
|
118
|
+
|
|
119
|
+
| Platform | Storage |
|
|
120
|
+
|---|---|
|
|
121
|
+
| macOS | Keychain, via `security` |
|
|
122
|
+
| Linux | Keyring, via `secret-tool`, when libsecret is present |
|
|
123
|
+
| Windows | Owner-only encrypted file |
|
|
124
|
+
|
|
125
|
+
Windows has no scriptable Credential Manager path that avoids a dependency, so it
|
|
126
|
+
uses the file tier. That is the same on the Node CLI. The file is `0600` and its
|
|
127
|
+
contents are tied to the machine and user, which stops a casual `cat` or a backup
|
|
128
|
+
scraper; anyone who can already run code as you can read it. The keychain is
|
|
129
|
+
better, which is why it is tried first.
|
|
130
|
+
|
|
131
|
+
## Deleting
|
|
132
|
+
|
|
133
|
+
`delete` is two-step by default: without `--yes` it previews and changes nothing.
|
|
134
|
+
|
|
135
|
+
`delete --all` clears that one end user's memories and nothing else. No form of any
|
|
136
|
+
command can delete an account, a project or an API key.
|
|
137
|
+
|
|
138
|
+
To clear every memory for an end user through the API directly, use a wide filter
|
|
139
|
+
on `DELETE /memory/forget`, for example `{"before": "<now>"}`. Not
|
|
140
|
+
`/memory/user/purge`: despite its path it is not end-user scoped and erases the
|
|
141
|
+
account behind the credential.
|
|
142
|
+
|
|
143
|
+
## Environment variables
|
|
144
|
+
|
|
145
|
+
| Variable | Purpose |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `MEMORYSYNC_API_KEY` | Key, highest priority |
|
|
148
|
+
| `MEMORYSYNC_BASE_URL` | API base URL |
|
|
149
|
+
| `MEMORYSYNC_USER` | Default end user |
|
|
150
|
+
| `MEMORYSYNC_PROJECT` | Default project |
|
|
151
|
+
| `MEMORYSYNC_PROFILE` | Named profile |
|
|
152
|
+
| `MEMORYSYNC_OUTPUT` | Default output format |
|
|
153
|
+
| `MEMORYSYNC_CONFIG_DIR` | Where config and credentials live |
|
|
154
|
+
| `NO_COLOR` | Disable colour |
|
|
155
|
+
|
|
156
|
+
## Documentation
|
|
157
|
+
|
|
158
|
+
<https://docs.memorysync.io/cli>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
memorysync_cli/__init__.py,sha256=rIo2gmWpCD0Mr4IaRQkdlfeQ8epfMDQJuV1wAu_KssY,503
|
|
2
|
+
memorysync_cli/__main__.py,sha256=EUWNiTcTB3QGHWPXzOkBcHOjz8zEWWRiSgxkZEH78nM,257
|
|
3
|
+
memorysync_cli/_version.py,sha256=LZTFaiDdXahAtu6Prb5WEPk4QX_pfMd7zDoNQSzcGsI,23
|
|
4
|
+
memorysync_cli/args.py,sha256=vZD3HgBUHg8eDQ_uSk9ijDwoFDBAd1y72HKlqP6Oj-c,7355
|
|
5
|
+
memorysync_cli/completions.py,sha256=h7vxXva-4uvk3mC2aVQpOoYtMkzB4-RiNRAGrH7s5DU,5129
|
|
6
|
+
memorysync_cli/config.py,sha256=Y8uyBmtN9X5tbHNMVLjpVm6jjIcwNPbDq4T28yG-38E,4868
|
|
7
|
+
memorysync_cli/credentials.py,sha256=wn_VCAS2UQfoLoeOPkmMZpzB12GG-u3cWp9J4H-yAQI,8773
|
|
8
|
+
memorysync_cli/errors.py,sha256=pCwR-_LBFQvkVWn9gIGd1mR0i_vSJgUcOxcEg3YN9Hg,3812
|
|
9
|
+
memorysync_cli/http.py,sha256=O0ijJp4UO7lRM2gegRnbxapYRD7ArU0AxULrnOY0S5Y,10125
|
|
10
|
+
memorysync_cli/main.py,sha256=zZCR45FoKPO7UPtoQzlVS9xUhSjNQ4-pcVeHfdLdAP8,11544
|
|
11
|
+
memorysync_cli/output.py,sha256=pOKlv1LqDfrkuLsl2nsTgylLvajyh-nNNqD7NCSJimQ,9751
|
|
12
|
+
memorysync_cli/registry.py,sha256=DqyQlqWnPEahpd3ar4WR67xxR3Idm618P2TR13ateZA,3723
|
|
13
|
+
memorysync_cli/commands/__init__.py,sha256=M0dK8dCV4ZA2oiOaygx3MTxT8D9GEAaH6hghXkKuTyA,321
|
|
14
|
+
memorysync_cli/commands/admin.py,sha256=EHdgIbpKL5LWZokYp2ERLuao79FXtb02WwzGHoCbXL8,12716
|
|
15
|
+
memorysync_cli/commands/init.py,sha256=_a5Cvd0NZgC8tybMQe7nx-28yB51m3WJbPLvrFDvJ_A,3993
|
|
16
|
+
memorysync_cli/commands/memory.py,sha256=VuDqHhgI7qDHVIXZytWLGfZj-fwfZfR3oegEQnoiq4g,24141
|
|
17
|
+
memorysync_cli/commands/source.py,sha256=RPQ3Zs5FVhbiQNzTKQXEFcnsELQVUZQB4ejoqEIU_hA,4865
|
|
18
|
+
memorysync_cli/commands/tooling.py,sha256=aBCE0mqbAoIx3YMbwDSdaDDw_6aliKbGSc8Ht2aUuT8,9117
|
|
19
|
+
memorysync_cli/registry.json,sha256=9zCclXXjLlJm30-pMpXkdCeZKaAX3ZaBXuhqKaYxQMo,18588
|
|
20
|
+
memorysync_cli-1.0.2.dist-info/METADATA,sha256=5s1D5d9tLd6FIidJtpPFUmjoRpUWXRaxt42XpbtrPns,5833
|
|
21
|
+
memorysync_cli-1.0.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
22
|
+
memorysync_cli-1.0.2.dist-info/entry_points.txt,sha256=kcdyOYwO3rCrg1-fFBRhSZJ672zYIyAatnFPrmMMqR8,87
|
|
23
|
+
memorysync_cli-1.0.2.dist-info/licenses/LICENSE,sha256=Q3_7utsuE0ra7B7SvEUYhdEEdNnYceaffKzQg10k7WE,1088
|
|
24
|
+
memorysync_cli-1.0.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MemorySync
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|