cloudagent-daemon 0.4.0__tar.gz → 0.4.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.
Files changed (90) hide show
  1. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/PKG-INFO +1 -1
  2. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/pyproject.toml +1 -1
  3. cloudagent_daemon-0.4.1/src/cloudagent_daemon/__init__.py +1 -0
  4. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/runtime_detect.py +7 -0
  5. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_runtime_detect.py +41 -0
  6. cloudagent_daemon-0.4.0/src/cloudagent_daemon/__init__.py +0 -1
  7. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/.gitignore +0 -0
  8. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/LICENSE +0 -0
  9. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/README.md +0 -0
  10. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/__main__.py +0 -0
  11. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/agent_upload.py +0 -0
  12. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/agent_upload_denylist.py +0 -0
  13. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/claude_runner.py +0 -0
  14. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/cli.py +0 -0
  15. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/config.py +0 -0
  16. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/context_fetch.py +0 -0
  17. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/delegation_report.py +0 -0
  18. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/doctor.py +0 -0
  19. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/frame_dispatch.py +0 -0
  20. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/http_outbound.py +0 -0
  21. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/injection_state.py +0 -0
  22. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/jsonl_logging.py +0 -0
  23. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/login.py +0 -0
  24. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/main_loop.py +0 -0
  25. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/mcp_bridge.py +0 -0
  26. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/metrics.py +0 -0
  27. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/metrics_server.py +0 -0
  28. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/outbound_queue.py +0 -0
  29. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/paths.py +0 -0
  30. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/protocol.py +0 -0
  31. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/readonly_bash_guard.py +0 -0
  32. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/service.py +0 -0
  33. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/spawn_outbox.py +0 -0
  34. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/spawn_queue.py +0 -0
  35. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/sse_client.py +0 -0
  36. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/transport.py +0 -0
  37. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/unix_socket.py +0 -0
  38. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/workspace.py +0 -0
  39. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/src/cloudagent_daemon/ws_client.py +0 -0
  40. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/__init__.py +0 -0
  41. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/_fake_sse_server.py +0 -0
  42. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/conftest.py +0 -0
  43. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_e2e_deliver_to_spawn.py +0 -0
  44. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_e2e_sse.py +0 -0
  45. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_full_e2e.py +0 -0
  46. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_mcp_bridge_round_trip.py +0 -0
  47. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_one_shot_cli.py +0 -0
  48. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_spawn_mcp_bridge_e2e.py +0 -0
  49. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_sse_handshake.py +0 -0
  50. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_sse_watchdog.py +0 -0
  51. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_ws_handshake.py +0 -0
  52. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/integration/test_ws_reconnect.py +0 -0
  53. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/conftest.py +0 -0
  54. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_agent_upload.py +0 -0
  55. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_claude_runner.py +0 -0
  56. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_claude_runner_codex_contract.py +0 -0
  57. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_claude_runner_routing_contract.py +0 -0
  58. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_claude_runner_w3.py +0 -0
  59. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_cli_multi_profile.py +0 -0
  60. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_cli_smoke.py +0 -0
  61. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_config.py +0 -0
  62. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_context_fetch.py +0 -0
  63. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_delegation_report.py +0 -0
  64. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_doctor.py +0 -0
  65. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_frame_dispatch.py +0 -0
  66. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_http_outbound.py +0 -0
  67. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_injection_state.py +0 -0
  68. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_jsonl_logging.py +0 -0
  69. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_login.py +0 -0
  70. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_main_loop_assign.py +0 -0
  71. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_mcp_bridge_agent_retrieval.py +0 -0
  72. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_mcp_bridge_send_message.py +0 -0
  73. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_metrics.py +0 -0
  74. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_metrics_server.py +0 -0
  75. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_multi_tool_wake.py +0 -0
  76. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_outbound_queue.py +0 -0
  77. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_outbox_stuck_watchdog.py +0 -0
  78. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_paths.py +0 -0
  79. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_protocol.py +0 -0
  80. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_readonly_bash_guard.py +0 -0
  81. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_service.py +0 -0
  82. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_service_multi_profile.py +0 -0
  83. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_spawn_outbox.py +0 -0
  84. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_spawn_queue.py +0 -0
  85. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_sse_active_watchdog.py +0 -0
  86. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_status_stop.py +0 -0
  87. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_workspace.py +0 -0
  88. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_workspace_root_task113.py +0 -0
  89. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/tests/unit/test_ws_client_insecure.py +0 -0
  90. {cloudagent_daemon-0.4.0 → cloudagent_daemon-0.4.1}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudagent-daemon
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Local daemon for cloudagent — bridges Claude Code subprocesses to the cloudagent backend over WebSocket.
5
5
  Project-URL: Homepage, https://cloudagent.chat
6
6
  Project-URL: Repository, https://codeup.aliyun.com/69bd0a4d29ad98af4065ce71/cloudagent
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cloudagent-daemon"
7
- version = "0.4.0"
7
+ version = "0.4.1"
8
8
  description = "Local daemon for cloudagent — bridges Claude Code subprocesses to the cloudagent backend over WebSocket."
9
9
  authors = [{name = "chaoyin", email = "tudoucyx@gmail.com"}]
10
10
  readme = "README.md"
@@ -0,0 +1 @@
1
+ __version__ = "0.4.1"
@@ -123,6 +123,13 @@ def _capture_version(binary: str, args: list[str], timeout: float) -> str:
123
123
  )
124
124
  except (subprocess.TimeoutExpired, OSError):
125
125
  return "unknown"
126
+ # 2026-07-23 (macpro Dex 排查) — 探针失败必须归 "unknown",不能把报错行
127
+ # 当版本:残缺的 nvm codex `--version` 以 rc=1 打出
128
+ # "Error: spawn ~/.nvm/versions/node/v22.22.2/lib/...",_version_sort_key
129
+ # 抽出路径里的 (22,22,2) 反而压过真 codex 的 (0,145,0),坏安装胜出、
130
+ # agent spawn 秒崩。退出码非零 = 不是可用的版本行。
131
+ if r.returncode != 0:
132
+ return "unknown"
126
133
  out = (r.stdout or "") + (r.stderr or "")
127
134
  first_line = out.strip().splitlines()[0] if out.strip() else ""
128
135
  return first_line[:64] if first_line else "unknown"
@@ -273,3 +273,44 @@ class TestDetectRuntimes:
273
273
  codex = next(r for r in result if r.name == "codex")
274
274
  assert codex.version.startswith("v0.0.15")
275
275
  assert str(new_node) in codex.binary
276
+
277
+
278
+ class TestBrokenInstallNeverWins:
279
+ """2026-07-23 macpro Dex 排查回归:残缺安装的报错行不得冒充版本。
280
+
281
+ 现场:nvm 里残缺的 codex `--version` 以 rc=1 打出
282
+ "Error: spawn ~/.nvm/versions/node/v22.22.2/lib/..."——
283
+ _version_sort_key 抽出 (22,22,2) 压过真 codex 的 (0,145,0),
284
+ 坏安装胜出、agent spawn 秒崩。rc!=0 必须归 "unknown"。
285
+ """
286
+
287
+ def test_nonzero_exit_probe_is_unknown(self, tmp_path, monkeypatch):
288
+ FakeBinary.write(
289
+ tmp_path, "codex",
290
+ stdout="Error: spawn /x/.nvm/versions/node/v22.22.2/lib/node",
291
+ exit_code=1,
292
+ )
293
+ monkeypatch.setattr("cloudagent_daemon.runtime_detect.shutil.which", lambda _: None)
294
+ monkeypatch.setenv("PATH", str(tmp_path))
295
+ result = detect_runtimes()
296
+ codex = [r for r in result if r.name == "codex"]
297
+ assert len(codex) == 1
298
+ assert codex[0].version == "unknown"
299
+
300
+ def test_healthy_low_version_beats_broken_high_digits(self, tmp_path, monkeypatch):
301
+ good_dir = tmp_path / "good"; good_dir.mkdir()
302
+ bad_dir = tmp_path / "bad"; bad_dir.mkdir()
303
+ FakeBinary.write(good_dir, "codex", stdout="codex-cli 0.145.0", exit_code=0)
304
+ FakeBinary.write(
305
+ bad_dir, "codex",
306
+ stdout="Error: spawn /x/.nvm/versions/node/v22.22.2/lib/node",
307
+ exit_code=1,
308
+ )
309
+ monkeypatch.setattr("cloudagent_daemon.runtime_detect.shutil.which", lambda _: None)
310
+ # 坏的排 PATH 前面 —— 修复后仍必须选到好的那份
311
+ monkeypatch.setenv("PATH", f"{bad_dir}{os.pathsep}{good_dir}")
312
+ result = detect_runtimes()
313
+ codex = [r for r in result if r.name == "codex"]
314
+ assert len(codex) == 1
315
+ assert codex[0].version.startswith("codex-cli 0.145.0")
316
+ assert str(good_dir) in codex[0].binary
@@ -1 +0,0 @@
1
- __version__ = "0.4.0"