forgexa-cli 1.60.0__tar.gz → 1.61.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.60.0 → forgexa_cli-1.61.0}/PKG-INFO +2 -2
  2. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/README.md +1 -1
  3. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/__init__.py +1 -1
  4. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/agent_core.py +32 -3
  5. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/daemon.py +17 -13
  6. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/main.py +5 -4
  7. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli.egg-info/PKG-INFO +2 -2
  8. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/pyproject.toml +1 -1
  9. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_check_command.py +17 -2
  10. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/_build_config.py +0 -0
  11. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/_local_bind.py +0 -0
  12. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/autoupgrade.py +0 -0
  13. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/py.typed +0 -0
  14. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/runtime_evidence.py +0 -0
  15. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli/zcode_protocol.py +0 -0
  16. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  17. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  18. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli.egg-info/entry_points.txt +0 -0
  19. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli.egg-info/requires.txt +0 -0
  20. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/forgexa_cli.egg-info/top_level.txt +0 -0
  21. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/setup.cfg +0 -0
  22. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_auth_and_runtime_commands.py +0 -0
  23. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_autoupgrade.py +0 -0
  24. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_expiry_warnings_and_revoke.py +0 -0
  25. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_local_bind_commands.py +0 -0
  26. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_runtime_credentials.py +0 -0
  27. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_session_credentials.py +0 -0
  28. {forgexa_cli-1.60.0 → forgexa_cli-1.61.0}/tests/test_silent_install.py +0 -0
  29. {forgexa_cli-1.60.0 → forgexa_cli-1.61.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.60.0
3
+ Version: 1.61.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** 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).
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-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).
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.0"
2
+ __version__ = "1.61.0"
@@ -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-harness": {
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-harness`"
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
- if agent_id == "deepseek-harness":
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.0"
1199
+ DAEMON_VERSION = "1.61.0"
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-harness":
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-harness" else self._detect_agent_output_failure(result, agent.agent_id)
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-harness": "npm i -g @deepseek-ai/dsh@0.2.0-rc.2",
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-harness",
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-harness",
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-harness": "npm i -g @deepseek-ai/dsh@0.2.0-rc.2",
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-harness":
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.0
3
+ Version: 1.61.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** 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).
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
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "forgexa-cli"
3
- version = "1.60.0"
3
+ version = "1.61.0"
4
4
  description = "Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform"
5
5
  requires-python = ">=3.9"
6
6
  license = "MIT"
@@ -30,7 +30,8 @@ def _agent(agent_id: str, version: str = "1.0.0") -> daemon.DiscoveredAgent:
30
30
  )
31
31
 
32
32
 
33
- def test_deepseek_harness_live_approval_is_build_scoped(tmp_path, monkeypatch, capsys):
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="deepseek-harness", binary="/fake/dsh"))
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