agentsecrets-cli 3.3.2__py3-none-any.whl → 3.3.3__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.
- agentsecrets/binary.py +43 -84
- {agentsecrets_cli-3.3.2.dist-info → agentsecrets_cli-3.3.3.dist-info}/METADATA +7 -2
- agentsecrets_cli-3.3.3.dist-info/RECORD +7 -0
- agentsecrets_cli-3.3.2.dist-info/RECORD +0 -7
- {agentsecrets_cli-3.3.2.dist-info → agentsecrets_cli-3.3.3.dist-info}/WHEEL +0 -0
- {agentsecrets_cli-3.3.2.dist-info → agentsecrets_cli-3.3.3.dist-info}/entry_points.txt +0 -0
agentsecrets/binary.py
CHANGED
|
@@ -1,97 +1,36 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import platform
|
|
3
3
|
import sys
|
|
4
|
-
import time
|
|
5
4
|
import urllib.request
|
|
6
5
|
import tarfile
|
|
7
6
|
import zipfile
|
|
8
7
|
import tempfile
|
|
9
8
|
import shutil
|
|
10
9
|
import stat
|
|
10
|
+
|
|
11
11
|
import json
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
def get_latest_github_version():
|
|
14
|
+
"""Fetches the latest version tag from GitHub API."""
|
|
15
|
+
try:
|
|
16
|
+
url = "https://api.github.com/repos/The-17/agentsecrets/releases/latest"
|
|
17
|
+
req = urllib.request.Request(url, headers={'User-Agent': 'agentsecrets-pypi'})
|
|
18
|
+
with urllib.request.urlopen(req) as response:
|
|
19
|
+
data = json.loads(response.read().decode())
|
|
20
|
+
return data['tag_name'].lstrip('v')
|
|
21
|
+
except Exception:
|
|
22
|
+
return None
|
|
14
23
|
|
|
15
24
|
def _get_version():
|
|
16
25
|
try:
|
|
17
|
-
from importlib.metadata import version
|
|
26
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
18
27
|
return version("agentsecrets-cli")
|
|
19
|
-
except
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import re
|
|
23
|
-
pyproject = os.path.join(os.path.dirname(__file__), "..", "..", "pyproject.toml")
|
|
24
|
-
if os.path.exists(pyproject):
|
|
25
|
-
with open(pyproject, "r", encoding="utf-8") as f:
|
|
26
|
-
m = re.search(r'version\s*=\s*["\']([^"\']+)["\']', f.read())
|
|
27
|
-
if m:
|
|
28
|
-
return m.group(1)
|
|
29
|
-
except Exception:
|
|
30
|
-
pass
|
|
31
|
-
return "dev"
|
|
28
|
+
except (ImportError, PackageNotFoundError):
|
|
29
|
+
latest = get_latest_github_version()
|
|
30
|
+
return latest if latest else "1.3.1"
|
|
32
31
|
|
|
33
32
|
VERSION = _get_version()
|
|
34
|
-
|
|
35
|
-
def compare_versions(v1, v2):
|
|
36
|
-
p1 = [int(x) for x in (v1 or "").lstrip("v").split(".") if x.isdigit()]
|
|
37
|
-
p2 = [int(x) for x in (v2 or "").lstrip("v").split(".") if x.isdigit()]
|
|
38
|
-
while len(p1) < 3: p1.append(0)
|
|
39
|
-
while len(p2) < 3: p2.append(0)
|
|
40
|
-
for i in range(3):
|
|
41
|
-
if p1[i] < p2[i]: return -1
|
|
42
|
-
if p1[i] > p2[i]: return 1
|
|
43
|
-
return 0
|
|
44
|
-
|
|
45
|
-
def check_update_notice():
|
|
46
|
-
try:
|
|
47
|
-
cache_file = os.path.expanduser("~/.agentsecrets/pypi_update_cache.json")
|
|
48
|
-
cache = None
|
|
49
|
-
if os.path.exists(cache_file):
|
|
50
|
-
try:
|
|
51
|
-
with open(cache_file, "r") as f:
|
|
52
|
-
cache = json.load(f)
|
|
53
|
-
except Exception:
|
|
54
|
-
pass
|
|
55
|
-
|
|
56
|
-
now = int(time.time())
|
|
57
|
-
if cache and cache.get("latest_version") and compare_versions(cache["latest_version"], VERSION) > 0:
|
|
58
|
-
sys.stderr.write(
|
|
59
|
-
f"\n\033[33mUpdate available:\033[0m {VERSION} -> \033[32m{cache['latest_version']}\033[0m\n"
|
|
60
|
-
f"Run: \033[36mpip install --upgrade agentsecrets-cli\033[0m to update\n\n"
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
if not cache or not cache.get("last_checked") or now - cache["last_checked"] > 86400:
|
|
64
|
-
try:
|
|
65
|
-
req = urllib.request.Request(
|
|
66
|
-
f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest",
|
|
67
|
-
headers={"User-Agent": "agentsecrets-pypi"}
|
|
68
|
-
)
|
|
69
|
-
with urllib.request.urlopen(req, timeout=2.0) as response:
|
|
70
|
-
data = json.loads(response.read().decode())
|
|
71
|
-
latest = data.get("tag_name", "").lstrip("v")
|
|
72
|
-
if latest:
|
|
73
|
-
os.makedirs(os.path.dirname(cache_file), exist_ok=True)
|
|
74
|
-
with open(cache_file, "w") as f:
|
|
75
|
-
json.dump({"last_checked": now, "latest_version": latest}, f)
|
|
76
|
-
except Exception:
|
|
77
|
-
pass
|
|
78
|
-
except Exception:
|
|
79
|
-
pass
|
|
80
|
-
|
|
81
|
-
def cleanup_old_binaries(base_dir, current_binary_path):
|
|
82
|
-
try:
|
|
83
|
-
if not os.path.exists(base_dir):
|
|
84
|
-
return
|
|
85
|
-
prefix = "agentsecrets.exe_" if platform.system().lower() == "windows" else "agentsecrets_"
|
|
86
|
-
for fname in os.listdir(base_dir):
|
|
87
|
-
full_path = os.path.join(base_dir, fname)
|
|
88
|
-
if fname.startswith(prefix) and full_path != current_binary_path:
|
|
89
|
-
try:
|
|
90
|
-
os.remove(full_path)
|
|
91
|
-
except Exception:
|
|
92
|
-
pass
|
|
93
|
-
except Exception:
|
|
94
|
-
pass
|
|
33
|
+
GITHUB_REPO = "The-17/agentsecrets"
|
|
95
34
|
|
|
96
35
|
def get_platform_info():
|
|
97
36
|
"""Returns a tuple of (os_name, arch_name) compatible with GoReleaser naming."""
|
|
@@ -122,9 +61,11 @@ def ensure_binary():
|
|
|
122
61
|
If not, download it from GitHub Releases.
|
|
123
62
|
Returns the absolute path to the binary.
|
|
124
63
|
"""
|
|
125
|
-
check_update_notice()
|
|
126
64
|
os_name, arch_name = get_platform_info()
|
|
127
65
|
|
|
66
|
+
# Store binaries in a hidden directory in the user's home or package dir
|
|
67
|
+
# For PyPI, it's easier to store in the package directory itself if we have permissions,
|
|
68
|
+
# or ~/.agentsecrets/bin
|
|
128
69
|
base_dir = os.path.expanduser("~/.agentsecrets/bin")
|
|
129
70
|
os.makedirs(base_dir, exist_ok=True)
|
|
130
71
|
|
|
@@ -132,14 +73,22 @@ def ensure_binary():
|
|
|
132
73
|
if os_name == "windows":
|
|
133
74
|
binary_name += ".exe"
|
|
134
75
|
|
|
76
|
+
# Versioned binary path
|
|
135
77
|
binary_path = os.path.join(base_dir, f"{binary_name}_{VERSION}")
|
|
136
78
|
|
|
137
79
|
if os.path.exists(binary_path):
|
|
138
80
|
return binary_path
|
|
139
81
|
|
|
140
|
-
|
|
82
|
+
# Need to download
|
|
83
|
+
print(f"AgentSecrets binary not found. Downloading version {VERSION} for {os_name}/{arch_name}...", file=sys.stderr)
|
|
141
84
|
|
|
142
85
|
ext = "tar.gz" if os_name != "windows" else "zip"
|
|
86
|
+
# Match the naming template in .goreleaser.yaml: {{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}
|
|
87
|
+
# Note: GoReleaser naming is case-sensitive and uses specific strings.
|
|
88
|
+
# Looking at .goreleaser.yaml: name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
|
89
|
+
# GoReleaser Os: linux, darwin, windows
|
|
90
|
+
# GoReleaser Arch: amd64, arm64
|
|
91
|
+
|
|
143
92
|
asset_name = f"agentsecrets_{VERSION}_{os_name}_{arch_name}.{ext}"
|
|
144
93
|
url = f"https://github.com/{GITHUB_REPO}/releases/download/v{VERSION}/{asset_name}"
|
|
145
94
|
|
|
@@ -147,9 +96,11 @@ def ensure_binary():
|
|
|
147
96
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
148
97
|
archive_path = os.path.join(tmpdir, asset_name)
|
|
149
98
|
|
|
99
|
+
# Download the archive
|
|
150
100
|
with urllib.request.urlopen(url) as response, open(archive_path, 'wb') as out_file:
|
|
151
101
|
shutil.copyfileobj(response, out_file)
|
|
152
102
|
|
|
103
|
+
# Extract
|
|
153
104
|
if ext == "tar.gz":
|
|
154
105
|
with tarfile.open(archive_path, "r:gz") as tar:
|
|
155
106
|
tar.extractall(path=tmpdir)
|
|
@@ -157,8 +108,12 @@ def ensure_binary():
|
|
|
157
108
|
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
|
|
158
109
|
zip_ref.extractall(tmpdir)
|
|
159
110
|
|
|
111
|
+
# Move the binary to the final location
|
|
112
|
+
# The archive contains the binary in the root
|
|
160
113
|
extracted_binary = os.path.join(tmpdir, binary_name)
|
|
161
114
|
if not os.path.exists(extracted_binary):
|
|
115
|
+
# Maybe it's inside a folder? goreleaser usually puts it in root by default unless configured otherwise
|
|
116
|
+
# Let's check all files in tmpdir
|
|
162
117
|
for root, dirs, files in os.walk(tmpdir):
|
|
163
118
|
if binary_name in files:
|
|
164
119
|
extracted_binary = os.path.join(root, binary_name)
|
|
@@ -166,10 +121,12 @@ def ensure_binary():
|
|
|
166
121
|
|
|
167
122
|
shutil.move(extracted_binary, binary_path)
|
|
168
123
|
|
|
124
|
+
# Ensure executable
|
|
169
125
|
st = os.stat(binary_path)
|
|
170
126
|
os.chmod(binary_path, st.st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
|
171
127
|
|
|
172
|
-
# Pre-register with keychain-auth if available
|
|
128
|
+
# Pre-register with keychain-auth if available. This eliminates
|
|
129
|
+
# the one-time setup spinner on the user's first command.
|
|
173
130
|
import subprocess
|
|
174
131
|
kc = shutil.which("keychain-auth")
|
|
175
132
|
if kc:
|
|
@@ -179,19 +136,21 @@ def ensure_binary():
|
|
|
179
136
|
timeout=5, capture_output=True,
|
|
180
137
|
)
|
|
181
138
|
except Exception:
|
|
182
|
-
pass
|
|
139
|
+
pass # AutoSetup handles registration at runtime if needed
|
|
183
140
|
|
|
184
|
-
cleanup_old_binaries(base_dir, binary_path)
|
|
185
141
|
return binary_path
|
|
186
142
|
|
|
187
143
|
except Exception as e:
|
|
144
|
+
# Fallback to checking if a real binary is already in the PATH
|
|
188
145
|
system_binary = shutil.which("agentsecrets")
|
|
146
|
+
# Ensure we don't pick up this Python wrapper itself (infinite loop)
|
|
189
147
|
if system_binary and not system_binary.endswith(".py") and "site-packages" not in system_binary:
|
|
190
148
|
return system_binary
|
|
191
149
|
|
|
192
150
|
raise Exception(
|
|
193
151
|
f"Failed to download AgentSecrets binary from {url}.\n"
|
|
194
152
|
f"Error: {e}\n\n"
|
|
195
|
-
"TIP:
|
|
196
|
-
"
|
|
153
|
+
"TIP: This usually happens if the version hasn't been released on GitHub yet.\n"
|
|
154
|
+
"Please run: git tag v1.0.0 && git push origin v1.0.0\n"
|
|
155
|
+
"This will trigger the build that makes this binary available."
|
|
197
156
|
)
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentsecrets-cli
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.3
|
|
4
4
|
Summary: AI-native zero-knowledge secrets manager
|
|
5
|
+
Project-URL: Homepage, https://agentsecrets.tech
|
|
6
|
+
Project-URL: Documentation, https://docs.agentsecrets.tech
|
|
7
|
+
Project-URL: Repository, https://github.com/The-17/agentsecrets
|
|
8
|
+
Project-URL: Issues, https://github.com/The-17/agentsecrets/issues
|
|
5
9
|
Author-email: The Seventeen <engineering@theseventeen.co>
|
|
6
10
|
License-Expression: MIT
|
|
7
11
|
Keywords: agents,ai,cli,credentials,secrets,security
|
|
@@ -23,7 +27,7 @@ Every other secrets tool was built for humans to provision credentials to agents
|
|
|
23
27
|
[](https://go.dev/)
|
|
24
28
|
[](https://clawhub.ai/SteppaCodes/agentsecrets)
|
|
25
29
|
|
|
26
|
-
**[Official Website](https://agentsecrets.tech)** | **[Engineering Blog Series](https://engineering.theseventeen.co/series/building-agentsecrets)**
|
|
30
|
+
**[Official Website](https://agentsecrets.tech)** | **[Documentation](https://docs.agentsecrets.tech)** | **[Engineering Blog Series](https://engineering.theseventeen.co/series/building-agentsecrets)**
|
|
27
31
|
|
|
28
32
|
---
|
|
29
33
|
|
|
@@ -641,6 +645,7 @@ make test
|
|
|
641
645
|
## Links
|
|
642
646
|
|
|
643
647
|
- **Website**: [agentsecrets.tech](https://agentsecrets.tech)
|
|
648
|
+
- **Documentation**: [docs.agentsecrets.tech](https://docs.agentsecrets.tech)
|
|
644
649
|
- **Deep Dive**: [Building AgentSecrets (Engineering Blog)](https://engineering.theseventeen.co/series/building-agentsecrets)
|
|
645
650
|
- **GitHub**: [github.com/The-17/agentsecrets](https://github.com/The-17/agentsecrets)
|
|
646
651
|
- **SDK**: [github.com/The-17/agentsecrets-sdk](https://github.com/The-17/agentsecrets-sdk)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
agentsecrets/__init__.py,sha256=ZhzQKWZ8RFrTIkj7z87B144DI95e8LMfA5w8NDWQDtg,23
|
|
2
|
+
agentsecrets/binary.py,sha256=JLGrD4csZLq60HyRK1BbzoxHCuot99V9EfhFLIptxXc,6165
|
|
3
|
+
agentsecrets/main.py,sha256=_K_pSWENU9zMloWHgLyxFOzRvTXCPtRhv4YLhapDClM,676
|
|
4
|
+
agentsecrets_cli-3.3.3.dist-info/METADATA,sha256=zCF5HQSCpeblpeemi3nn3INk3vlJg18-ssI4OXHYO9Q,23920
|
|
5
|
+
agentsecrets_cli-3.3.3.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
6
|
+
agentsecrets_cli-3.3.3.dist-info/entry_points.txt,sha256=5NUzueK6QD4Bz2t5xrTDd3KQr0nGYEoL2sX2wFmfH4E,56
|
|
7
|
+
agentsecrets_cli-3.3.3.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
agentsecrets/__init__.py,sha256=ZhzQKWZ8RFrTIkj7z87B144DI95e8LMfA5w8NDWQDtg,23
|
|
2
|
-
agentsecrets/binary.py,sha256=kUkAZORcfSN2VYKS_RP6WuBjoVFLW8p5dFhsIn3BD7Q,7244
|
|
3
|
-
agentsecrets/main.py,sha256=_K_pSWENU9zMloWHgLyxFOzRvTXCPtRhv4YLhapDClM,676
|
|
4
|
-
agentsecrets_cli-3.3.2.dist-info/METADATA,sha256=PnRxU59ns0NLKyr6NFn6uCoRJM8Xi_kTNzjSADdqGRY,23549
|
|
5
|
-
agentsecrets_cli-3.3.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
6
|
-
agentsecrets_cli-3.3.2.dist-info/entry_points.txt,sha256=5NUzueK6QD4Bz2t5xrTDd3KQr0nGYEoL2sX2wFmfH4E,56
|
|
7
|
-
agentsecrets_cli-3.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|