auxly-cli 1.0.21__tar.gz
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.
- auxly_cli-1.0.21/PKG-INFO +42 -0
- auxly_cli-1.0.21/README.md +28 -0
- auxly_cli-1.0.21/auxly_cli/__init__.py +5 -0
- auxly_cli-1.0.21/auxly_cli/_runner.py +118 -0
- auxly_cli-1.0.21/auxly_cli/_verify.py +93 -0
- auxly_cli-1.0.21/auxly_cli.egg-info/PKG-INFO +42 -0
- auxly_cli-1.0.21/auxly_cli.egg-info/SOURCES.txt +11 -0
- auxly_cli-1.0.21/auxly_cli.egg-info/dependency_links.txt +1 -0
- auxly_cli-1.0.21/auxly_cli.egg-info/entry_points.txt +2 -0
- auxly_cli-1.0.21/auxly_cli.egg-info/requires.txt +1 -0
- auxly_cli-1.0.21/auxly_cli.egg-info/top_level.txt +1 -0
- auxly_cli-1.0.21/pyproject.toml +25 -0
- auxly_cli-1.0.21/setup.cfg +4 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: auxly-cli
|
|
3
|
+
Version: 1.0.21
|
|
4
|
+
Summary: Local-first unified memory system for AI agents — downloads the signature-verified auxly binary.
|
|
5
|
+
Author-email: "Tzamun Arabia IT Co." <hi@auxly.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://auxly.io
|
|
8
|
+
Project-URL: Repository, https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli
|
|
9
|
+
Project-URL: Issues, https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli/issues
|
|
10
|
+
Keywords: auxly,ai,memory,mcp,cli,agents
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: cryptography>=3.4
|
|
14
|
+
|
|
15
|
+
# auxly-cli
|
|
16
|
+
|
|
17
|
+
Local-first unified memory system for AI agents. This package installs a thin
|
|
18
|
+
launcher that downloads the prebuilt [`auxly`](https://auxly.io) binary for your
|
|
19
|
+
platform on first run and verifies it against the project's **minisign-signed**
|
|
20
|
+
checksum manifest.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install auxly-cli
|
|
24
|
+
auxly --help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How it works
|
|
28
|
+
|
|
29
|
+
- `pip install auxly-cli` installs a small pure-Python package (one wheel, all
|
|
30
|
+
platforms).
|
|
31
|
+
- The first time you run `auxly`, it downloads `auxly-<os>-<arch>` from the GitHub
|
|
32
|
+
release matching this package's version, fetches the signed
|
|
33
|
+
`auxly-<version>-checksums.txt` + `.minisig`, verifies the **minisign signature**
|
|
34
|
+
against the pinned public key, checks the binary's **SHA-256** against the signed
|
|
35
|
+
manifest, then caches and execs it. Later runs use the cache.
|
|
36
|
+
|
|
37
|
+
Set `AUXLY_REQUIRE_SIGNATURE=1` to hard-fail if a signed manifest is unavailable.
|
|
38
|
+
The cache lives under `$XDG_CACHE_HOME/auxly` (or `~/.cache/auxly`).
|
|
39
|
+
|
|
40
|
+
Supported: macOS / Linux / Windows on x64 / arm64. Python ≥ 3.8.
|
|
41
|
+
|
|
42
|
+
License: MIT · <https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# auxly-cli
|
|
2
|
+
|
|
3
|
+
Local-first unified memory system for AI agents. This package installs a thin
|
|
4
|
+
launcher that downloads the prebuilt [`auxly`](https://auxly.io) binary for your
|
|
5
|
+
platform on first run and verifies it against the project's **minisign-signed**
|
|
6
|
+
checksum manifest.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install auxly-cli
|
|
10
|
+
auxly --help
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
- `pip install auxly-cli` installs a small pure-Python package (one wheel, all
|
|
16
|
+
platforms).
|
|
17
|
+
- The first time you run `auxly`, it downloads `auxly-<os>-<arch>` from the GitHub
|
|
18
|
+
release matching this package's version, fetches the signed
|
|
19
|
+
`auxly-<version>-checksums.txt` + `.minisig`, verifies the **minisign signature**
|
|
20
|
+
against the pinned public key, checks the binary's **SHA-256** against the signed
|
|
21
|
+
manifest, then caches and execs it. Later runs use the cache.
|
|
22
|
+
|
|
23
|
+
Set `AUXLY_REQUIRE_SIGNATURE=1` to hard-fail if a signed manifest is unavailable.
|
|
24
|
+
The cache lives under `$XDG_CACHE_HOME/auxly` (or `~/.cache/auxly`).
|
|
25
|
+
|
|
26
|
+
Supported: macOS / Linux / Windows on x64 / arm64. Python ≥ 3.8.
|
|
27
|
+
|
|
28
|
+
License: MIT · <https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""auxly console-script entry point.
|
|
2
|
+
|
|
3
|
+
The wheel ships only this thin Python package; the actual auxly binary is
|
|
4
|
+
downloaded + verified on FIRST RUN into a per-user cache, then exec'd. Subsequent
|
|
5
|
+
runs use the cache. This keeps the wheel pure-Python (one wheel, all platforms)
|
|
6
|
+
while still verifying the minisign signature like the native installers do.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import platform
|
|
13
|
+
import stat
|
|
14
|
+
import sys
|
|
15
|
+
import urllib.request
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from ._verify import manifest_has_hash, sha256_hex, verify_minisign
|
|
19
|
+
|
|
20
|
+
REPO = "Tzamun-Arabia-IT-Co/auxly-memory-cli"
|
|
21
|
+
__version__ = "1.0.21"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _target() -> tuple[str, str]:
|
|
25
|
+
sys_map = {"darwin": "darwin", "linux": "linux", "windows": "windows"}
|
|
26
|
+
machine = platform.machine().lower()
|
|
27
|
+
arch_map = {"x86_64": "amd64", "amd64": "amd64", "arm64": "arm64", "aarch64": "arm64"}
|
|
28
|
+
osname = sys_map.get(platform.system().lower())
|
|
29
|
+
arch = arch_map.get(machine)
|
|
30
|
+
if not osname or not arch:
|
|
31
|
+
raise SystemExit(f"auxly: unsupported platform {platform.system()}/{machine}")
|
|
32
|
+
ext = ".exe" if osname == "windows" else ""
|
|
33
|
+
return f"auxly-{osname}-{arch}{ext}", ext
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _cache_dir() -> Path:
|
|
37
|
+
base = os.environ.get("XDG_CACHE_HOME") or os.path.join(Path.home(), ".cache")
|
|
38
|
+
root = Path(base) / "auxly"
|
|
39
|
+
d = root / __version__
|
|
40
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
# Restrict to the owner so another local user can't pre-place / swap the cached
|
|
42
|
+
# binary that we exec (the cached copy is run without re-fetching the manifest).
|
|
43
|
+
for p in (root, d):
|
|
44
|
+
try:
|
|
45
|
+
os.chmod(p, 0o700)
|
|
46
|
+
except OSError:
|
|
47
|
+
pass
|
|
48
|
+
return d
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _fetch(url: str) -> bytes:
|
|
52
|
+
req = urllib.request.Request(url, headers={"User-Agent": "auxly-pip-installer"})
|
|
53
|
+
with urllib.request.urlopen(req) as resp: # nosec - https only, verified below
|
|
54
|
+
return resp.read()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _download_and_verify(dest: Path, bin_name: str) -> None:
|
|
58
|
+
base = f"https://github.com/{REPO}/releases/download/v{__version__}"
|
|
59
|
+
manifest_name = f"auxly-{__version__}-checksums.txt"
|
|
60
|
+
sys.stderr.write(f"auxly: downloading {bin_name} (v{__version__})…\n")
|
|
61
|
+
binary = _fetch(f"{base}/{bin_name}")
|
|
62
|
+
|
|
63
|
+
# Every release this wrapper targets (it is version-locked to a release tag)
|
|
64
|
+
# ships a signed manifest, so verification is REQUIRED by default — a missing or
|
|
65
|
+
# junk manifest aborts rather than running an unverified binary.
|
|
66
|
+
# AUXLY_ALLOW_UNSIGNED=1 relaxes this for emergencies.
|
|
67
|
+
allow_unsigned = os.environ.get("AUXLY_ALLOW_UNSIGNED") == "1"
|
|
68
|
+
try:
|
|
69
|
+
manifest = _fetch(f"{base}/{manifest_name}").decode("utf-8")
|
|
70
|
+
sig = _fetch(f"{base}/{manifest_name}.minisig").decode("utf-8")
|
|
71
|
+
except Exception as e: # noqa: BLE001
|
|
72
|
+
if not allow_unsigned:
|
|
73
|
+
raise SystemExit(
|
|
74
|
+
f"auxly: signed manifest unavailable ({e}) and verification is required "
|
|
75
|
+
"— set AUXLY_ALLOW_UNSIGNED=1 only if you accept an unverified install"
|
|
76
|
+
)
|
|
77
|
+
sys.stderr.write(f"auxly: AUXLY_ALLOW_UNSIGNED=1 — installing unverified ({e})\n")
|
|
78
|
+
manifest = sig = None
|
|
79
|
+
|
|
80
|
+
if manifest and sig:
|
|
81
|
+
import re
|
|
82
|
+
|
|
83
|
+
if not re.search(r"^[0-9a-f]{64}\s+\S", manifest, re.MULTILINE):
|
|
84
|
+
if not allow_unsigned:
|
|
85
|
+
raise SystemExit("auxly: fetched manifest is not a checksums file — refusing")
|
|
86
|
+
sys.stderr.write("auxly: AUXLY_ALLOW_UNSIGNED=1 — manifest not a checksums file; unverified\n")
|
|
87
|
+
else:
|
|
88
|
+
verify_minisign(manifest.encode("utf-8"), sig) # raises on failure
|
|
89
|
+
if not manifest_has_hash(manifest, sha256_hex(binary)):
|
|
90
|
+
raise SystemExit("auxly: binary SHA-256 not in signed manifest — refusing")
|
|
91
|
+
sys.stderr.write("auxly: signature + checksum verified ✔\n")
|
|
92
|
+
|
|
93
|
+
tmp = dest.with_suffix(dest.suffix + ".tmp")
|
|
94
|
+
tmp.write_bytes(binary)
|
|
95
|
+
tmp.chmod(tmp.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
96
|
+
os.replace(tmp, dest)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _binary_path() -> Path:
|
|
100
|
+
bin_name, ext = _target()
|
|
101
|
+
dest = _cache_dir() / f"auxly{ext}"
|
|
102
|
+
if not dest.exists() or dest.stat().st_size == 0:
|
|
103
|
+
_download_and_verify(dest, bin_name)
|
|
104
|
+
return dest
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main() -> None:
|
|
108
|
+
binary = _binary_path()
|
|
109
|
+
args = [str(binary), *sys.argv[1:]]
|
|
110
|
+
if os.name == "nt":
|
|
111
|
+
import subprocess
|
|
112
|
+
|
|
113
|
+
sys.exit(subprocess.run(args).returncode)
|
|
114
|
+
os.execv(str(binary), args) # replace this process on POSIX
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
main()
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Minisign + SHA-256 verification for the auxly pip wrapper.
|
|
2
|
+
|
|
3
|
+
Mirrors npm/lib/verify.js and internal/update/verify.go: the release CI signs the
|
|
4
|
+
checksum manifest with minisign (prehashed "ED" mode = ed25519 over BLAKE2b-512).
|
|
5
|
+
We verify that signature against the PINNED public key, plus the SHA-256 integrity
|
|
6
|
+
of the downloaded binary against the signed manifest.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import base64
|
|
12
|
+
import hashlib
|
|
13
|
+
|
|
14
|
+
from cryptography.exceptions import InvalidSignature
|
|
15
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
|
16
|
+
|
|
17
|
+
# Pinned minisign public key (base64). MUST match internal/update/verify.go.
|
|
18
|
+
PUBKEY_B64 = "RWQfIGHWpXR4MtPvcbWwN1J7mx9FGsCaHMmdIpGMZAKDvmILC2Of5Q/K"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def sha256_hex(data: bytes) -> str:
|
|
22
|
+
return hashlib.sha256(data).hexdigest()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def manifest_has_hash(manifest_text: str, hash_hex: str) -> bool:
|
|
26
|
+
"""True if hash_hex is the first whitespace-delimited field of any line
|
|
27
|
+
(full field match, never a substring)."""
|
|
28
|
+
want = hash_hex.lower()
|
|
29
|
+
for line in manifest_text.splitlines():
|
|
30
|
+
parts = line.strip().split()
|
|
31
|
+
if parts and parts[0].lower() == want:
|
|
32
|
+
return True
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _ed25519_ok(pub_raw: bytes, message: bytes, sig: bytes) -> bool:
|
|
37
|
+
try:
|
|
38
|
+
Ed25519PublicKey.from_public_bytes(pub_raw).verify(sig, message)
|
|
39
|
+
return True
|
|
40
|
+
except InvalidSignature:
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def verify_minisign(file_bytes: bytes, minisig_text: str) -> str:
|
|
45
|
+
"""Verify a minisign signature over file_bytes using the pinned key.
|
|
46
|
+
|
|
47
|
+
Verifies BOTH the file signature and the global (trusted-comment) signature,
|
|
48
|
+
exactly as the minisign CLI does. Raises ValueError on any failure; returns
|
|
49
|
+
the trusted comment on success.
|
|
50
|
+
"""
|
|
51
|
+
pub = base64.b64decode(PUBKEY_B64)
|
|
52
|
+
if len(pub) != 42:
|
|
53
|
+
raise ValueError("pinned public key malformed")
|
|
54
|
+
pub_keyid = pub[2:10]
|
|
55
|
+
pub_raw = pub[10:42]
|
|
56
|
+
|
|
57
|
+
lines = minisig_text.split("\n")
|
|
58
|
+
if len(lines) < 4:
|
|
59
|
+
raise ValueError("minisig truncated")
|
|
60
|
+
|
|
61
|
+
sig_blob = base64.b64decode(lines[1].strip())
|
|
62
|
+
if len(sig_blob) != 74:
|
|
63
|
+
raise ValueError("minisig signature block malformed")
|
|
64
|
+
algo = sig_blob[0:2]
|
|
65
|
+
sig_keyid = sig_blob[2:10]
|
|
66
|
+
sig = sig_blob[10:74]
|
|
67
|
+
if sig_keyid != pub_keyid:
|
|
68
|
+
raise ValueError("minisign key id mismatch")
|
|
69
|
+
|
|
70
|
+
if algo == b"ED":
|
|
71
|
+
message = hashlib.blake2b(file_bytes, digest_size=64).digest() # prehashed
|
|
72
|
+
elif algo == b"Ed":
|
|
73
|
+
message = file_bytes # legacy
|
|
74
|
+
else:
|
|
75
|
+
raise ValueError(f"unsupported minisign algorithm {algo!r}")
|
|
76
|
+
|
|
77
|
+
if not _ed25519_ok(pub_raw, message, sig):
|
|
78
|
+
raise ValueError("minisign file signature is INVALID")
|
|
79
|
+
|
|
80
|
+
# Global signature binds the trusted comment to the signature.
|
|
81
|
+
trusted_line = lines[2]
|
|
82
|
+
global_sig = base64.b64decode(lines[3].strip())
|
|
83
|
+
if len(global_sig) != 64:
|
|
84
|
+
raise ValueError("minisig global signature malformed")
|
|
85
|
+
prefix = "trusted comment:"
|
|
86
|
+
idx = trusted_line.find(prefix)
|
|
87
|
+
trusted_comment = trusted_line[idx + len(prefix):] if idx >= 0 else ""
|
|
88
|
+
if trusted_comment[:1].isspace(): # strip the single separator space
|
|
89
|
+
trusted_comment = trusted_comment[1:]
|
|
90
|
+
global_msg = sig + trusted_comment.encode("utf-8")
|
|
91
|
+
if not _ed25519_ok(pub_raw, global_msg, global_sig):
|
|
92
|
+
raise ValueError("minisign trusted-comment signature is INVALID")
|
|
93
|
+
return trusted_comment
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: auxly-cli
|
|
3
|
+
Version: 1.0.21
|
|
4
|
+
Summary: Local-first unified memory system for AI agents — downloads the signature-verified auxly binary.
|
|
5
|
+
Author-email: "Tzamun Arabia IT Co." <hi@auxly.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://auxly.io
|
|
8
|
+
Project-URL: Repository, https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli
|
|
9
|
+
Project-URL: Issues, https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli/issues
|
|
10
|
+
Keywords: auxly,ai,memory,mcp,cli,agents
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: cryptography>=3.4
|
|
14
|
+
|
|
15
|
+
# auxly-cli
|
|
16
|
+
|
|
17
|
+
Local-first unified memory system for AI agents. This package installs a thin
|
|
18
|
+
launcher that downloads the prebuilt [`auxly`](https://auxly.io) binary for your
|
|
19
|
+
platform on first run and verifies it against the project's **minisign-signed**
|
|
20
|
+
checksum manifest.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install auxly-cli
|
|
24
|
+
auxly --help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How it works
|
|
28
|
+
|
|
29
|
+
- `pip install auxly-cli` installs a small pure-Python package (one wheel, all
|
|
30
|
+
platforms).
|
|
31
|
+
- The first time you run `auxly`, it downloads `auxly-<os>-<arch>` from the GitHub
|
|
32
|
+
release matching this package's version, fetches the signed
|
|
33
|
+
`auxly-<version>-checksums.txt` + `.minisig`, verifies the **minisign signature**
|
|
34
|
+
against the pinned public key, checks the binary's **SHA-256** against the signed
|
|
35
|
+
manifest, then caches and execs it. Later runs use the cache.
|
|
36
|
+
|
|
37
|
+
Set `AUXLY_REQUIRE_SIGNATURE=1` to hard-fail if a signed manifest is unavailable.
|
|
38
|
+
The cache lives under `$XDG_CACHE_HOME/auxly` (or `~/.cache/auxly`).
|
|
39
|
+
|
|
40
|
+
Supported: macOS / Linux / Windows on x64 / arm64. Python ≥ 3.8.
|
|
41
|
+
|
|
42
|
+
License: MIT · <https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
auxly_cli/__init__.py
|
|
4
|
+
auxly_cli/_runner.py
|
|
5
|
+
auxly_cli/_verify.py
|
|
6
|
+
auxly_cli.egg-info/PKG-INFO
|
|
7
|
+
auxly_cli.egg-info/SOURCES.txt
|
|
8
|
+
auxly_cli.egg-info/dependency_links.txt
|
|
9
|
+
auxly_cli.egg-info/entry_points.txt
|
|
10
|
+
auxly_cli.egg-info/requires.txt
|
|
11
|
+
auxly_cli.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cryptography>=3.4
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
auxly_cli
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "auxly-cli"
|
|
7
|
+
version = "1.0.21"
|
|
8
|
+
description = "Local-first unified memory system for AI agents — downloads the signature-verified auxly binary."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Tzamun Arabia IT Co.", email = "hi@auxly.io" }]
|
|
13
|
+
keywords = ["auxly", "ai", "memory", "mcp", "cli", "agents"]
|
|
14
|
+
dependencies = ["cryptography>=3.4"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://auxly.io"
|
|
18
|
+
Repository = "https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli"
|
|
19
|
+
Issues = "https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli/issues"
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
auxly = "auxly_cli._runner:main"
|
|
23
|
+
|
|
24
|
+
[tool.setuptools]
|
|
25
|
+
packages = ["auxly_cli"]
|