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.
@@ -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,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ memorysync = memorysync_cli.main:run
3
+ msync = memorysync_cli.main:run
@@ -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.