forgexa-cli 1.59.1__tar.gz → 1.60.0__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.
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/PKG-INFO +2 -2
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/README.md +1 -1
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/__init__.py +1 -1
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/_local_bind.py +22 -46
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/agent_core.py +645 -2
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/daemon.py +101 -12
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/main.py +18 -3
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/PKG-INFO +2 -2
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/pyproject.toml +1 -1
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_check_command.py +14 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_local_bind_commands.py +40 -3
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/_build_config.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/autoupgrade.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/py.typed +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/runtime_evidence.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/zcode_protocol.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/SOURCES.txt +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/dependency_links.txt +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/entry_points.txt +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/requires.txt +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/top_level.txt +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/setup.cfg +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_auth_and_runtime_commands.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_autoupgrade.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_expiry_warnings_and_revoke.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_runtime_credentials.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_session_credentials.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_silent_install.py +0 -0
- {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_upgrade_observability.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: forgexa-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.60.0
|
|
4
4
|
Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
|
|
5
5
|
Author-email: Jason Sun <dev.winds@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -35,7 +35,7 @@ Requires-Dist: socksio>=1.0.0; extra == "daemon"
|
|
|
35
35
|
Command-line client and agent runtime for the [Forgexa](https://forgexa.net) platform.
|
|
36
36
|
|
|
37
37
|
Communicates with the Forgexa server via REST API.
|
|
38
|
-
Includes a built-in **daemon**
|
|
38
|
+
Includes a built-in **daemon** with thirteen integrations: Claude Code, Codex, GitHub Copilot, Gemini CLI, OpenCode, Kimi Code, MiMo Code, Qwen Code, CodeBuddy, Qoder CLI, TraeCode CLI, ZCode, and DeepSeek Harness. Six standard candidates are automatically routed; seven require explicit selection. Harness (`deepseek-harness`) is a developer preview for personal Runtimes/Desktop, pinned to 0.2.0-rc.2 and Node 22.19+ within 22.x or 24+. It owns a managed runtime profile with read-only external credentials, without copying personal settings. Shared pools/native Windows are blocked. After exact-build live acceptance, `forgexa agent approve-live deepseek-harness` records an attestation; `forgexa check --agent deepseek-harness --quick` avoids model calls, while normal `check` runs a potentially billable minimal task. See [global/local installation and limits](../documentation/guide/agent-installation.md#deepseek-harness-developer-preview).
|
|
39
39
|
|
|
40
40
|
## Installation
|
|
41
41
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Command-line client and agent runtime for the [Forgexa](https://forgexa.net) platform.
|
|
4
4
|
|
|
5
5
|
Communicates with the Forgexa server via REST API.
|
|
6
|
-
Includes a built-in **daemon**
|
|
6
|
+
Includes a built-in **daemon** with thirteen integrations: Claude Code, Codex, GitHub Copilot, Gemini CLI, OpenCode, Kimi Code, MiMo Code, Qwen Code, CodeBuddy, Qoder CLI, TraeCode CLI, ZCode, and DeepSeek Harness. Six standard candidates are automatically routed; seven require explicit selection. Harness (`deepseek-harness`) is a developer preview for personal Runtimes/Desktop, pinned to 0.2.0-rc.2 and Node 22.19+ within 22.x or 24+. It owns a managed runtime profile with read-only external credentials, without copying personal settings. Shared pools/native Windows are blocked. After exact-build live acceptance, `forgexa agent approve-live deepseek-harness` records an attestation; `forgexa check --agent deepseek-harness --quick` avoids model calls, while normal `check` runs a potentially billable minimal task. See [global/local installation and limits](../documentation/guide/agent-installation.md#deepseek-harness-developer-preview).
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""forgexa-cli — Forgexa command-line client."""
|
|
2
|
-
__version__ = "1.
|
|
2
|
+
__version__ = "1.60.0"
|
|
@@ -47,58 +47,34 @@ def save_local_workspaces_mapping(mapping: dict) -> None:
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
@contextlib.contextmanager
|
|
50
|
-
def local_workspaces_mapping_lock() -> Iterator[None]:
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
crate); without it, a CLI bind-local and a Desktop link running
|
|
55
|
-
concurrently could each drop the other's just-written entry. Best-effort:
|
|
56
|
-
platforms without fcntl/msvcrt degrade to lock-free (the atomic rename
|
|
57
|
-
still prevents torn files).
|
|
58
|
-
"""
|
|
50
|
+
def local_workspaces_mapping_lock(workspace_path: str | Path | None = None) -> Iterator[None]:
|
|
51
|
+
"""Serialize mapping writes; lock or parse failures never degrade to unlocked writes."""
|
|
52
|
+
from forgexa_cli.agent_core import acquire_file_lock, release_file_lock
|
|
53
|
+
|
|
59
54
|
path = local_workspaces_mapping_path()
|
|
60
55
|
lock_path = path.with_name(path.name + ".lock")
|
|
56
|
+
lock_file = acquire_file_lock(lock_path, blocking=True)
|
|
57
|
+
if lock_file is None:
|
|
58
|
+
raise RuntimeError("Could not acquire the local workspace mapping write lock")
|
|
59
|
+
workspace_lock = None
|
|
61
60
|
try:
|
|
62
|
-
path.
|
|
63
|
-
lock_file = open(lock_path, "a+")
|
|
64
|
-
except OSError:
|
|
65
|
-
yield
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
lock_kind = None
|
|
69
|
-
try:
|
|
70
|
-
try:
|
|
71
|
-
import fcntl
|
|
72
|
-
|
|
73
|
-
fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
|
|
74
|
-
lock_kind = "fcntl"
|
|
75
|
-
except ImportError:
|
|
61
|
+
if path.exists():
|
|
76
62
|
try:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
63
|
+
mapping = json.loads(path.read_text(encoding="utf-8"))
|
|
64
|
+
if not isinstance(mapping, dict):
|
|
65
|
+
raise ValueError("Mapping must be a JSON object")
|
|
66
|
+
except (OSError, ValueError) as error:
|
|
67
|
+
raise RuntimeError("Local workspace mapping is unreadable; recover it before modifying bindings") from error
|
|
68
|
+
if workspace_path is not None:
|
|
69
|
+
from forgexa_cli.agent_core import acquire_workspace_write_lock
|
|
70
|
+
|
|
71
|
+
workspace_lock = acquire_workspace_write_lock(workspace_path)
|
|
72
|
+
if workspace_lock is None:
|
|
73
|
+
raise RuntimeError("A task or agent is writing this workspace; wait before changing its mapping")
|
|
84
74
|
yield
|
|
85
75
|
finally:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
import fcntl
|
|
89
|
-
|
|
90
|
-
fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
|
|
91
|
-
except (ImportError, OSError):
|
|
92
|
-
pass
|
|
93
|
-
elif lock_kind == "msvcrt":
|
|
94
|
-
try:
|
|
95
|
-
import msvcrt
|
|
96
|
-
|
|
97
|
-
lock_file.seek(0)
|
|
98
|
-
msvcrt.locking(lock_file.fileno(), msvcrt.LK_UNLCK, 1)
|
|
99
|
-
except (ImportError, OSError):
|
|
100
|
-
pass
|
|
101
|
-
lock_file.close()
|
|
76
|
+
release_file_lock(workspace_lock)
|
|
77
|
+
release_file_lock(lock_file)
|
|
102
78
|
|
|
103
79
|
|
|
104
80
|
_SSH_SCHEME_RE = re.compile(r"^ssh://(?:[^@/]+@)?([^/:]+)(?::\d+)?/(.+?)(?:\.git)?/?$")
|