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.
Files changed (29) hide show
  1. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/PKG-INFO +2 -2
  2. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/README.md +1 -1
  3. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/__init__.py +1 -1
  4. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/_local_bind.py +22 -46
  5. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/agent_core.py +645 -2
  6. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/daemon.py +101 -12
  7. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/main.py +18 -3
  8. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/PKG-INFO +2 -2
  9. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/pyproject.toml +1 -1
  10. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_check_command.py +14 -0
  11. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_local_bind_commands.py +40 -3
  12. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/_build_config.py +0 -0
  13. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/autoupgrade.py +0 -0
  14. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/py.typed +0 -0
  15. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/runtime_evidence.py +0 -0
  16. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli/zcode_protocol.py +0 -0
  17. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  18. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  19. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/entry_points.txt +0 -0
  20. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/requires.txt +0 -0
  21. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/forgexa_cli.egg-info/top_level.txt +0 -0
  22. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/setup.cfg +0 -0
  23. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_auth_and_runtime_commands.py +0 -0
  24. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_autoupgrade.py +0 -0
  25. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_expiry_warnings_and_revoke.py +0 -0
  26. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_runtime_credentials.py +0 -0
  27. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_session_credentials.py +0 -0
  28. {forgexa_cli-1.59.1 → forgexa_cli-1.60.0}/tests/test_silent_install.py +0 -0
  29. {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.59.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** that discovers twelve local AI agent integrations (Claude Code, Codex, GitHub Copilot, Gemini CLI, OpenCode, Kimi Code, MiMo Code, Qwen Code, CodeBuddy, Qoder CLI, TraeCode CLI, and ZCode) and executes tasks on behalf of the server. MiMo Code (`mimo`, v0.1.14+), Qwen Code (`qwen`, v0.24.1+), CodeBuddy (`codebuddy`, v2.156.0+), Qoder CLI (`qoder`, v1.1.59+), TraeCode CLI (`trae`), and ZCode (`zcode`) are selected explicitly; automatic routing and generated default fallback chains exclude all six. CodeBuddy and Qoder completed their local AgentHost start/resume acceptance gates. Authentication, endpoint, and model selection remain in each local CLI profile; Forgexa never stores or overrides them.
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** that discovers twelve local AI agent integrations (Claude Code, Codex, GitHub Copilot, Gemini CLI, OpenCode, Kimi Code, MiMo Code, Qwen Code, CodeBuddy, Qoder CLI, TraeCode CLI, and ZCode) and executes tasks on behalf of the server. MiMo Code (`mimo`, v0.1.14+), Qwen Code (`qwen`, v0.24.1+), CodeBuddy (`codebuddy`, v2.156.0+), Qoder CLI (`qoder`, v1.1.59+), TraeCode CLI (`trae`), and ZCode (`zcode`) are selected explicitly; automatic routing and generated default fallback chains exclude all six. CodeBuddy and Qoder completed their local AgentHost start/resume acceptance gates. Authentication, endpoint, and model selection remain in each local CLI profile; Forgexa never stores or overrides them.
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.59.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
- """Advisory cross-process lock for read-modify-write cycles on the
52
- mapping file (multi-workspace parallel design §6.1/§6.3). Shares the
53
- `local-workspaces.json.lock` path with the Desktop Rust writer (fd-lock
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.parent.mkdir(parents=True, exist_ok=True)
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
- import msvcrt
78
-
79
- lock_file.seek(0)
80
- msvcrt.locking(lock_file.fileno(), msvcrt.LK_LOCK, 1)
81
- lock_kind = "msvcrt"
82
- except (ImportError, OSError):
83
- pass
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
- if lock_kind == "fcntl":
87
- try:
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)?/?$")