forgeqe-cli 2.2.4__tar.gz → 2.2.5__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.
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/PKG-INFO +2 -1
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli/__init__.py +1 -1
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli/launcher.py +73 -5
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli.egg-info/PKG-INFO +2 -1
- forgeqe_cli-2.2.5/py/forgeqe_cli.egg-info/requires.txt +6 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/pyproject.toml +3 -2
- forgeqe_cli-2.2.4/py/forgeqe_cli.egg-info/requires.txt +0 -3
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/LICENSE +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/README.md +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli/__main__.py +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli/pytest_plugin.py +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli.egg-info/SOURCES.txt +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli.egg-info/dependency_links.txt +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli.egg-info/entry_points.txt +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/py/forgeqe_cli.egg-info/top_level.txt +0 -0
- {forgeqe_cli-2.2.4 → forgeqe_cli-2.2.5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: forgeqe-cli
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: pip launcher for the ForgeQE browser agent (npm package: @capagents/forgeqe)
|
|
5
5
|
Author: CLI-Agents
|
|
6
6
|
License: MIT
|
|
@@ -8,6 +8,7 @@ Keywords: forgeqe,browser,agent,cli,opentui
|
|
|
8
8
|
Requires-Python: >=3.9
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
+
Requires-Dist: truststore==0.10.4; python_version >= "3.10"
|
|
11
12
|
Provides-Extra: dev
|
|
12
13
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
13
14
|
Dynamic: license-file
|
|
@@ -5,6 +5,7 @@ import io
|
|
|
5
5
|
import os
|
|
6
6
|
import platform
|
|
7
7
|
import shutil
|
|
8
|
+
import ssl
|
|
8
9
|
import stat
|
|
9
10
|
import subprocess
|
|
10
11
|
import sys
|
|
@@ -93,11 +94,77 @@ def bun_asset(system: str | None = None, machine: str | None = None, musl: bool
|
|
|
93
94
|
return f"bun-{os_name}-{cpu}{'-musl' if musl else ''}{'-baseline' if cpu == 'x64' else ''}.zip"
|
|
94
95
|
|
|
95
96
|
|
|
97
|
+
def _ssl_context() -> ssl.SSLContext | None:
|
|
98
|
+
"""The system's certificate store (truststore), so downloads work on networks that inspect HTTPS."""
|
|
99
|
+
try:
|
|
100
|
+
import truststore
|
|
101
|
+
|
|
102
|
+
return truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
103
|
+
except Exception:
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
96
107
|
def _download(url: str) -> bytes:
|
|
97
|
-
with urllib.request.urlopen(url, timeout=120) as res:
|
|
108
|
+
with urllib.request.urlopen(url, timeout=120, context=_ssl_context()) as res:
|
|
98
109
|
return res.read()
|
|
99
110
|
|
|
100
111
|
|
|
112
|
+
def github_release(repo: str, tag: str, asset: str) -> str:
|
|
113
|
+
"""A GitHub release download, from FORGEQE_GITHUB_MIRROR when one is set (src/network.ts)."""
|
|
114
|
+
mirror = os.environ.get("FORGEQE_GITHUB_MIRROR", "").strip().rstrip("/")
|
|
115
|
+
base = mirror if mirror.lower().startswith("https://") else "https://github.com"
|
|
116
|
+
return f"{base}/{repo}/releases/download/{tag}/{asset}"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def certs_off() -> bool:
|
|
120
|
+
return os.environ.get("FORGEQE_SYSTEM_CERTS", "").strip().lower() in ("0", "off", "false", "no")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def system_ca_path() -> Path:
|
|
124
|
+
return forgeqe_home() / "cache" / "system-ca.pem"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _system_roots() -> list[str]:
|
|
128
|
+
"""PEM roots the system trusts: Windows' ROOT store, macOS' System keychains, or Linux's bundle."""
|
|
129
|
+
if WINDOWS:
|
|
130
|
+
return [ssl.DER_cert_to_PEM_cert(der) for der, enc, _ in ssl.enum_certificates("ROOT") if enc == "x509_asn"]
|
|
131
|
+
if sys.platform == "darwin":
|
|
132
|
+
keychains = [k for k in ("/Library/Keychains/System.keychain", "/System/Library/Keychains/SystemRootCertificates.keychain") if Path(k).is_file()]
|
|
133
|
+
try:
|
|
134
|
+
out = subprocess.run(["/usr/bin/security", "find-certificate", "-a", "-p", *keychains], capture_output=True, text=True, timeout=30)
|
|
135
|
+
except (OSError, subprocess.SubprocessError):
|
|
136
|
+
return []
|
|
137
|
+
return [b + "-----END CERTIFICATE-----\n" for b in out.stdout.split("-----END CERTIFICATE-----") if "BEGIN CERTIFICATE" in b] if out.returncode == 0 else []
|
|
138
|
+
for bundle in ("/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/certs/ca-bundle.crt", "/etc/ssl/ca-bundle.pem", "/etc/ssl/cert.pem"):
|
|
139
|
+
if Path(bundle).is_file():
|
|
140
|
+
return [Path(bundle).read_text(encoding="utf-8", errors="replace")]
|
|
141
|
+
return []
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def bun_env(env: dict[str, str] | None = None) -> dict[str, str]:
|
|
145
|
+
"""
|
|
146
|
+
Bun reads NODE_EXTRA_CA_CERTS only at start: give it the system's trusted roots, written here the first time
|
|
147
|
+
(bun x fetches ForgeQE before ForgeQE runs) and kept up to date by ForgeQE (src/network.ts).
|
|
148
|
+
"""
|
|
149
|
+
env = dict(os.environ if env is None else env)
|
|
150
|
+
if env.get("NODE_EXTRA_CA_CERTS") or certs_off():
|
|
151
|
+
return env
|
|
152
|
+
ca = system_ca_path()
|
|
153
|
+
if not ca.is_file():
|
|
154
|
+
try:
|
|
155
|
+
roots = _system_roots()
|
|
156
|
+
if roots:
|
|
157
|
+
ca.parent.mkdir(parents=True, exist_ok=True)
|
|
158
|
+
tmp = ca.with_name(f"{ca.name}.{os.getpid()}.tmp")
|
|
159
|
+
tmp.write_text("".join(r if r.endswith("\n") else r + "\n" for r in roots), encoding="utf-8")
|
|
160
|
+
os.replace(tmp, ca)
|
|
161
|
+
except OSError:
|
|
162
|
+
pass
|
|
163
|
+
if ca.is_file():
|
|
164
|
+
env["NODE_EXTRA_CA_CERTS"] = str(ca)
|
|
165
|
+
return env
|
|
166
|
+
|
|
167
|
+
|
|
101
168
|
def expected_sha256(sums: str, asset: str) -> str | None:
|
|
102
169
|
for line in sums.splitlines():
|
|
103
170
|
parts = line.split()
|
|
@@ -110,7 +177,7 @@ def install_bun() -> str:
|
|
|
110
177
|
asset = bun_asset()
|
|
111
178
|
if not asset:
|
|
112
179
|
raise LaunchError(f"no Bun build for {platform.system()}/{platform.machine()}")
|
|
113
|
-
base =
|
|
180
|
+
base = github_release("oven-sh/bun", f"bun-v{BUN_VERSION}", "").rstrip("/")
|
|
114
181
|
print(f"forgeqe: downloading Bun {BUN_VERSION} ({asset}) into {tools_dir()} (one time)...", file=sys.stderr)
|
|
115
182
|
data = _download(f"{base}/{asset}")
|
|
116
183
|
expected = expected_sha256(_download(f"{base}/SHASUMS256.txt").decode("utf-8"), asset)
|
|
@@ -139,7 +206,8 @@ def manual_hint() -> str:
|
|
|
139
206
|
install = 'powershell -c "irm bun.sh/install.ps1 | iex"' if WINDOWS else "curl -fsSL https://bun.sh/install | bash"
|
|
140
207
|
return (
|
|
141
208
|
f"Install Bun {'.'.join(map(str, MIN_BUN))}+ yourself ({install}) and re-run forgeqe,\n"
|
|
142
|
-
f"or set FORGEQE_BUN to the full path of {BUN_EXE}
|
|
209
|
+
f"or set FORGEQE_BUN to the full path of {BUN_EXE}.\n"
|
|
210
|
+
"Behind a company mirror of GitHub downloads, set FORGEQE_GITHUB_MIRROR to it."
|
|
143
211
|
)
|
|
144
212
|
|
|
145
213
|
|
|
@@ -179,7 +247,7 @@ def main() -> None:
|
|
|
179
247
|
os.environ["PATH"] = bindir + os.pathsep + os.environ.get("PATH", "")
|
|
180
248
|
if WINDOWS:
|
|
181
249
|
try:
|
|
182
|
-
raise SystemExit(subprocess.call(cmd))
|
|
250
|
+
raise SystemExit(subprocess.call(cmd, env=bun_env()))
|
|
183
251
|
except KeyboardInterrupt:
|
|
184
252
|
raise SystemExit(130)
|
|
185
|
-
os.
|
|
253
|
+
os.execve(cmd[0], cmd, bun_env())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: forgeqe-cli
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: pip launcher for the ForgeQE browser agent (npm package: @capagents/forgeqe)
|
|
5
5
|
Author: CLI-Agents
|
|
6
6
|
License: MIT
|
|
@@ -8,6 +8,7 @@ Keywords: forgeqe,browser,agent,cli,opentui
|
|
|
8
8
|
Requires-Python: >=3.9
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
+
Requires-Dist: truststore==0.10.4; python_version >= "3.10"
|
|
11
12
|
Provides-Extra: dev
|
|
12
13
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
13
14
|
Dynamic: license-file
|
|
@@ -4,14 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "forgeqe-cli"
|
|
7
|
-
version = "2.2.
|
|
7
|
+
version = "2.2.5"
|
|
8
8
|
description = "pip launcher for the ForgeQE browser agent (npm package: @capagents/forgeqe)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
11
|
license = { text = "MIT" }
|
|
12
12
|
authors = [{ name = "CLI-Agents" }]
|
|
13
13
|
keywords = ["forgeqe", "browser", "agent", "cli", "opentui"]
|
|
14
|
-
|
|
14
|
+
# truststore: downloads check HTTPS certificates with the system's store, for networks that inspect HTTPS.
|
|
15
|
+
dependencies = ["truststore==0.10.4; python_version >= '3.10'"]
|
|
15
16
|
|
|
16
17
|
[project.optional-dependencies]
|
|
17
18
|
dev = ["pytest>=8.0"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|