forgexa-cli 1.60.0__tar.gz → 1.60.1__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.60.0 → forgexa_cli-1.60.1}/PKG-INFO +2 -2
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/README.md +1 -1
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/__init__.py +1 -1
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/agent_core.py +32 -3
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/daemon.py +17 -13
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/main.py +5 -4
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli.egg-info/PKG-INFO +2 -2
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/pyproject.toml +1 -1
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_check_command.py +17 -2
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/_build_config.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/_local_bind.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/autoupgrade.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/py.typed +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/runtime_evidence.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli/zcode_protocol.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli.egg-info/SOURCES.txt +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli.egg-info/dependency_links.txt +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli.egg-info/entry_points.txt +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli.egg-info/requires.txt +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/forgexa_cli.egg-info/top_level.txt +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/setup.cfg +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_auth_and_runtime_commands.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_autoupgrade.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_expiry_warnings_and_revoke.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_local_bind_commands.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_runtime_credentials.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_session_credentials.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/tests/test_silent_install.py +0 -0
- {forgexa_cli-1.60.0 → forgexa_cli-1.60.1}/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.60.
|
|
3
|
+
Version: 1.60.1
|
|
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** 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
|
|
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`) 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` records an attestation; `forgexa check --agent deepseek --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** 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
|
|
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`) 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` records an attestation; `forgexa check --agent deepseek --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.60.
|
|
2
|
+
__version__ = "1.60.1"
|
|
@@ -531,6 +531,34 @@ def _agent_discovery_verification_issue(agent_id: str, binary: str) -> str | Non
|
|
|
531
531
|
return agent_execution_verification_issue(agent_id, binary)
|
|
532
532
|
|
|
533
533
|
|
|
534
|
+
def canonical_agent_id(agent_id: str | None) -> str | None:
|
|
535
|
+
return "deepseek" if agent_id == "deepseek-harness" else agent_id
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def canonical_agent_inventory(agents: list | None) -> list | None:
|
|
539
|
+
if not isinstance(agents, list) or not agents:
|
|
540
|
+
return agents
|
|
541
|
+
return [
|
|
542
|
+
{**entry, "agent_id": "deepseek", "reported_agent_id": "deepseek-harness"}
|
|
543
|
+
if isinstance(entry, dict) and entry.get("agent_id") == "deepseek-harness" else entry
|
|
544
|
+
for entry in agents
|
|
545
|
+
]
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def runtime_agent_wire_id(agent_id: str | None, available_agents: list | None) -> str | None:
|
|
549
|
+
canonical = canonical_agent_id(agent_id)
|
|
550
|
+
if canonical != "deepseek":
|
|
551
|
+
return canonical
|
|
552
|
+
reported = [
|
|
553
|
+
entry.get("reported_agent_id") or entry.get("agent_id")
|
|
554
|
+
for entry in available_agents or []
|
|
555
|
+
if isinstance(entry, dict) and canonical_agent_id(entry.get("agent_id")) == canonical
|
|
556
|
+
]
|
|
557
|
+
if "deepseek" not in reported and "deepseek-harness" in reported:
|
|
558
|
+
return "deepseek-harness"
|
|
559
|
+
return canonical
|
|
560
|
+
|
|
561
|
+
|
|
534
562
|
# ── Agent Discovery ──
|
|
535
563
|
|
|
536
564
|
|
|
@@ -584,7 +612,7 @@ class AgentDiscovery:
|
|
|
584
612
|
),
|
|
585
613
|
"upgrade_hint": "mimo upgrade",
|
|
586
614
|
},
|
|
587
|
-
"deepseek
|
|
615
|
+
"deepseek": {
|
|
588
616
|
"commands": ["dsh"],
|
|
589
617
|
"detect": "dsh --version",
|
|
590
618
|
"invoke_modes": ["cli"],
|
|
@@ -2378,7 +2406,7 @@ def deepseek_harness_verification_issue(binary: str) -> str | None:
|
|
|
2378
2406
|
pass
|
|
2379
2407
|
return (
|
|
2380
2408
|
"DeepSeek Harness requires live start/resume/cancel/isolation acceptance "
|
|
2381
|
-
"for this installed build; then run `forgexa agent approve-live deepseek
|
|
2409
|
+
"for this installed build; then run `forgexa agent approve-live deepseek`"
|
|
2382
2410
|
)
|
|
2383
2411
|
|
|
2384
2412
|
|
|
@@ -3106,7 +3134,8 @@ def agent_live_gate_approved(agent_id: str, env: dict[str, str] | None = None) -
|
|
|
3106
3134
|
|
|
3107
3135
|
def agent_execution_verification_issue(agent_id: str, binary: str) -> str | None:
|
|
3108
3136
|
"""Return a fail-closed build/live-acceptance gate for local agents."""
|
|
3109
|
-
|
|
3137
|
+
agent_id = canonical_agent_id(agent_id)
|
|
3138
|
+
if agent_id == "deepseek":
|
|
3110
3139
|
return deepseek_harness_verification_issue(binary)
|
|
3111
3140
|
if agent_id == "zcode":
|
|
3112
3141
|
build_issue = zcode_build_verification_issue(binary)
|
|
@@ -1196,7 +1196,7 @@ except (ImportError, ModuleNotFoundError):
|
|
|
1196
1196
|
# DAEMON_VERSION is the protocol/logic version of the daemon code.
|
|
1197
1197
|
# Kept in sync with pyproject.toml version via bump-version.sh.
|
|
1198
1198
|
# CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
|
|
1199
|
-
DAEMON_VERSION = "1.60.
|
|
1199
|
+
DAEMON_VERSION = "1.60.1"
|
|
1200
1200
|
|
|
1201
1201
|
|
|
1202
1202
|
def _detect_client_type() -> str:
|
|
@@ -6266,7 +6266,7 @@ class ProcessManager:
|
|
|
6266
6266
|
result = await self._run_mimo(
|
|
6267
6267
|
agent, prompt, workspace_path, timeout, task.task_id, on_chunk,
|
|
6268
6268
|
)
|
|
6269
|
-
elif agent.agent_id == "deepseek
|
|
6269
|
+
elif agent_core.canonical_agent_id(agent.agent_id) == "deepseek":
|
|
6270
6270
|
result = await self._run_deepseek_harness(
|
|
6271
6271
|
agent, prompt, workspace_path, timeout, task.task_id, on_chunk,
|
|
6272
6272
|
)
|
|
@@ -6316,7 +6316,7 @@ class ProcessManager:
|
|
|
6316
6316
|
result.metrics["duration_seconds"] = round(elapsed, 2)
|
|
6317
6317
|
|
|
6318
6318
|
# Detect agent-level failures despite exit code 0
|
|
6319
|
-
output_failure = None if agent.agent_id == "deepseek
|
|
6319
|
+
output_failure = None if agent_core.canonical_agent_id(agent.agent_id) == "deepseek" else self._detect_agent_output_failure(result, agent.agent_id)
|
|
6320
6320
|
if output_failure:
|
|
6321
6321
|
logger.warning(
|
|
6322
6322
|
"Agent '%s' exited 0 but output indicates failure: %s",
|
|
@@ -12104,7 +12104,7 @@ class RuntimeDaemon:
|
|
|
12104
12104
|
"codex": "npm install -g @openai/codex",
|
|
12105
12105
|
"opencode": "curl -sSL https://opencode.ai/install | sh",
|
|
12106
12106
|
"mimo": "curl -fsSL https://mimo.xiaomi.com/install | bash",
|
|
12107
|
-
"deepseek
|
|
12107
|
+
"deepseek": "npm i -g @deepseek-ai/dsh@0.2.0-rc.2",
|
|
12108
12108
|
"qwen": "npm install -g @qwen-code/qwen-code",
|
|
12109
12109
|
"codebuddy": "npm install -g @tencent-ai/codebuddy-code",
|
|
12110
12110
|
"qoder": "curl -fsSL https://qoder.com/install | bash",
|
|
@@ -13167,13 +13167,15 @@ class RuntimeDaemon:
|
|
|
13167
13167
|
self, current_agent_id: str, fallback_chain: list[str] | None, tried: set[str]
|
|
13168
13168
|
) -> DiscoveredAgent | None:
|
|
13169
13169
|
"""Find the next untried agent from fallback chain or available agents."""
|
|
13170
|
+
tried = {agent_core.canonical_agent_id(agent_id) for agent_id in tried}
|
|
13170
13171
|
# 1. Try fallback chain
|
|
13171
13172
|
if fallback_chain:
|
|
13172
13173
|
for fallback_id in fallback_chain:
|
|
13174
|
+
fallback_id = agent_core.canonical_agent_id(fallback_id)
|
|
13173
13175
|
if fallback_id in tried:
|
|
13174
13176
|
continue
|
|
13175
13177
|
for agent in self.agents:
|
|
13176
|
-
if agent.agent_id == fallback_id:
|
|
13178
|
+
if agent_core.canonical_agent_id(agent.agent_id) == fallback_id:
|
|
13177
13179
|
return agent
|
|
13178
13180
|
|
|
13179
13181
|
# 2. Try any available agent not yet tried (prefer opencode > copilot > gemini > claude)
|
|
@@ -13189,8 +13191,8 @@ class RuntimeDaemon:
|
|
|
13189
13191
|
# become implicit catch-alls because their execution profiles are
|
|
13190
13192
|
# tightly managed.
|
|
13191
13193
|
for agent in self.agents:
|
|
13192
|
-
if agent.agent_id not in tried and agent.agent_id not in {
|
|
13193
|
-
"mimo", "qwen", "codebuddy", "qoder", "trae", "zcode", "deepseek
|
|
13194
|
+
if agent_core.canonical_agent_id(agent.agent_id) not in tried and agent_core.canonical_agent_id(agent.agent_id) not in {
|
|
13195
|
+
"mimo", "qwen", "codebuddy", "qoder", "trae", "zcode", "deepseek",
|
|
13194
13196
|
}:
|
|
13195
13197
|
return agent
|
|
13196
13198
|
|
|
@@ -13208,18 +13210,20 @@ class RuntimeDaemon:
|
|
|
13208
13210
|
custom identifier). This prevents silent substitution when the user explicitly
|
|
13209
13211
|
selected an agent that is just not installed locally.
|
|
13210
13212
|
"""
|
|
13213
|
+
agent_type = agent_core.canonical_agent_id(agent_type)
|
|
13211
13214
|
# 1. Exact match
|
|
13212
13215
|
for agent in self.agents:
|
|
13213
|
-
if agent.agent_id == agent_type:
|
|
13216
|
+
if agent_core.canonical_agent_id(agent.agent_id) == agent_type:
|
|
13214
13217
|
return agent
|
|
13215
13218
|
|
|
13216
13219
|
# 2. Try fallback chain from policy
|
|
13217
13220
|
if fallback_chain:
|
|
13218
13221
|
for fallback_id in fallback_chain:
|
|
13222
|
+
fallback_id = agent_core.canonical_agent_id(fallback_id)
|
|
13219
13223
|
if fallback_id == agent_type:
|
|
13220
13224
|
continue
|
|
13221
13225
|
for agent in self.agents:
|
|
13222
|
-
if agent.agent_id == fallback_id:
|
|
13226
|
+
if agent_core.canonical_agent_id(agent.agent_id) == fallback_id:
|
|
13223
13227
|
logger.info("Using fallback agent '%s' (requested '%s')", fallback_id, agent_type)
|
|
13224
13228
|
return agent
|
|
13225
13229
|
|
|
@@ -13239,8 +13243,8 @@ class RuntimeDaemon:
|
|
|
13239
13243
|
return next(
|
|
13240
13244
|
(
|
|
13241
13245
|
agent for agent in self.agents
|
|
13242
|
-
if agent.agent_id not in {
|
|
13243
|
-
"mimo", "qwen", "codebuddy", "qoder", "trae", "zcode", "deepseek
|
|
13246
|
+
if agent_core.canonical_agent_id(agent.agent_id) not in {
|
|
13247
|
+
"mimo", "qwen", "codebuddy", "qoder", "trae", "zcode", "deepseek",
|
|
13244
13248
|
}
|
|
13245
13249
|
),
|
|
13246
13250
|
None,
|
|
@@ -14624,7 +14628,7 @@ class RuntimeDaemon:
|
|
|
14624
14628
|
# string so _select_agent falls through to its "any available L3
|
|
14625
14629
|
# agent" logic instead of hard-failing on the 'claude' default.
|
|
14626
14630
|
_AGENT_ALIASES = {"claude": "claude", "kimi": "kimi"}
|
|
14627
|
-
agent_type = _AGENT_ALIASES.get(agent_override or "", agent_override or "")
|
|
14631
|
+
agent_type = agent_core.canonical_agent_id(_AGENT_ALIASES.get(agent_override or "", agent_override or ""))
|
|
14628
14632
|
agent = self._select_agent(agent_type, [])
|
|
14629
14633
|
if not agent:
|
|
14630
14634
|
_INSTALL_HINTS = {
|
|
@@ -14632,7 +14636,7 @@ class RuntimeDaemon:
|
|
|
14632
14636
|
"codex": "npm install -g @openai/codex",
|
|
14633
14637
|
"opencode": "curl -sSL https://opencode.ai/install | sh",
|
|
14634
14638
|
"mimo": "curl -fsSL https://mimo.xiaomi.com/install | bash",
|
|
14635
|
-
"deepseek
|
|
14639
|
+
"deepseek": "npm i -g @deepseek-ai/dsh@0.2.0-rc.2",
|
|
14636
14640
|
"qwen": "npm install -g @qwen-code/qwen-code",
|
|
14637
14641
|
"codebuddy": "npm install -g @tencent-ai/codebuddy-code",
|
|
14638
14642
|
"qoder": "curl -fsSL https://qoder.com/install | bash",
|
|
@@ -3018,8 +3018,9 @@ def cmd_check(args: argparse.Namespace) -> None:
|
|
|
3018
3018
|
|
|
3019
3019
|
os.environ.setdefault("DAEMON_NO_CONSOLE_LOG", "1")
|
|
3020
3020
|
from forgexa_cli.daemon import AgentDiscovery
|
|
3021
|
+
from forgexa_cli.agent_core import canonical_agent_id
|
|
3021
3022
|
|
|
3022
|
-
only_agent = getattr(args, "agent", None)
|
|
3023
|
+
only_agent = canonical_agent_id(getattr(args, "agent", None))
|
|
3023
3024
|
quick = bool(getattr(args, "quick", False))
|
|
3024
3025
|
environment_requested = bool(getattr(args, "environment", False))
|
|
3025
3026
|
timeout = getattr(args, "timeout", None) or 90
|
|
@@ -3686,8 +3687,8 @@ def cmd_agent_approve_live(args: argparse.Namespace) -> None:
|
|
|
3686
3687
|
|
|
3687
3688
|
from . import agent_core
|
|
3688
3689
|
|
|
3689
|
-
agent_id = args.agent_id.strip().lower()
|
|
3690
|
-
if agent_id == "deepseek
|
|
3690
|
+
agent_id = agent_core.canonical_agent_id(args.agent_id.strip().lower())
|
|
3691
|
+
if agent_id == "deepseek":
|
|
3691
3692
|
binary = getattr(args, "binary", None) or os.environ.get("FACTORY_DEEPSEEK_HARNESS_PATH") or shutil.which("dsh")
|
|
3692
3693
|
if not binary:
|
|
3693
3694
|
print("error: dsh not found; install @deepseek-ai/dsh@0.2.0-rc.2 globally", file=sys.stderr)
|
|
@@ -3976,7 +3977,7 @@ def main() -> None:
|
|
|
3976
3977
|
)
|
|
3977
3978
|
agent_approve_live_p.add_argument(
|
|
3978
3979
|
"agent_id", metavar="AGENT_ID",
|
|
3979
|
-
help="Gated agent id (e.g. trae, zcode, deepseek-harness)",
|
|
3980
|
+
help="Gated agent id (e.g. trae, zcode, deepseek; legacy deepseek-harness accepted)",
|
|
3980
3981
|
)
|
|
3981
3982
|
agent_approve_live_p.add_argument("--binary", default=None, metavar="PATH", help="Installed Harness binary for build-scoped acceptance")
|
|
3982
3983
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: forgexa-cli
|
|
3
|
-
Version: 1.60.
|
|
3
|
+
Version: 1.60.1
|
|
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** 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
|
|
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`) 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` records an attestation; `forgexa check --agent deepseek --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
|
|
|
@@ -30,7 +30,8 @@ def _agent(agent_id: str, version: str = "1.0.0") -> daemon.DiscoveredAgent:
|
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
@pytest.mark.parametrize("agent_id", ["deepseek", "deepseek-harness"])
|
|
34
|
+
def test_deepseek_harness_live_approval_is_build_scoped(tmp_path, monkeypatch, capsys, agent_id):
|
|
34
35
|
from forgexa_cli import agent_core
|
|
35
36
|
|
|
36
37
|
approval = tmp_path / "build-approved.json"
|
|
@@ -38,12 +39,26 @@ def test_deepseek_harness_live_approval_is_build_scoped(tmp_path, monkeypatch, c
|
|
|
38
39
|
monkeypatch.setattr(agent_core, "DEEPSEEK_HARNESS_APPROVAL_FILE", approval)
|
|
39
40
|
monkeypatch.setattr(agent_core, "AGENT_LIVE_VERIFIED_FILE", old_approval)
|
|
40
41
|
monkeypatch.setattr(agent_core, "deepseek_harness_build_info", lambda binary: {"fingerprint": "test-build", "version": "0.2.0-rc.2", "node_version": "25.2.1"})
|
|
41
|
-
main.cmd_agent_approve_live(SimpleNamespace(agent_id=
|
|
42
|
+
main.cmd_agent_approve_live(SimpleNamespace(agent_id=agent_id, binary="/fake/dsh"))
|
|
42
43
|
assert json.loads(approval.read_text())["builds"] == ["test-build"]
|
|
43
44
|
assert not old_approval.exists()
|
|
44
45
|
assert "attestation" in capsys.readouterr().out
|
|
45
46
|
|
|
46
47
|
|
|
48
|
+
@pytest.mark.parametrize("agent_id", ["deepseek", "deepseek-harness"])
|
|
49
|
+
def test_deepseek_harness_quick_check_accepts_legacy_id(monkeypatch, capsys, agent_id):
|
|
50
|
+
monkeypatch.setattr(daemon.AgentDiscovery, "AGENT_REGISTRY", {"deepseek": {"commands": ["dsh"], "detect": "dsh --version"}})
|
|
51
|
+
monkeypatch.setattr(daemon.AgentDiscovery, "discover", AsyncMock(return_value=[_agent("deepseek", "0.2.0-rc.2")]))
|
|
52
|
+
execute = AsyncMock()
|
|
53
|
+
monkeypatch.setattr(daemon.ProcessManager, "run_agent", execute)
|
|
54
|
+
main.cmd_check(SimpleNamespace(agent=agent_id, quick=True, timeout=90))
|
|
55
|
+
output = capsys.readouterr().out
|
|
56
|
+
assert "deepseek" in output and "v0.2.0-rc.2" in output
|
|
57
|
+
assert "1/1 agent(s) available" in output
|
|
58
|
+
assert "deepseek-harness" not in output
|
|
59
|
+
execute.assert_not_called()
|
|
60
|
+
|
|
61
|
+
|
|
47
62
|
def test_check_quick_reports_installed_and_missing_agents(
|
|
48
63
|
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str],
|
|
49
64
|
) -> None:
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|