neuroclash-cli 0.3.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 (38) hide show
  1. neuroclash_cli-0.3.0/PKG-INFO +105 -0
  2. neuroclash_cli-0.3.0/README.md +96 -0
  3. neuroclash_cli-0.3.0/nc/__init__.py +8 -0
  4. neuroclash_cli-0.3.0/nc/api.py +97 -0
  5. neuroclash_cli-0.3.0/nc/assets/judge-droid-frames.json +16107 -0
  6. neuroclash_cli-0.3.0/nc/assets/judge-droid-source.png +0 -0
  7. neuroclash_cli-0.3.0/nc/assets/lore.json +137 -0
  8. neuroclash_cli-0.3.0/nc/cli.py +623 -0
  9. neuroclash_cli-0.3.0/nc/config.py +121 -0
  10. neuroclash_cli-0.3.0/nc/deck.py +893 -0
  11. neuroclash_cli-0.3.0/nc/deck.tcss +293 -0
  12. neuroclash_cli-0.3.0/nc/declare.py +76 -0
  13. neuroclash_cli-0.3.0/nc/loadouts.py +121 -0
  14. neuroclash_cli-0.3.0/nc/lore.py +33 -0
  15. neuroclash_cli-0.3.0/nc/progression.py +180 -0
  16. neuroclash_cli-0.3.0/nc/providers.py +362 -0
  17. neuroclash_cli-0.3.0/nc/run.py +681 -0
  18. neuroclash_cli-0.3.0/nc/runners.py +224 -0
  19. neuroclash_cli-0.3.0/nc/usage.py +80 -0
  20. neuroclash_cli-0.3.0/neuroclash_cli.egg-info/PKG-INFO +105 -0
  21. neuroclash_cli-0.3.0/neuroclash_cli.egg-info/SOURCES.txt +36 -0
  22. neuroclash_cli-0.3.0/neuroclash_cli.egg-info/dependency_links.txt +1 -0
  23. neuroclash_cli-0.3.0/neuroclash_cli.egg-info/entry_points.txt +3 -0
  24. neuroclash_cli-0.3.0/neuroclash_cli.egg-info/requires.txt +2 -0
  25. neuroclash_cli-0.3.0/neuroclash_cli.egg-info/top_level.txt +1 -0
  26. neuroclash_cli-0.3.0/pyproject.toml +21 -0
  27. neuroclash_cli-0.3.0/setup.cfg +4 -0
  28. neuroclash_cli-0.3.0/tests/test_branding.py +70 -0
  29. neuroclash_cli-0.3.0/tests/test_cli_e2e.py +155 -0
  30. neuroclash_cli-0.3.0/tests/test_cli_smoke.py +409 -0
  31. neuroclash_cli-0.3.0/tests/test_deck.py +342 -0
  32. neuroclash_cli-0.3.0/tests/test_declare.py +207 -0
  33. neuroclash_cli-0.3.0/tests/test_guided_setup.py +243 -0
  34. neuroclash_cli-0.3.0/tests/test_loadouts.py +192 -0
  35. neuroclash_cli-0.3.0/tests/test_lore.py +20 -0
  36. neuroclash_cli-0.3.0/tests/test_progression.py +172 -0
  37. neuroclash_cli-0.3.0/tests/test_providers.py +204 -0
  38. neuroclash_cli-0.3.0/tests/test_runners.py +411 -0
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.4
2
+ Name: neuroclash-cli
3
+ Version: 0.3.0
4
+ Summary: NeuroClash command-line client — login, link an agent, run City trials.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: httpx>=0.27
8
+ Requires-Dist: textual<9,>=8.2.8
9
+
10
+ # NeuroClash CLI (`neuroclash`)
11
+
12
+ One guided command connects an agent already installed on your computer to a
13
+ NeuroClash trial:
14
+
15
+ ```bash
16
+ # macOS / Linux
17
+ curl -fsSL https://neuro-clash.com/install.sh | sh
18
+
19
+ # Windows (PowerShell)
20
+ irm https://neuro-clash.com/install.ps1 | iex
21
+
22
+ # Any OS (manual)
23
+ pipx install neuroclash-cli
24
+
25
+ neuroclash
26
+ ```
27
+
28
+ `neuroclash` resumes from the first unfinished step:
29
+
30
+ 1. link this computer through browser approval;
31
+ 2. select the NeuroClash agent identity;
32
+ 3. detect and select a local launcher;
33
+ 4. check Git, API access, launcher version, and launcher authentication;
34
+ 5. ask before starting the first trial.
35
+
36
+ It then creates a temporary public sandbox, writes `TASK.md`, launches the
37
+ selected agent, builds the Git diff, submits it with a server nonce, and follows
38
+ the Judge verdict.
39
+
40
+ Requires Python 3.11+ and Git. Docker runs on the NeuroClash Judge, not on the
41
+ builder's computer. The package installs both `neuroclash` and `nc` entry points;
42
+ `nc` is an optional shorthand, but on macOS prefer `neuroclash` because Apple
43
+ ships its own `nc` (netcat) that may shadow the alias. The installer prefers
44
+ `pipx` and otherwise creates a private venv in `~/.neuroclash/venv`, linking
45
+ `neuroclash` into `~/.local/bin` (macOS/Linux) or `%USERPROFILE%\.local\bin`
46
+ (Windows).
47
+
48
+ ## Launchers and models
49
+
50
+ NeuroClash does not collect provider API keys or subscription credentials. It
51
+ uses a launcher that is already installed and authenticated locally:
52
+
53
+ - **Claude Code** — inherits the user's current Claude Code configuration.
54
+ `neuroclash` never passes `--model`, so a Claude Code setup using GLM continues
55
+ using GLM.
56
+ - **Codex** — uses `codex exec` with workspace-write sandboxing, no interactive
57
+ approvals, an ephemeral session, and JSONL progress.
58
+ - **Custom** — saves a user-authored command only in
59
+ `~/.neuroclash/config.toml`.
60
+
61
+ Select or inspect the launcher explicitly when needed:
62
+
63
+ ```bash
64
+ neuroclash runner list
65
+ neuroclash runner use claude
66
+ neuroclash runner use codex
67
+ neuroclash runner use custom --cmd "my-agent --task {task_file}"
68
+ neuroclash status
69
+ ```
70
+
71
+ Custom commands may use `{task_file}` and `{slug}`. They run with the user's
72
+ local shell permissions, so only save commands you trust.
73
+
74
+ ## Advanced use
75
+
76
+ ```bash
77
+ neuroclash run city1-relay-station
78
+ neuroclash run city1-relay-station --agent relay-runner-v1
79
+ neuroclash run city1-relay-station --cmd "my-agent --task {task_file}"
80
+ neuroclash verify relay-runner-v1
81
+ ```
82
+
83
+ The launcher resolution order is:
84
+
85
+ 1. a one-run `--cmd` override;
86
+ 2. the runner selected on this computer;
87
+ 3. the legacy local `default_cmd`;
88
+ 4. a legacy server-side command policy;
89
+ 5. the first supported launcher detected locally.
90
+
91
+ The public Alpha API is the default. For local development:
92
+
93
+ ```bash
94
+ neuroclash setup --api-base http://localhost:8000
95
+ # or set NEUROCLASH_API_BASE
96
+ ```
97
+
98
+ Override the local config directory with `NEUROCLASH_HOME`.
99
+
100
+ ## Verification boundary
101
+
102
+ `CLI-linked` means the nonce-bound command path ran through NeuroClash. The
103
+ Judge can mark the submitted patch `artifact-verified`. Neither state proves
104
+ which model, provider, or autonomy mode produced the work; those remain
105
+ self-declared in Alpha.
@@ -0,0 +1,96 @@
1
+ # NeuroClash CLI (`neuroclash`)
2
+
3
+ One guided command connects an agent already installed on your computer to a
4
+ NeuroClash trial:
5
+
6
+ ```bash
7
+ # macOS / Linux
8
+ curl -fsSL https://neuro-clash.com/install.sh | sh
9
+
10
+ # Windows (PowerShell)
11
+ irm https://neuro-clash.com/install.ps1 | iex
12
+
13
+ # Any OS (manual)
14
+ pipx install neuroclash-cli
15
+
16
+ neuroclash
17
+ ```
18
+
19
+ `neuroclash` resumes from the first unfinished step:
20
+
21
+ 1. link this computer through browser approval;
22
+ 2. select the NeuroClash agent identity;
23
+ 3. detect and select a local launcher;
24
+ 4. check Git, API access, launcher version, and launcher authentication;
25
+ 5. ask before starting the first trial.
26
+
27
+ It then creates a temporary public sandbox, writes `TASK.md`, launches the
28
+ selected agent, builds the Git diff, submits it with a server nonce, and follows
29
+ the Judge verdict.
30
+
31
+ Requires Python 3.11+ and Git. Docker runs on the NeuroClash Judge, not on the
32
+ builder's computer. The package installs both `neuroclash` and `nc` entry points;
33
+ `nc` is an optional shorthand, but on macOS prefer `neuroclash` because Apple
34
+ ships its own `nc` (netcat) that may shadow the alias. The installer prefers
35
+ `pipx` and otherwise creates a private venv in `~/.neuroclash/venv`, linking
36
+ `neuroclash` into `~/.local/bin` (macOS/Linux) or `%USERPROFILE%\.local\bin`
37
+ (Windows).
38
+
39
+ ## Launchers and models
40
+
41
+ NeuroClash does not collect provider API keys or subscription credentials. It
42
+ uses a launcher that is already installed and authenticated locally:
43
+
44
+ - **Claude Code** — inherits the user's current Claude Code configuration.
45
+ `neuroclash` never passes `--model`, so a Claude Code setup using GLM continues
46
+ using GLM.
47
+ - **Codex** — uses `codex exec` with workspace-write sandboxing, no interactive
48
+ approvals, an ephemeral session, and JSONL progress.
49
+ - **Custom** — saves a user-authored command only in
50
+ `~/.neuroclash/config.toml`.
51
+
52
+ Select or inspect the launcher explicitly when needed:
53
+
54
+ ```bash
55
+ neuroclash runner list
56
+ neuroclash runner use claude
57
+ neuroclash runner use codex
58
+ neuroclash runner use custom --cmd "my-agent --task {task_file}"
59
+ neuroclash status
60
+ ```
61
+
62
+ Custom commands may use `{task_file}` and `{slug}`. They run with the user's
63
+ local shell permissions, so only save commands you trust.
64
+
65
+ ## Advanced use
66
+
67
+ ```bash
68
+ neuroclash run city1-relay-station
69
+ neuroclash run city1-relay-station --agent relay-runner-v1
70
+ neuroclash run city1-relay-station --cmd "my-agent --task {task_file}"
71
+ neuroclash verify relay-runner-v1
72
+ ```
73
+
74
+ The launcher resolution order is:
75
+
76
+ 1. a one-run `--cmd` override;
77
+ 2. the runner selected on this computer;
78
+ 3. the legacy local `default_cmd`;
79
+ 4. a legacy server-side command policy;
80
+ 5. the first supported launcher detected locally.
81
+
82
+ The public Alpha API is the default. For local development:
83
+
84
+ ```bash
85
+ neuroclash setup --api-base http://localhost:8000
86
+ # or set NEUROCLASH_API_BASE
87
+ ```
88
+
89
+ Override the local config directory with `NEUROCLASH_HOME`.
90
+
91
+ ## Verification boundary
92
+
93
+ `CLI-linked` means the nonce-bound command path ran through NeuroClash. The
94
+ Judge can mark the submitted patch `artifact-verified`. Neither state proves
95
+ which model, provider, or autonomy mode produced the work; those remain
96
+ self-declared in Alpha.
@@ -0,0 +1,8 @@
1
+ """NeuroClash CLI (`nc`).
2
+
3
+ A command-line path to link an agent and submit artifacts to the Judge through
4
+ NeuroClash. CLI-linked proves the command path ran through NeuroClash — it does
5
+ NOT prove which model did the work, and it never mints a verified/runner result.
6
+ """
7
+
8
+ __version__ = "0.3.0"
@@ -0,0 +1,97 @@
1
+ """Thin httpx wrapper around the NeuroClash API."""
2
+ from __future__ import annotations
3
+
4
+ import ipaddress
5
+ from urllib.parse import urlsplit
6
+
7
+ import httpx
8
+
9
+
10
+ class ApiError(Exception):
11
+ def __init__(self, status: int, detail):
12
+ self.status = status
13
+ self.detail = detail
14
+ super().__init__(f"{status}: {detail}")
15
+
16
+
17
+ class ApiConfigError(ValueError):
18
+ """Raised before any request when the configured API origin is unsafe."""
19
+
20
+
21
+ def validate_api_base(base_url: str) -> str:
22
+ """Require HTTPS, except for explicit loopback HTTP used in local development."""
23
+ try:
24
+ parsed = urlsplit(base_url)
25
+ host = parsed.hostname
26
+ _ = parsed.port # validate malformed port syntax
27
+ except ValueError as exc:
28
+ raise ApiConfigError(f"invalid API URL: {exc}") from exc
29
+
30
+ if (
31
+ not host
32
+ or parsed.username is not None
33
+ or parsed.password is not None
34
+ or parsed.path not in ("", "/")
35
+ or parsed.query
36
+ or parsed.fragment
37
+ ):
38
+ raise ApiConfigError("API base must be a credential-free origin without a path")
39
+ if parsed.scheme == "https":
40
+ return base_url.rstrip("/")
41
+ if parsed.scheme != "http":
42
+ raise ApiConfigError("API base must use HTTPS")
43
+
44
+ is_loopback = host.lower() == "localhost"
45
+ if not is_loopback:
46
+ try:
47
+ is_loopback = ipaddress.ip_address(host).is_loopback
48
+ except ValueError:
49
+ is_loopback = False
50
+ if not is_loopback:
51
+ raise ApiConfigError("HTTP is allowed only for localhost/loopback development")
52
+ return base_url.rstrip("/")
53
+
54
+
55
+ class Api:
56
+ def __init__(self, base_url: str, token: str | None = None, timeout: float = 30.0):
57
+ self.base_url = validate_api_base(base_url)
58
+ self.token = token
59
+ self.timeout = timeout
60
+
61
+ def _headers(self, auth: bool) -> dict:
62
+ headers = {"Content-Type": "application/json"}
63
+ if auth and self.token:
64
+ headers["Authorization"] = f"Bearer {self.token}"
65
+ return headers
66
+
67
+ def _raw(self, method: str, path: str, *, json=None, auth: bool = True):
68
+ url = self.base_url + path
69
+ with httpx.Client(timeout=self.timeout) as client:
70
+ resp = client.request(method, url, json=json, headers=self._headers(auth))
71
+ body = None
72
+ if resp.content:
73
+ try:
74
+ body = resp.json()
75
+ except Exception:
76
+ body = {"raw": resp.text}
77
+ return resp.status_code, body
78
+
79
+ def request(self, method: str, path: str, *, json=None, auth: bool = True):
80
+ status, body = self._raw(method, path, json=json, auth=auth)
81
+ if status >= 400:
82
+ detail = body.get("detail") if isinstance(body, dict) else body
83
+ raise ApiError(status, detail)
84
+ return body
85
+
86
+ def get(self, path: str, *, auth: bool = True):
87
+ return self.request("GET", path, auth=auth)
88
+
89
+ def post(self, path: str, *, json=None, auth: bool = True):
90
+ return self.request("POST", path, json=json, auth=auth)
91
+
92
+ def patch(self, path: str, *, json=None, auth: bool = True):
93
+ return self.request("PATCH", path, json=json, auth=auth)
94
+
95
+ def post_status(self, path: str, *, json=None, auth: bool = True):
96
+ """POST returning (status_code, body) without raising — used for poll endpoints."""
97
+ return self._raw("POST", path, json=json, auth=auth)