hx-cli 0.2.11__tar.gz → 0.2.14__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.
- {hx_cli-0.2.11 → hx_cli-0.2.14}/CHANGELOG.md +107 -1
- {hx_cli-0.2.11 → hx_cli-0.2.14}/PKG-INFO +80 -15
- {hx_cli-0.2.11 → hx_cli-0.2.14}/README.md +78 -14
- {hx_cli-0.2.11 → hx_cli-0.2.14}/pyproject.toml +3 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/__init__.py +1 -1
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/agents/subagent.py +8 -1
- hx_cli-0.2.14/src/hx/auth/claude_code.py +369 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/resolve.py +45 -1
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/cli.py +53 -31
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/loop.py +70 -18
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/session.py +18 -5
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/title.py +14 -1
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/net.py +62 -6
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/base.py +5 -0
- hx_cli-0.2.14/src/hx/providers/claude_code.py +972 -0
- hx_cli-0.2.14/src/hx/providers/claude_code_catalogue.py +276 -0
- hx_cli-0.2.14/src/hx/providers/claude_code_cli.py +414 -0
- hx_cli-0.2.14/src/hx/providers/claude_code_transcript.py +433 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/codex.py +1 -1
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/models.py +298 -33
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/registry.py +41 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/glob.py +25 -6
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/app.py +4 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/commands.py +102 -37
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/runtime.py +64 -11
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/pickers.py +101 -14
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/status.py +17 -6
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/conftest.py +117 -1
- hx_cli-0.2.14/tests/e2e/fake_claude.py +585 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/stub.py +58 -3
- hx_cli-0.2.14/tests/e2e/test_claude_code.py +1299 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/test_commands.py +305 -2
- hx_cli-0.2.14/tests/e2e/test_queue.py +156 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/test_tools.py +27 -0
- hx_cli-0.2.14/tests/test_live_claude_code.py +350 -0
- hx_cli-0.2.14/tests/tls_proxy.py +222 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/uv.lock +191 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/.github/workflows/ci.yml +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/.gitignore +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/examples/hooks/check.sh +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/install.sh +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/agents/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/agents/definitions.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/oauth/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/oauth/browser.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/oauth/callback.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/oauth/codex.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/oauth/devin.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/oauth/pkce.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/auth/store.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/config.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/checkpoints.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/compaction.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/context.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/events.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/images.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/lateinject.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/messages.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/core/usage.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/docs.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/frontmatter.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/git.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/hooks/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/hooks/engine.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/hooks/spec.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/keys.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/mcp/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/mcp/client.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/mcp/manager.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/mcp/oauth.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/paths.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/permissions/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/permissions/engine.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/permissions/parser.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/permissions/sandbox.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/codex_catalogue.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/devin.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/devin_catalogue.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/devin_wire.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/openrouter.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/protowire.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/providers/responses_codec.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/skills/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/skills/loader.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/skills/runtime.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/ansi.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/buffer.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/component.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/demo.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/editor.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/keydecode.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/loop.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/markdown.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/modifiers.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/primitives.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/sanitize.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/screen.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/syntax.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/terminal.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/undo.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/width.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/term/word_nav.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/anchors.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/base.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/bash.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/edit.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/grep.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/output.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/read.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/registry.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/symbols.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/task.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/todo.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/websearch.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tools/write.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/trace.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/clipboard.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/format.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/fuzzy.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/glyphs.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/killring.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/limits.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/paint.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/renderers.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/roles.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/theme.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/theme_json.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/themes/ansi.json +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/themes/dark.json +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/themes/light.json +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/blocks.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/dialog.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/login.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/permission.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/prompt.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/src/hx/tui/views/transcript.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/conftest.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/__init__.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/fixtures/echo_server.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/report.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/terminal.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/test_chat.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/test_cli.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/test_extend.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/test_input.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/e2e/test_print.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/test_live.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/test_live_codex.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/test_live_devin.py +0 -0
- {hx_cli-0.2.11 → hx_cli-0.2.14}/tests/test_live_tavily.py +0 -0
|
@@ -28,6 +28,109 @@ the project follows [semantic versioning](https://semver.org/).
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
+
## [0.2.14] - 2026-10-04
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- When the installed Claude Code is behind its current release - and so lists older Claude
|
|
36
|
+
models than your subscription can run - `/model` says so under the list, with the command
|
|
37
|
+
that updates it (`brew upgrade --cask claude-code` for a Homebrew install, otherwise
|
|
38
|
+
`claude update`). After updating, the next `/model` lists the new models; no
|
|
39
|
+
refresh needed.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- The model catalogue is refreshed from inside the `/model` picker: press `ctrl+r`. The
|
|
44
|
+
list updates in place and keeps your filter and selection; the outcome, or why the refresh
|
|
45
|
+
failed, shows under the list. With no models at all, `/model` now opens anyway and says
|
|
46
|
+
so, so `ctrl+r` is there to fill it.
|
|
47
|
+
|
|
48
|
+
### Removed
|
|
49
|
+
|
|
50
|
+
- `/models refresh`. It sat one letter away from `/model` and did nothing without its one
|
|
51
|
+
argument; use `ctrl+r` in the `/model` picker.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- On the `claude-code` route, the context window is the one Claude Code reports, not a
|
|
56
|
+
200k guess: Opus 5.5 runs with 1M. Claude Code lists its models without their sizes, and
|
|
57
|
+
what it serves depends on the plan, so a model starts at the window it was measured
|
|
58
|
+
serving on every plan - 1M for Opus 5.5, Sonnet 5.5, Sonnet 5 and Opus 4.7, 200k
|
|
59
|
+
otherwise - until its first turn reports the real window and maximum output for your
|
|
60
|
+
account. From then on the context gauge, the compaction threshold, the `/model` picker
|
|
61
|
+
and later sessions all use it, and a catalogue refresh keeps it.
|
|
62
|
+
- A model Claude Code lists at its long context - Fable 5.1 as `claude-fable-5-1[1m]` -
|
|
63
|
+
runs at it: `/model` offers `claude-code/claude-fable-5-1[1m]` at 1M, where HX used to
|
|
64
|
+
drop the `[1m]` and run the model at its standard context.
|
|
65
|
+
- A turn refused because the model, or its 1M context, needs usage credits your Claude plan
|
|
66
|
+
has off no longer reads "usage limit is reached. It resets at ...": HX says what needs the
|
|
67
|
+
credits, where to turn them on, and which model runs without them. Once they are on, the
|
|
68
|
+
next turn runs.
|
|
69
|
+
- After a catalogue refresh (`ctrl+r` in `/model`, or signing in), the session in progress
|
|
70
|
+
measures its context against the refreshed window, not the one it started with.
|
|
71
|
+
- `/model anthropic` (or typing `anthropic` in the picker) lists the Claude models your Claude
|
|
72
|
+
Code subscription runs, first, ahead of the per-token OpenRouter ones; `openai` does the same
|
|
73
|
+
for Codex. Several words match in any order: `/model anthropic sonnet`.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## [0.2.13] - 2026-10-04
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- Claude Pro/Max route: `hx auth login claude-code`, then
|
|
82
|
+
`hx --model claude-code/claude-sonnet-5`. Runs Claude models on your Claude
|
|
83
|
+
subscription through the official Claude Code CLI, with HX's own tools,
|
|
84
|
+
approvals and transcript. `/model` lists the account's models and `/effort`
|
|
85
|
+
their levels.
|
|
86
|
+
- Behind a TLS-inspecting proxy the `claude-code` route takes the same
|
|
87
|
+
settings as every other route: `HX_CA_BUNDLE` reaches Claude Code as
|
|
88
|
+
`NODE_EXTRA_CA_CERTS` and `HX_SSL_NO_VERIFY` as
|
|
89
|
+
`NODE_TLS_REJECT_UNAUTHORIZED=0`, Claude Code's own `CLAUDE_CODE_CERT_STORE`
|
|
90
|
+
and `CLAUDE_CODE_CLIENT_CERT` / `_KEY` / `_KEY_PASSPHRASE` (for a network
|
|
91
|
+
that requires a client certificate) pass through, and a certificate failure
|
|
92
|
+
it reports names the fix.
|
|
93
|
+
- On the `claude-code` route, a turn Anthropic bills as Extra Usage while
|
|
94
|
+
your plan still has room says so, and names HX's part of the system prompt,
|
|
95
|
+
instead of claiming the plan's usage limit is reached. A turn whose prompt
|
|
96
|
+
carries HX's own system prompt text (a copied `system-prompt.md`, an
|
|
97
|
+
AGENTS.md, an agent definition) is refused before it is sent, naming where
|
|
98
|
+
the text is; `hx prompt` shows the sources.
|
|
99
|
+
|
|
100
|
+
### Fixed
|
|
101
|
+
|
|
102
|
+
- A subagent that fails - a provider error, a refused prompt, the turn limit -
|
|
103
|
+
reports why to the parent model, instead of "(the subagent returned no
|
|
104
|
+
text)".
|
|
105
|
+
- `Glob` with a pattern of `.` or `./` returns an error saying to use `*` or
|
|
106
|
+
`**/*`, and an absolute pattern one naming the `path` and relative pattern
|
|
107
|
+
to send instead, on every Python version, instead of a Python exception.
|
|
108
|
+
- With `tui.enterWhileBusy` set to `"steer"`, `alt+enter` queues a message
|
|
109
|
+
behind the running turn, as the prompt says. It used to steer like `enter`,
|
|
110
|
+
leaving no way to queue in that mode.
|
|
111
|
+
- The status bar's `⧗N queued` count stays visible in a project with a long
|
|
112
|
+
path or branch name; the path is shortened instead of the count being cut off.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## [0.2.12] - 2026-10-01
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
|
|
120
|
+
- `/exit` and `ctrl+d` return the shell at once. They used to wait up to 10
|
|
121
|
+
seconds on a model call renaming the session; sessions are no longer renamed
|
|
122
|
+
on the way out, in the TUI or with `hx -p`.
|
|
123
|
+
- A name set with `/title` is no longer replaced by a generated one, including
|
|
124
|
+
one that was still being generated when you set it.
|
|
125
|
+
- The session name is generated from the opening and the latest stretch of the
|
|
126
|
+
conversation, not only its first 2000 characters.
|
|
127
|
+
- A session left before its first name came back is named from your first
|
|
128
|
+
message, instead of being listed by `/resume` with no name.
|
|
129
|
+
- A session left with `/resume` into another directory is renamed for what it
|
|
130
|
+
became, by the HX that starts there, in the background.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
31
134
|
## [0.2.11] - 2026-10-01
|
|
32
135
|
|
|
33
136
|
### Fixed
|
|
@@ -776,7 +879,10 @@ First release, published to PyPI as [`hx-cli`](https://pypi.org/project/hx-cli/)
|
|
|
776
879
|
- `/configure` and `hx auth` for the OpenRouter key, `hx upgrade` for
|
|
777
880
|
self-update, and `install.sh` bootstrapping uv with a pinned Python.
|
|
778
881
|
|
|
779
|
-
[Unreleased]: https://github.com/aletisunil/hx/compare/v0.2.
|
|
882
|
+
[Unreleased]: https://github.com/aletisunil/hx/compare/v0.2.14...HEAD
|
|
883
|
+
[0.2.14]: https://github.com/aletisunil/hx/compare/v0.2.13...v0.2.14
|
|
884
|
+
[0.2.13]: https://github.com/aletisunil/hx/compare/v0.2.12...v0.2.13
|
|
885
|
+
[0.2.12]: https://github.com/aletisunil/hx/compare/v0.2.11...v0.2.12
|
|
780
886
|
[0.2.11]: https://github.com/aletisunil/hx/compare/v0.2.10...v0.2.11
|
|
781
887
|
[0.2.10]: https://github.com/aletisunil/hx/compare/v0.2.9...v0.2.10
|
|
782
888
|
[0.2.9]: https://github.com/aletisunil/hx/compare/v0.2.8...v0.2.9
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hx-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.14
|
|
4
4
|
Summary: HX - an agent harness for the terminal
|
|
5
5
|
Project-URL: Homepage, https://hx.sunilaleti.dev
|
|
6
6
|
Project-URL: Documentation, https://hx.sunilaleti.dev
|
|
@@ -31,6 +31,7 @@ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
|
31
31
|
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
32
32
|
Requires-Dist: pytest>=8.2; extra == 'dev'
|
|
33
33
|
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
34
|
+
Requires-Dist: trustme>=1.2; extra == 'dev'
|
|
34
35
|
Requires-Dist: types-pygments; extra == 'dev'
|
|
35
36
|
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
36
37
|
Provides-Extra: symbols
|
|
@@ -90,7 +91,7 @@ Requires Python 3.11+. macOS and Linux. Update with `hx upgrade`.
|
|
|
90
91
|
|
|
91
92
|
### Credentials
|
|
92
93
|
|
|
93
|
-
HX reaches models over
|
|
94
|
+
HX reaches models over four routes. Which one serves a turn is decided by the
|
|
94
95
|
model id alone, so "what paid for that" is always answerable by reading it:
|
|
95
96
|
|
|
96
97
|
| Model id | Route | Billing |
|
|
@@ -98,8 +99,10 @@ model id alone, so "what paid for that" is always answerable by reading it:
|
|
|
98
99
|
| `anthropic/claude-sonnet-4.5`, `openai/gpt-5`, … | OpenRouter | per token, API key |
|
|
99
100
|
| `openai-codex/gpt-5.6-terra` | ChatGPT Plus/Pro | your subscription |
|
|
100
101
|
| `devin/swe-1-6`, `devin/claude-opus-5`, … | Devin | your subscription |
|
|
102
|
+
| `claude-code/claude-sonnet-5`, `claude-code/claude-opus-4-8`, … | Claude Pro/Max, via Claude Code | your subscription |
|
|
101
103
|
|
|
102
|
-
Credentials live in `~/.hx/auth.json`, mode 0600, one entry per route
|
|
104
|
+
Credentials live in `~/.hx/auth.json`, mode 0600, one entry per route - except
|
|
105
|
+
Claude Code's, which stays with Claude Code.
|
|
103
106
|
|
|
104
107
|
**OpenRouter.** On first run HX asks for a key. Get one at
|
|
105
108
|
<https://openrouter.ai/keys>. Change it later with `/configure` in the TUI, or:
|
|
@@ -153,7 +156,7 @@ reach it at all.
|
|
|
153
156
|
|
|
154
157
|
**Which Codex models you get** is decided by your ChatGPT account, not by HX.
|
|
155
158
|
Signing in fetches the account's own list from the Codex backend, and `/model`
|
|
156
|
-
offers exactly that; `/
|
|
159
|
+
offers exactly that; ctrl+r in `/model` asks again. Entitlement is per model -
|
|
157
160
|
the same `plus` account can run `gpt-5.6-sol` and be refused `gpt-5.3-codex` —
|
|
158
161
|
so a model the picker does not list is one the subscription does not cover.
|
|
159
162
|
|
|
@@ -215,7 +218,7 @@ you to sign in again. On a machine with no browser at all, a session token in
|
|
|
215
218
|
`HX_DEVIN_API_KEY` or `DEVIN_API_KEY` is used when nothing is saved.
|
|
216
219
|
|
|
217
220
|
Signing in fetches the account's own model list, and `/model` offers exactly
|
|
218
|
-
that; `/
|
|
221
|
+
that; ctrl+r in `/model` asks again. Devin publishes each reasoning depth as a
|
|
219
222
|
model of its own - Claude Opus 5 High, Claude Opus 5 Max - and HX folds each
|
|
220
223
|
family into one model, so `/effort` picks the depth on Devin exactly as it does
|
|
221
224
|
on Codex. A fast lane or a 1M-context lane stays a separate model, since it
|
|
@@ -223,6 +226,54 @@ changes what a turn costs or how much fits. Router models such as
|
|
|
223
226
|
`devin/adaptive` are resolved to a concrete model on every turn by Devin itself.
|
|
224
227
|
If the list cannot be fetched, `devin/swe-1-6` and `devin/swe-1-6-fast` stand in.
|
|
225
228
|
|
|
229
|
+
**Claude Pro/Max.** HX runs Claude models on your Claude subscription through
|
|
230
|
+
the official [Claude Code](https://claude.com/claude-code) CLI, the way the
|
|
231
|
+
Claude Agent SDK does. Install Claude Code, then:
|
|
232
|
+
|
|
233
|
+
```sh
|
|
234
|
+
hx auth login claude-code # Claude Code's own sign-in; or /login inside HX
|
|
235
|
+
hx --model claude-code/claude-sonnet-5
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
HX holds no Claude token. The login is Claude Code's, kept and refreshed where
|
|
239
|
+
Claude Code keeps it, so `hx auth logout claude-code` only tells you to run
|
|
240
|
+
`claude auth logout` - which signs out every Claude Code on the machine. A
|
|
241
|
+
headless machine can use a token from `claude setup-token` in
|
|
242
|
+
`CLAUDE_CODE_OAUTH_TOKEN`. A Console login (`claude auth login --console`) bills
|
|
243
|
+
per token and is refused: this route is the subscription.
|
|
244
|
+
|
|
245
|
+
How a turn works: HX starts `claude -p` with every one of Claude Code's own
|
|
246
|
+
tools switched off and serves HX's tools to it as an MCP server. The model's
|
|
247
|
+
tool calls are run, permission-checked and drawn by HX exactly as on every
|
|
248
|
+
other route; Claude Code holds each call open until HX answers it, however long
|
|
249
|
+
an approval takes. The system prompt is Claude Code's, with your AGENTS.md
|
|
250
|
+
files, skills index and `--append-system-prompt` text added. One Claude Code
|
|
251
|
+
process serves a conversation for as long as it can, so the prompt cache
|
|
252
|
+
carries from turn to turn; after an interrupt, a steer while a tool runs, a
|
|
253
|
+
compaction, `/model`, `/effort` or a resumed session, HX starts a new one on a
|
|
254
|
+
session rebuilt from its own transcript. That costs a second or so and a
|
|
255
|
+
partly cold cache, not the conversation.
|
|
256
|
+
|
|
257
|
+
Claude Code is started isolated from your Claude Code setup: no CLAUDE.md, no
|
|
258
|
+
hooks, no plugins or MCP servers from `~/.claude`, no auto-memory, no
|
|
259
|
+
auto-compaction (HX compacts its own transcript), and nothing saved to Claude
|
|
260
|
+
Code's session list. Variables that would move it off the subscription -
|
|
261
|
+
`ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`, `CLAUDE_CODE_USE_BEDROCK` and the
|
|
262
|
+
rest - are removed from its environment; its TLS settings are kept (see
|
|
263
|
+
*Behind a TLS-inspecting proxy* below). `HX_CLAUDE_CODE_PATH` points HX at a
|
|
264
|
+
`claude` other than the one on `PATH`.
|
|
265
|
+
|
|
266
|
+
`/model` offers the models Claude Code lists for the account, each with the
|
|
267
|
+
efforts it accepts for `/effort`; ctrl+r in `/model` asks again. A model Claude
|
|
268
|
+
Code runs at its long context keeps `[1m]` in its id
|
|
269
|
+
(`claude-code/claude-fable-5-1[1m]`), exactly as Claude Code's own `/model` runs
|
|
270
|
+
it. Claude Code lists no context sizes, so a model starts at the window it was
|
|
271
|
+
measured serving on every plan - 1M for Opus 5.5, Sonnet 5.5, Sonnet 5 and Opus
|
|
272
|
+
4.7, otherwise 200k - and from its first turn uses the window Claude Code
|
|
273
|
+
reports for your account. When a usage limit is reached, HX says which one and
|
|
274
|
+
when it resets; when a model or its 1M context needs usage credits your plan
|
|
275
|
+
has off, HX says that instead, and what to pick without them.
|
|
276
|
+
|
|
226
277
|
**Web search.** Optional, and the one credential that is not a model route.
|
|
227
278
|
It powers two tools:
|
|
228
279
|
|
|
@@ -232,7 +283,7 @@ It powers two tools:
|
|
|
232
283
|
| `WebFetch` | read up to 5 URLs, returned as markdown |
|
|
233
284
|
|
|
234
285
|
[Tavily](https://app.tavily.com) bills per search rather than per token, so it
|
|
235
|
-
works identically on
|
|
286
|
+
works identically on every route - including the subscription ones,
|
|
236
287
|
where a provider-native search tool is not on offer.
|
|
237
288
|
|
|
238
289
|
Get a key at <https://app.tavily.com> — the free tier is 1000 searches a month
|
|
@@ -286,9 +337,18 @@ startup every session, because it is not a fix. A TLS failure is reported in
|
|
|
286
337
|
one line - `/model` and the startup notice both name the certificate problem
|
|
287
338
|
rather than reporting an empty catalogue with no cause.
|
|
288
339
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
340
|
+
The same settings cover the `claude-code` route, whose requests Claude Code
|
|
341
|
+
makes with its own TLS stack: HX passes `HX_CA_BUNDLE` on to it as
|
|
342
|
+
`NODE_EXTRA_CA_CERTS` (unless you already set that yourself), and
|
|
343
|
+
`HX_SSL_NO_VERIFY` as `NODE_TLS_REJECT_UNAUTHORIZED=0`. Claude Code reads the
|
|
344
|
+
OS trust store on its own, and its own TLS settings reach it untouched:
|
|
345
|
+
`CLAUDE_CODE_CERT_STORE`, and `CLAUDE_CODE_CLIENT_CERT`,
|
|
346
|
+
`CLAUDE_CODE_CLIENT_KEY` and `CLAUDE_CODE_CLIENT_KEY_PASSPHRASE` for a network
|
|
347
|
+
that requires a client certificate.
|
|
348
|
+
|
|
349
|
+
HX never sends a Claude subscription token to the API itself - Anthropic
|
|
350
|
+
accepts those only from Claude Code, and HX will not impersonate it. The
|
|
351
|
+
`claude-code` route runs the real Claude Code instead.
|
|
292
352
|
|
|
293
353
|
---
|
|
294
354
|
|
|
@@ -314,7 +374,7 @@ hx mcp list|add|remove # manage MCP servers
|
|
|
314
374
|
hx mcp login <server> # sign in to a remote MCP server in the browser
|
|
315
375
|
hx mcp logout <server> # forget a remote MCP server's sign-in
|
|
316
376
|
hx auth [set|clear] # manage the OpenRouter key
|
|
317
|
-
hx auth login [provider] # sign in (openrouter, openai-codex, devin)
|
|
377
|
+
hx auth login [provider] # sign in (openrouter, openai-codex, devin, claude-code)
|
|
318
378
|
hx auth logout <provider> # forget a stored credential
|
|
319
379
|
hx docs [section] # the manual; no argument lists its sections
|
|
320
380
|
hx changelog [version] # what shipped in each version
|
|
@@ -368,7 +428,7 @@ be rebound (see [Keybindings](#keybindings)).
|
|
|
368
428
|
| `ctrl+d` | exit, when the prompt is empty |
|
|
369
429
|
| `shift+tab` | cycle permission mode |
|
|
370
430
|
| `ctrl+p` | command palette |
|
|
371
|
-
| `ctrl+l` | model picker |
|
|
431
|
+
| `ctrl+l` | model picker; inside it, `ctrl+r` fetches the catalogue again |
|
|
372
432
|
| `ctrl+o` | expand tool output (also `ctrl+r`) |
|
|
373
433
|
| `ctrl+t` | show the current plan |
|
|
374
434
|
| `ctrl+x` | copy the selected message to the clipboard |
|
|
@@ -474,8 +534,7 @@ silently resolved.
|
|
|
474
534
|
|
|
475
535
|
| Command | Does |
|
|
476
536
|
|---|---|
|
|
477
|
-
| `/model [query]` | pick a model; shows context window, price per Mtok, cache support |
|
|
478
|
-
| `/models refresh` | re-fetch the catalogue |
|
|
537
|
+
| `/model [query]` | pick a model; shows context window, price per Mtok, cache support. `ctrl+r` in the picker re-fetches the catalogue |
|
|
479
538
|
| `/effort [level]` | how hard a reasoning model thinks, from the levels it offers |
|
|
480
539
|
| `/configure` | session settings and the API key |
|
|
481
540
|
| `/login [provider]` | sign in to a model route |
|
|
@@ -709,8 +768,14 @@ After the first exchange, HX asks the model for a short name for the session and
|
|
|
709
768
|
writes it to `~/.hx/sessions/<id>/meta.json`, so `/resume` lists work rather
|
|
710
769
|
than timestamps. It is one small call — cap 32 output tokens, `models.title_model`
|
|
711
770
|
if you want a cheaper model for it — and it is counted in `/cost` like any other.
|
|
712
|
-
If the call fails the session is still named,
|
|
713
|
-
|
|
771
|
+
If the call fails, or you leave before it is back, the session is still named,
|
|
772
|
+
from your first message.
|
|
773
|
+
|
|
774
|
+
The live session is never renamed while it runs, and nothing is renamed on
|
|
775
|
+
`/exit`, which returns your shell at once. A session you leave with `/clear` or
|
|
776
|
+
`/resume` - including a `/resume` into another directory - is renamed in the
|
|
777
|
+
background for what it became. `/title <text>` renames it yourself, and a name
|
|
778
|
+
you chose is never replaced.
|
|
714
779
|
|
|
715
780
|
`/resume` lists every session except the one you are in: this directory's
|
|
716
781
|
first, then other directories', each row naming where it lives. A session from
|
|
@@ -50,7 +50,7 @@ Requires Python 3.11+. macOS and Linux. Update with `hx upgrade`.
|
|
|
50
50
|
|
|
51
51
|
### Credentials
|
|
52
52
|
|
|
53
|
-
HX reaches models over
|
|
53
|
+
HX reaches models over four routes. Which one serves a turn is decided by the
|
|
54
54
|
model id alone, so "what paid for that" is always answerable by reading it:
|
|
55
55
|
|
|
56
56
|
| Model id | Route | Billing |
|
|
@@ -58,8 +58,10 @@ model id alone, so "what paid for that" is always answerable by reading it:
|
|
|
58
58
|
| `anthropic/claude-sonnet-4.5`, `openai/gpt-5`, … | OpenRouter | per token, API key |
|
|
59
59
|
| `openai-codex/gpt-5.6-terra` | ChatGPT Plus/Pro | your subscription |
|
|
60
60
|
| `devin/swe-1-6`, `devin/claude-opus-5`, … | Devin | your subscription |
|
|
61
|
+
| `claude-code/claude-sonnet-5`, `claude-code/claude-opus-4-8`, … | Claude Pro/Max, via Claude Code | your subscription |
|
|
61
62
|
|
|
62
|
-
Credentials live in `~/.hx/auth.json`, mode 0600, one entry per route
|
|
63
|
+
Credentials live in `~/.hx/auth.json`, mode 0600, one entry per route - except
|
|
64
|
+
Claude Code's, which stays with Claude Code.
|
|
63
65
|
|
|
64
66
|
**OpenRouter.** On first run HX asks for a key. Get one at
|
|
65
67
|
<https://openrouter.ai/keys>. Change it later with `/configure` in the TUI, or:
|
|
@@ -113,7 +115,7 @@ reach it at all.
|
|
|
113
115
|
|
|
114
116
|
**Which Codex models you get** is decided by your ChatGPT account, not by HX.
|
|
115
117
|
Signing in fetches the account's own list from the Codex backend, and `/model`
|
|
116
|
-
offers exactly that; `/
|
|
118
|
+
offers exactly that; ctrl+r in `/model` asks again. Entitlement is per model -
|
|
117
119
|
the same `plus` account can run `gpt-5.6-sol` and be refused `gpt-5.3-codex` —
|
|
118
120
|
so a model the picker does not list is one the subscription does not cover.
|
|
119
121
|
|
|
@@ -175,7 +177,7 @@ you to sign in again. On a machine with no browser at all, a session token in
|
|
|
175
177
|
`HX_DEVIN_API_KEY` or `DEVIN_API_KEY` is used when nothing is saved.
|
|
176
178
|
|
|
177
179
|
Signing in fetches the account's own model list, and `/model` offers exactly
|
|
178
|
-
that; `/
|
|
180
|
+
that; ctrl+r in `/model` asks again. Devin publishes each reasoning depth as a
|
|
179
181
|
model of its own - Claude Opus 5 High, Claude Opus 5 Max - and HX folds each
|
|
180
182
|
family into one model, so `/effort` picks the depth on Devin exactly as it does
|
|
181
183
|
on Codex. A fast lane or a 1M-context lane stays a separate model, since it
|
|
@@ -183,6 +185,54 @@ changes what a turn costs or how much fits. Router models such as
|
|
|
183
185
|
`devin/adaptive` are resolved to a concrete model on every turn by Devin itself.
|
|
184
186
|
If the list cannot be fetched, `devin/swe-1-6` and `devin/swe-1-6-fast` stand in.
|
|
185
187
|
|
|
188
|
+
**Claude Pro/Max.** HX runs Claude models on your Claude subscription through
|
|
189
|
+
the official [Claude Code](https://claude.com/claude-code) CLI, the way the
|
|
190
|
+
Claude Agent SDK does. Install Claude Code, then:
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
hx auth login claude-code # Claude Code's own sign-in; or /login inside HX
|
|
194
|
+
hx --model claude-code/claude-sonnet-5
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
HX holds no Claude token. The login is Claude Code's, kept and refreshed where
|
|
198
|
+
Claude Code keeps it, so `hx auth logout claude-code` only tells you to run
|
|
199
|
+
`claude auth logout` - which signs out every Claude Code on the machine. A
|
|
200
|
+
headless machine can use a token from `claude setup-token` in
|
|
201
|
+
`CLAUDE_CODE_OAUTH_TOKEN`. A Console login (`claude auth login --console`) bills
|
|
202
|
+
per token and is refused: this route is the subscription.
|
|
203
|
+
|
|
204
|
+
How a turn works: HX starts `claude -p` with every one of Claude Code's own
|
|
205
|
+
tools switched off and serves HX's tools to it as an MCP server. The model's
|
|
206
|
+
tool calls are run, permission-checked and drawn by HX exactly as on every
|
|
207
|
+
other route; Claude Code holds each call open until HX answers it, however long
|
|
208
|
+
an approval takes. The system prompt is Claude Code's, with your AGENTS.md
|
|
209
|
+
files, skills index and `--append-system-prompt` text added. One Claude Code
|
|
210
|
+
process serves a conversation for as long as it can, so the prompt cache
|
|
211
|
+
carries from turn to turn; after an interrupt, a steer while a tool runs, a
|
|
212
|
+
compaction, `/model`, `/effort` or a resumed session, HX starts a new one on a
|
|
213
|
+
session rebuilt from its own transcript. That costs a second or so and a
|
|
214
|
+
partly cold cache, not the conversation.
|
|
215
|
+
|
|
216
|
+
Claude Code is started isolated from your Claude Code setup: no CLAUDE.md, no
|
|
217
|
+
hooks, no plugins or MCP servers from `~/.claude`, no auto-memory, no
|
|
218
|
+
auto-compaction (HX compacts its own transcript), and nothing saved to Claude
|
|
219
|
+
Code's session list. Variables that would move it off the subscription -
|
|
220
|
+
`ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`, `CLAUDE_CODE_USE_BEDROCK` and the
|
|
221
|
+
rest - are removed from its environment; its TLS settings are kept (see
|
|
222
|
+
*Behind a TLS-inspecting proxy* below). `HX_CLAUDE_CODE_PATH` points HX at a
|
|
223
|
+
`claude` other than the one on `PATH`.
|
|
224
|
+
|
|
225
|
+
`/model` offers the models Claude Code lists for the account, each with the
|
|
226
|
+
efforts it accepts for `/effort`; ctrl+r in `/model` asks again. A model Claude
|
|
227
|
+
Code runs at its long context keeps `[1m]` in its id
|
|
228
|
+
(`claude-code/claude-fable-5-1[1m]`), exactly as Claude Code's own `/model` runs
|
|
229
|
+
it. Claude Code lists no context sizes, so a model starts at the window it was
|
|
230
|
+
measured serving on every plan - 1M for Opus 5.5, Sonnet 5.5, Sonnet 5 and Opus
|
|
231
|
+
4.7, otherwise 200k - and from its first turn uses the window Claude Code
|
|
232
|
+
reports for your account. When a usage limit is reached, HX says which one and
|
|
233
|
+
when it resets; when a model or its 1M context needs usage credits your plan
|
|
234
|
+
has off, HX says that instead, and what to pick without them.
|
|
235
|
+
|
|
186
236
|
**Web search.** Optional, and the one credential that is not a model route.
|
|
187
237
|
It powers two tools:
|
|
188
238
|
|
|
@@ -192,7 +242,7 @@ It powers two tools:
|
|
|
192
242
|
| `WebFetch` | read up to 5 URLs, returned as markdown |
|
|
193
243
|
|
|
194
244
|
[Tavily](https://app.tavily.com) bills per search rather than per token, so it
|
|
195
|
-
works identically on
|
|
245
|
+
works identically on every route - including the subscription ones,
|
|
196
246
|
where a provider-native search tool is not on offer.
|
|
197
247
|
|
|
198
248
|
Get a key at <https://app.tavily.com> — the free tier is 1000 searches a month
|
|
@@ -246,9 +296,18 @@ startup every session, because it is not a fix. A TLS failure is reported in
|
|
|
246
296
|
one line - `/model` and the startup notice both name the certificate problem
|
|
247
297
|
rather than reporting an empty catalogue with no cause.
|
|
248
298
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
299
|
+
The same settings cover the `claude-code` route, whose requests Claude Code
|
|
300
|
+
makes with its own TLS stack: HX passes `HX_CA_BUNDLE` on to it as
|
|
301
|
+
`NODE_EXTRA_CA_CERTS` (unless you already set that yourself), and
|
|
302
|
+
`HX_SSL_NO_VERIFY` as `NODE_TLS_REJECT_UNAUTHORIZED=0`. Claude Code reads the
|
|
303
|
+
OS trust store on its own, and its own TLS settings reach it untouched:
|
|
304
|
+
`CLAUDE_CODE_CERT_STORE`, and `CLAUDE_CODE_CLIENT_CERT`,
|
|
305
|
+
`CLAUDE_CODE_CLIENT_KEY` and `CLAUDE_CODE_CLIENT_KEY_PASSPHRASE` for a network
|
|
306
|
+
that requires a client certificate.
|
|
307
|
+
|
|
308
|
+
HX never sends a Claude subscription token to the API itself - Anthropic
|
|
309
|
+
accepts those only from Claude Code, and HX will not impersonate it. The
|
|
310
|
+
`claude-code` route runs the real Claude Code instead.
|
|
252
311
|
|
|
253
312
|
---
|
|
254
313
|
|
|
@@ -274,7 +333,7 @@ hx mcp list|add|remove # manage MCP servers
|
|
|
274
333
|
hx mcp login <server> # sign in to a remote MCP server in the browser
|
|
275
334
|
hx mcp logout <server> # forget a remote MCP server's sign-in
|
|
276
335
|
hx auth [set|clear] # manage the OpenRouter key
|
|
277
|
-
hx auth login [provider] # sign in (openrouter, openai-codex, devin)
|
|
336
|
+
hx auth login [provider] # sign in (openrouter, openai-codex, devin, claude-code)
|
|
278
337
|
hx auth logout <provider> # forget a stored credential
|
|
279
338
|
hx docs [section] # the manual; no argument lists its sections
|
|
280
339
|
hx changelog [version] # what shipped in each version
|
|
@@ -328,7 +387,7 @@ be rebound (see [Keybindings](#keybindings)).
|
|
|
328
387
|
| `ctrl+d` | exit, when the prompt is empty |
|
|
329
388
|
| `shift+tab` | cycle permission mode |
|
|
330
389
|
| `ctrl+p` | command palette |
|
|
331
|
-
| `ctrl+l` | model picker |
|
|
390
|
+
| `ctrl+l` | model picker; inside it, `ctrl+r` fetches the catalogue again |
|
|
332
391
|
| `ctrl+o` | expand tool output (also `ctrl+r`) |
|
|
333
392
|
| `ctrl+t` | show the current plan |
|
|
334
393
|
| `ctrl+x` | copy the selected message to the clipboard |
|
|
@@ -434,8 +493,7 @@ silently resolved.
|
|
|
434
493
|
|
|
435
494
|
| Command | Does |
|
|
436
495
|
|---|---|
|
|
437
|
-
| `/model [query]` | pick a model; shows context window, price per Mtok, cache support |
|
|
438
|
-
| `/models refresh` | re-fetch the catalogue |
|
|
496
|
+
| `/model [query]` | pick a model; shows context window, price per Mtok, cache support. `ctrl+r` in the picker re-fetches the catalogue |
|
|
439
497
|
| `/effort [level]` | how hard a reasoning model thinks, from the levels it offers |
|
|
440
498
|
| `/configure` | session settings and the API key |
|
|
441
499
|
| `/login [provider]` | sign in to a model route |
|
|
@@ -669,8 +727,14 @@ After the first exchange, HX asks the model for a short name for the session and
|
|
|
669
727
|
writes it to `~/.hx/sessions/<id>/meta.json`, so `/resume` lists work rather
|
|
670
728
|
than timestamps. It is one small call — cap 32 output tokens, `models.title_model`
|
|
671
729
|
if you want a cheaper model for it — and it is counted in `/cost` like any other.
|
|
672
|
-
If the call fails the session is still named,
|
|
673
|
-
|
|
730
|
+
If the call fails, or you leave before it is back, the session is still named,
|
|
731
|
+
from your first message.
|
|
732
|
+
|
|
733
|
+
The live session is never renamed while it runs, and nothing is renamed on
|
|
734
|
+
`/exit`, which returns your shell at once. A session you leave with `/clear` or
|
|
735
|
+
`/resume` - including a `/resume` into another directory - is renamed in the
|
|
736
|
+
background for what it became. `/title <text>` renames it yourself, and a name
|
|
737
|
+
you chose is never replaced.
|
|
674
738
|
|
|
675
739
|
`/resume` lists every session except the one you are in: this directory's
|
|
676
740
|
first, then other directories', each row naming where it lives. A session from
|
|
@@ -55,6 +55,9 @@ dev = [
|
|
|
55
55
|
# A VT emulator, so tests can assert what the differ actually paints rather
|
|
56
56
|
# than what it claims to have written.
|
|
57
57
|
"pyte>=0.8",
|
|
58
|
+
# A throwaway CA, so the TLS tests can stand up the intercepting proxy a
|
|
59
|
+
# corporate network puts between HX and the API.
|
|
60
|
+
"trustme>=1.2",
|
|
58
61
|
]
|
|
59
62
|
|
|
60
63
|
[project.scripts]
|
|
@@ -107,7 +107,13 @@ class SubagentRunner:
|
|
|
107
107
|
try:
|
|
108
108
|
loop = self._build_loop(definition, subagent_id)
|
|
109
109
|
result = await loop.run(prompt)
|
|
110
|
-
report = _final_text(result)
|
|
110
|
+
report = _final_text(result)
|
|
111
|
+
if result.error is not None:
|
|
112
|
+
# The parent model only sees the report: without the reason it
|
|
113
|
+
# cannot tell a refused or broken run from one with nothing to say.
|
|
114
|
+
failure = f"The subagent failed: {result.error}"
|
|
115
|
+
report = f"{report}\n\n{failure}" if report else failure
|
|
116
|
+
report = report or "(the subagent returned no text)"
|
|
111
117
|
cost = loop.session.usage.total_cost_usd
|
|
112
118
|
self._roll_up_cost(loop)
|
|
113
119
|
return SubagentResult(
|
|
@@ -167,6 +173,7 @@ class SubagentRunner:
|
|
|
167
173
|
model_info=self.models.get_or_default(model) if self.models else None,
|
|
168
174
|
project_context=self.project_context,
|
|
169
175
|
hooks=self.hooks,
|
|
176
|
+
models=self.models,
|
|
170
177
|
)
|
|
171
178
|
loop.origin = f"{definition.name} subagent"
|
|
172
179
|
return loop
|