hx-cli 0.2.4__tar.gz → 0.2.6__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.4 → hx_cli-0.2.6}/CHANGELOG.md +77 -1
- {hx_cli-0.2.4 → hx_cli-0.2.6}/PKG-INFO +91 -6
- {hx_cli-0.2.4 → hx_cli-0.2.6}/README.md +89 -5
- {hx_cli-0.2.4 → hx_cli-0.2.6}/pyproject.toml +1 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/__init__.py +1 -1
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/cli.py +257 -14
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/compaction.py +17 -2
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/context.py +25 -4
- hx_cli-0.2.6/src/hx/core/images.py +394 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/loop.py +25 -11
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/messages.py +80 -4
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/session.py +59 -9
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/keys.py +3 -0
- hx_cli-0.2.6/src/hx/mcp/client.py +662 -0
- hx_cli-0.2.6/src/hx/mcp/manager.py +481 -0
- hx_cli-0.2.6/src/hx/mcp/oauth.py +766 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/codex_catalogue.py +12 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/devin.py +14 -1
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/devin_catalogue.py +4 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/devin_wire.py +21 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/models.py +36 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/openrouter.py +35 -1
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/responses_codec.py +29 -6
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/screen.py +38 -7
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/base.py +6 -1
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/bash.py +14 -2
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/read.py +36 -1
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/registry.py +4 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/trace.py +32 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/app.py +4 -3
- hx_cli-0.2.6/src/hx/tui/clipboard.py +308 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/commands.py +103 -8
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/format.py +22 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/glyphs.py +3 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/renderers.py +69 -16
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/runtime.py +124 -30
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/blocks.py +27 -9
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/login.py +3 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/pickers.py +84 -17
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/prompt.py +108 -8
- hx_cli-0.2.6/tests/core/test_images.py +281 -0
- hx_cli-0.2.6/tests/core/test_loop_images.py +181 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_session.py +51 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_steering.py +3 -3
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/mcp/fixtures/echo_server.py +26 -1
- hx_cli-0.2.6/tests/mcp/fixtures/oauth_server.py +438 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/mcp/test_manager.py +20 -0
- hx_cli-0.2.6/tests/mcp/test_oauth.py +670 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_catalogue.py +55 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_codex_catalogue.py +7 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_devin.py +36 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_devin_catalogue.py +23 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_openrouter.py +70 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_responses_codec.py +34 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_screen.py +27 -1
- hx_cli-0.2.6/tests/test_cli.py +409 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_readme.py +1 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_trace.py +23 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_background.py +14 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_files.py +33 -0
- hx_cli-0.2.6/tests/tui/test_images.py +319 -0
- hx_cli-0.2.6/tests/tui/test_mcp_login.py +102 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_renderers.py +74 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_session.py +22 -11
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/test_prompt.py +9 -9
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/test_runtime.py +171 -1
- {hx_cli-0.2.4 → hx_cli-0.2.6}/uv.lock +87 -0
- hx_cli-0.2.4/src/hx/mcp/client.py +0 -347
- hx_cli-0.2.4/src/hx/mcp/manager.py +0 -265
- hx_cli-0.2.4/src/hx/tui/clipboard.py +0 -125
- hx_cli-0.2.4/tests/test_cli.py +0 -215
- {hx_cli-0.2.4 → hx_cli-0.2.6}/.github/workflows/ci.yml +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/.gitignore +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/examples/hooks/check.sh +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/install.sh +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/agents/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/agents/definitions.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/agents/subagent.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/oauth/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/oauth/browser.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/oauth/callback.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/oauth/codex.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/oauth/devin.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/oauth/pkce.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/resolve.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/auth/store.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/config.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/checkpoints.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/events.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/lateinject.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/title.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/core/usage.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/docs.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/frontmatter.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/git.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/hooks/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/hooks/engine.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/hooks/spec.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/mcp/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/net.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/paths.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/permissions/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/permissions/engine.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/permissions/parser.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/permissions/sandbox.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/base.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/codex.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/fake.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/protowire.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/providers/registry.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/skills/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/skills/loader.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/skills/runtime.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/ansi.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/buffer.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/component.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/demo.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/editor.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/keydecode.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/loop.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/markdown.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/primitives.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/sanitize.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/syntax.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/terminal.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/undo.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/width.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/term/word_nav.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/anchors.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/edit.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/glob.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/grep.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/output.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/symbols.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/task.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/todo.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/websearch.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tools/write.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/fuzzy.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/killring.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/limits.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/paint.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/roles.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/theme.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/theme_json.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/themes/ansi.json +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/themes/dark.json +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/themes/light.json +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/dialog.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/permission.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/status.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/src/hx/tui/views/transcript.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/agents/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/agents/test_subagent.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/auth/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/auth/test_codex_oauth.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/auth/test_devin_oauth.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/auth/test_pkce.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/auth/test_resolve.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/auth/test_store.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/conftest.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_checkpoints.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_compaction.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_context.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_lateinject.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_loop.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_rewind.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_settings_layers.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_settings_migration.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_title.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/core/test_usage.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/hooks/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/hooks/test_engine.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/hooks/test_example_check.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/mcp/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/permissions/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/permissions/test_engine.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/permissions/test_parser.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/permissions/test_sandbox.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_codex.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_protowire.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/providers/test_registry.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/skills/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/skills/test_loader.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/conftest.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_ansi.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_keydecode.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_loop.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_markdown.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_primitives.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_sanitize.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_terminal.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/term/test_width.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_docs.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_git.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_install.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_integration.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_live.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_live_codex.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_live_devin.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_live_tavily.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_net.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/test_paths.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_bash.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_hashline.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_output.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_symbols.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_todo.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tools/test_websearch.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/support.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_autocomplete.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_clipboard.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_effort.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_keys.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_login.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_theme_json.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/test_trace_command.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/__init__.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/test_blocks.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/test_permission.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/test_pickers.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/test_status.py +0 -0
- {hx_cli-0.2.4 → hx_cli-0.2.6}/tests/tui/views/test_transcript.py +0 -0
|
@@ -28,6 +28,80 @@ the project follows [semantic versioning](https://semver.org/).
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
+
## [0.2.6] - 2026-09-23
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Sign in to remote MCP servers over OAuth. A server that asks for it -
|
|
36
|
+
Atlassian's `https://mcp.atlassian.com/v2/mcp`, for one - shows as needing
|
|
37
|
+
sign-in; `/mcp login <server>` or `hx mcp login <server>` opens the browser
|
|
38
|
+
and the tools arrive without a restart. Tokens refresh on their own;
|
|
39
|
+
`/mcp logout <server>` forgets them. `"oauth": {"clientId": ...}` in
|
|
40
|
+
`mcp.json` covers servers without client registration.
|
|
41
|
+
- MCP servers that change their tool list mid-session have the new list
|
|
42
|
+
swapped in, whether they announce it in a reply or on their own stream.
|
|
43
|
+
- `hx mcp add NAME --url URL --header "Name: value"` saves headers, such as an
|
|
44
|
+
API token, with the server.
|
|
45
|
+
- `/mcp reconnect <server>` restarts one server without restarting HX.
|
|
46
|
+
- `/resume` always offers a list to switch to: this directory's sessions
|
|
47
|
+
first, then every other directory's, each row naming where it lives.
|
|
48
|
+
Picking one from elsewhere restarts HX in that directory on it, with the
|
|
49
|
+
same `--mode` and `--model`. The session already open is no longer listed,
|
|
50
|
+
and the list is no longer cut at 20.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- `/resume` said "No previous sessions in this directory" in a fresh
|
|
55
|
+
directory, or inside a session resumed from another one, instead of
|
|
56
|
+
listing anything.
|
|
57
|
+
- `hx resume <id>` ran the session in whatever directory you typed it in,
|
|
58
|
+
not the one it was recorded in, so its paths and tool calls pointed at the
|
|
59
|
+
wrong project.
|
|
60
|
+
- `hx mcp add NAME --url URL`, `--user`, and server arguments like `npx -y`
|
|
61
|
+
were refused as unknown options, so none of them could be run.
|
|
62
|
+
- `hx mcp add` dropped headers from the entry it wrote.
|
|
63
|
+
- A remote MCP server that expires its session is initialized again instead
|
|
64
|
+
of failing every call until HX restarts.
|
|
65
|
+
- A multi-line shell command no longer breaks the screen. Its approval shows
|
|
66
|
+
one row per line, the tool call shows the first line and `+N lines`
|
|
67
|
+
(`ctrl+o` shows the rest), and the approval options and prompt are no longer
|
|
68
|
+
drawn several times over.
|
|
69
|
+
- `/resume` from inside a resumed session showed the resumed conversation
|
|
70
|
+
pushed off the top of the screen, leaving only the "Resumed" notice.
|
|
71
|
+
- A session title with a line break in it no longer splits its row in the
|
|
72
|
+
`/resume` picker.
|
|
73
|
+
- Started in your home directory, the status bar named it `~/.`; it now reads
|
|
74
|
+
`~`.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## [0.2.5] - 2026-09-23
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- Images as input. `ctrl+v` attaches the image on the clipboard, dragging an
|
|
83
|
+
image file into the terminal attaches it, and `hx -p "..." --image PATH`
|
|
84
|
+
attaches one to a headless prompt. Each shows in the prompt as
|
|
85
|
+
`[Image #N]`.
|
|
86
|
+
- `Read` returns image files as images, so the model can look at a screenshot
|
|
87
|
+
or mockup it is pointed at with `@path`.
|
|
88
|
+
- Images returned by MCP tools reach the model instead of being dropped.
|
|
89
|
+
- Every route carries images: OpenRouter, the Codex subscription and the Devin
|
|
90
|
+
subscription. Large images are scaled and re-encoded to fit each route's
|
|
91
|
+
limits.
|
|
92
|
+
- A model that does not accept images is warned about when one is attached,
|
|
93
|
+
and is told the image was left out rather than sent a request that fails.
|
|
94
|
+
The `/model` picker marks the models that can see images.
|
|
95
|
+
|
|
96
|
+
### Fixed
|
|
97
|
+
|
|
98
|
+
- Background jobs are waited for, not only signalled, when a session closes.
|
|
99
|
+
An unwaited subprocess transport was collected after the event loop had
|
|
100
|
+
gone, which raised `Event loop is closed` as an unraisable warning on CI
|
|
101
|
+
runs that otherwise passed.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
31
105
|
## [0.2.4] - 2026-09-19
|
|
32
106
|
|
|
33
107
|
### Added
|
|
@@ -565,7 +639,9 @@ First release, published to PyPI as [`hx-cli`](https://pypi.org/project/hx-cli/)
|
|
|
565
639
|
- `/configure` and `hx auth` for the OpenRouter key, `hx upgrade` for
|
|
566
640
|
self-update, and `install.sh` bootstrapping uv with a pinned Python.
|
|
567
641
|
|
|
568
|
-
[Unreleased]: https://github.com/aletisunil/hx/compare/v0.2.
|
|
642
|
+
[Unreleased]: https://github.com/aletisunil/hx/compare/v0.2.6...HEAD
|
|
643
|
+
[0.2.6]: https://github.com/aletisunil/hx/compare/v0.2.5...v0.2.6
|
|
644
|
+
[0.2.5]: https://github.com/aletisunil/hx/compare/v0.2.4...v0.2.5
|
|
569
645
|
[0.2.4]: https://github.com/aletisunil/hx/compare/v0.2.3...v0.2.4
|
|
570
646
|
[0.2.3]: https://github.com/aletisunil/hx/compare/v0.2.2...v0.2.3
|
|
571
647
|
[0.2.2]: https://github.com/aletisunil/hx/compare/v0.2.1...v0.2.2
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hx-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
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
|
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
18
18
|
Requires-Python: >=3.11
|
|
19
19
|
Requires-Dist: httpx>=0.27
|
|
20
20
|
Requires-Dist: markdown-it-py>=3.0
|
|
21
|
+
Requires-Dist: pillow>=10.4
|
|
21
22
|
Requires-Dist: pydantic>=2.7
|
|
22
23
|
Requires-Dist: pygments>=2.17
|
|
23
24
|
Requires-Dist: pyyaml>=6.0
|
|
@@ -296,8 +297,9 @@ available through OpenRouter.
|
|
|
296
297
|
```sh
|
|
297
298
|
hx # interactive TUI in the current directory
|
|
298
299
|
hx -p "explain this repo" # headless: streams to stdout, tool activity to stderr
|
|
300
|
+
hx -p "why?" --image s.png # attach an image to a headless prompt; repeatable
|
|
299
301
|
hx resume # resume the last session here
|
|
300
|
-
hx resume <session-id> # resume a specific one
|
|
302
|
+
hx resume <session-id> # resume a specific one, in the directory it was recorded in
|
|
301
303
|
hx prompt # print the system prompt this directory would use
|
|
302
304
|
hx trace # write the last session here to an HTML page
|
|
303
305
|
hx trace out.html # the same, to a path you choose
|
|
@@ -309,6 +311,8 @@ hx --no-sandbox # disable OS sandboxing (rules still apply)
|
|
|
309
311
|
hx --system-prompt @p.md # replace the system prompt for one run
|
|
310
312
|
hx --append-system-prompt "Always run the tests" # add to it; repeatable
|
|
311
313
|
hx mcp list|add|remove # manage MCP servers
|
|
314
|
+
hx mcp login <server> # sign in to a remote MCP server in the browser
|
|
315
|
+
hx mcp logout <server> # forget a remote MCP server's sign-in
|
|
312
316
|
hx auth [set|clear] # manage the OpenRouter key
|
|
313
317
|
hx auth login [provider] # sign in (openrouter, openai-codex, devin)
|
|
314
318
|
hx auth logout <provider> # forget a stored credential
|
|
@@ -375,6 +379,7 @@ be rebound (see [Keybindings](#keybindings)).
|
|
|
375
379
|
| `pgdn` | scroll the transcript down (fullscreen; otherwise your terminal scrolls) |
|
|
376
380
|
| `ctrl+home` | jump to the start: the viewport in fullscreen, the first message otherwise |
|
|
377
381
|
| `ctrl+end` | jump back to the newest output |
|
|
382
|
+
| `ctrl+v` | attach the image on the clipboard (see [Images](#images)) |
|
|
378
383
|
| `@path` | complete a file path |
|
|
379
384
|
| `!command` | run a shell command directly, no model turn |
|
|
380
385
|
|
|
@@ -406,6 +411,44 @@ text](#selecting-and-copying-text) for the terminal's own selection.
|
|
|
406
411
|
HX does not emit OSC 133 prompt markers yet, so shell-integration features that
|
|
407
412
|
jump between prompts will not see HX's messages.
|
|
408
413
|
|
|
414
|
+
#### Images
|
|
415
|
+
|
|
416
|
+
Give the model a picture three ways, and each lands in the prompt as a token
|
|
417
|
+
such as `[Image #1]`:
|
|
418
|
+
|
|
419
|
+
- **`ctrl+v`** attaches whatever image is on the clipboard: a screenshot copied
|
|
420
|
+
with `cmd+ctrl+shift+4`, an image copied in a browser, or an image file
|
|
421
|
+
copied in Finder or a file manager. Terminals whose own paste sends nothing
|
|
422
|
+
when the clipboard holds a picture are caught too - an empty paste is read as
|
|
423
|
+
a request for the image.
|
|
424
|
+
- **Drag an image file** into the terminal. The terminal pastes its path, and a
|
|
425
|
+
paste that is nothing but paths to image files attaches them instead of
|
|
426
|
+
inserting the text. Quoted, backslash-escaped and `file://` paths all work.
|
|
427
|
+
- **Mention it.** `look at @docs/mockup.png` sends the path as text, and the
|
|
428
|
+
model opens it with `Read`, which returns images as images.
|
|
429
|
+
|
|
430
|
+
The token is the attachment: move it and the text refers to the picture in a
|
|
431
|
+
different place, delete it (one `backspace` takes the whole token) and the
|
|
432
|
+
image is not sent. Sent messages list their images underneath, with size and
|
|
433
|
+
weight. Numbers run for the whole session, so a message recalled from history
|
|
434
|
+
or restored by a rewind still carries its pictures.
|
|
435
|
+
|
|
436
|
+
PNG, JPEG, GIF, WebP, BMP and TIFF are accepted. An image within every route's
|
|
437
|
+
limits goes byte for byte; a larger one is scaled to 2000 px on its long side
|
|
438
|
+
and re-encoded to stay under 5 MB, which is what a retina screenshot usually
|
|
439
|
+
needs. Images an MCP tool returns - a browser screenshot, say - are handled the
|
|
440
|
+
same way rather than dropped.
|
|
441
|
+
|
|
442
|
+
Whether a model can see images comes from the catalogue: OpenRouter's input
|
|
443
|
+
modalities, the Codex catalogue, and Devin's model config. The `/model` picker
|
|
444
|
+
marks the ones that can with `images`. A model that cannot
|
|
445
|
+
is warned about when you attach, and is sent a line saying an image was left
|
|
446
|
+
out, rather than a request that fails. The transcript keeps the image either
|
|
447
|
+
way, so `/model` to one that can see it and ask again.
|
|
448
|
+
|
|
449
|
+
Over SSH the clipboard you copied into is on your own machine, so `ctrl+v`
|
|
450
|
+
says so; copy the file over and drag or paste its path instead.
|
|
451
|
+
|
|
409
452
|
#### Keybindings
|
|
410
453
|
|
|
411
454
|
Any key can be rebound in `~/.hx/keybindings.json`, keyed by the action ids in
|
|
@@ -437,14 +480,14 @@ than being silently resolved.
|
|
|
437
480
|
| `/cost` | tokens, cache savings, spend |
|
|
438
481
|
| `/compact [focus]` | summarise older turns now |
|
|
439
482
|
| `/clear` | fresh session, same directory |
|
|
440
|
-
| `/resume` |
|
|
483
|
+
| `/resume` | switch to another session - this directory's first, then the rest |
|
|
441
484
|
| `/rewind` | go back to an earlier prompt, restoring the files HX changed |
|
|
442
485
|
| `/title [text]` | show or set this session's name |
|
|
443
486
|
| `/prompt` | the system prompt this session is running with |
|
|
444
487
|
| `/todos` | show the current plan |
|
|
445
488
|
| `/skills` | installed skills |
|
|
446
489
|
| `/agents` | subagent types |
|
|
447
|
-
| `/mcp` | server status |
|
|
490
|
+
| `/mcp [login\|logout\|reconnect <server>]` | server status, and signing in to remote servers |
|
|
448
491
|
| `/hooks` | configured hooks, and any that were refused |
|
|
449
492
|
| `/theme [name]` | `dark`, `light`, `ansi`, or any theme in `~/.hx/themes` |
|
|
450
493
|
| `/queue [steer <n>\|clear]` | messages waiting for the turn to end, and what to do with them |
|
|
@@ -660,6 +703,13 @@ if you want a cheaper model for it — and it is counted in `/cost` like any oth
|
|
|
660
703
|
If the call fails the session is still named, from your first message. `/title
|
|
661
704
|
<text>` renames it.
|
|
662
705
|
|
|
706
|
+
`/resume` lists every session except the one you are in: this directory's
|
|
707
|
+
first, then other directories', each row naming where it lives. A session from
|
|
708
|
+
this directory is swapped in place. One from elsewhere belongs to that
|
|
709
|
+
directory - its sandbox, permission rules, prompt and tools - so HX restarts
|
|
710
|
+
itself there with `hx resume <id>`, keeping options like `--mode` and
|
|
711
|
+
`--model`.
|
|
712
|
+
|
|
663
713
|
### Themes
|
|
664
714
|
|
|
665
715
|
A theme is a JSON file: a `vars` block of raw colours, and a `colors` block
|
|
@@ -877,6 +927,10 @@ and is unchanged; anchors are a second shape, not a replacement. Turn the whole
|
|
|
877
927
|
thing off with `"tools": {"hashline": false}` and reads go back to plain
|
|
878
928
|
`cat -n`.
|
|
879
929
|
|
|
930
|
+
**Images.** `Read` on a PNG, JPEG, GIF, WebP, BMP or TIFF - or on a file with
|
|
931
|
+
no extension whose bytes are one - returns the image itself for the model to
|
|
932
|
+
look at, normalised the way a pasted one is (see [Images](#images)).
|
|
933
|
+
|
|
880
934
|
**Symbols** answers structural questions with a parse tree rather than a
|
|
881
935
|
regex — three modes, `outline` for one file's shape, `definition` for where a
|
|
882
936
|
name is defined, `references` for where it is used:
|
|
@@ -951,10 +1005,41 @@ construction.
|
|
|
951
1005
|
}
|
|
952
1006
|
```
|
|
953
1007
|
|
|
954
|
-
Or `hx mcp add local python server.py
|
|
1008
|
+
Or `hx mcp add local python server.py`, or
|
|
1009
|
+
`hx mcp add remote --url https://example.com/mcp`. Tools arrive namespaced
|
|
955
1010
|
`mcp__<server>__<tool>` in a deterministic order. Servers connect concurrently
|
|
956
1011
|
with a per-server timeout; one that is broken or slow logs a warning and is
|
|
957
|
-
dropped rather than taking the session with it.
|
|
1012
|
+
dropped rather than taking the session with it. A server that changes its tool
|
|
1013
|
+
list mid-session (`notifications/tools/list_changed`) has the new list swapped
|
|
1014
|
+
in without a restart.
|
|
1015
|
+
|
|
1016
|
+
A remote server that asks for sign-in - Atlassian's, for one - is signed in to
|
|
1017
|
+
over OAuth, with nothing to configure:
|
|
1018
|
+
|
|
1019
|
+
```json
|
|
1020
|
+
{ "mcpServers": { "atlassian": { "url": "https://mcp.atlassian.com/v2/mcp" } } }
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
It shows as needing sign-in until you run `/mcp login atlassian` in a session
|
|
1024
|
+
or `hx mcp login atlassian` in a shell. That opens the browser, and the tools
|
|
1025
|
+
arrive as soon as you approve - no restart. HX follows the MCP authorization
|
|
1026
|
+
spec: it finds the authorization server from the server's metadata, registers
|
|
1027
|
+
itself as a client, signs in with PKCE, and keeps the token in `~/.hx/auth.json`
|
|
1028
|
+
(mode 0600), refreshing it before it expires and again if the server rejects
|
|
1029
|
+
it. Over SSH, paste the final redirect URL into the prompt instead.
|
|
1030
|
+
`/mcp logout atlassian` forgets it.
|
|
1031
|
+
|
|
1032
|
+
A server that does not offer client registration needs a client you register
|
|
1033
|
+
with it yourself, and anything else about the sign-in can be pinned the same
|
|
1034
|
+
way:
|
|
1035
|
+
|
|
1036
|
+
```json
|
|
1037
|
+
"oauth": { "clientId": "...", "clientSecret": "...", "scope": "read write", "callbackPort": 33418 }
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
To send a token of your own instead - an API key - give the server an
|
|
1041
|
+
`Authorization` header, and OAuth stays out of the way:
|
|
1042
|
+
`hx mcp add jira --url https://mcp.atlassian.com/v2/mcp --header "Authorization: Basic <base64 email:token>"`.
|
|
958
1043
|
|
|
959
1044
|
**Hooks** are shell commands HX runs at named points in a turn. Four events:
|
|
960
1045
|
`PreToolUse`, `PostToolUse`, `UserPromptSubmit` and `Stop`.
|
|
@@ -257,8 +257,9 @@ available through OpenRouter.
|
|
|
257
257
|
```sh
|
|
258
258
|
hx # interactive TUI in the current directory
|
|
259
259
|
hx -p "explain this repo" # headless: streams to stdout, tool activity to stderr
|
|
260
|
+
hx -p "why?" --image s.png # attach an image to a headless prompt; repeatable
|
|
260
261
|
hx resume # resume the last session here
|
|
261
|
-
hx resume <session-id> # resume a specific one
|
|
262
|
+
hx resume <session-id> # resume a specific one, in the directory it was recorded in
|
|
262
263
|
hx prompt # print the system prompt this directory would use
|
|
263
264
|
hx trace # write the last session here to an HTML page
|
|
264
265
|
hx trace out.html # the same, to a path you choose
|
|
@@ -270,6 +271,8 @@ hx --no-sandbox # disable OS sandboxing (rules still apply)
|
|
|
270
271
|
hx --system-prompt @p.md # replace the system prompt for one run
|
|
271
272
|
hx --append-system-prompt "Always run the tests" # add to it; repeatable
|
|
272
273
|
hx mcp list|add|remove # manage MCP servers
|
|
274
|
+
hx mcp login <server> # sign in to a remote MCP server in the browser
|
|
275
|
+
hx mcp logout <server> # forget a remote MCP server's sign-in
|
|
273
276
|
hx auth [set|clear] # manage the OpenRouter key
|
|
274
277
|
hx auth login [provider] # sign in (openrouter, openai-codex, devin)
|
|
275
278
|
hx auth logout <provider> # forget a stored credential
|
|
@@ -336,6 +339,7 @@ be rebound (see [Keybindings](#keybindings)).
|
|
|
336
339
|
| `pgdn` | scroll the transcript down (fullscreen; otherwise your terminal scrolls) |
|
|
337
340
|
| `ctrl+home` | jump to the start: the viewport in fullscreen, the first message otherwise |
|
|
338
341
|
| `ctrl+end` | jump back to the newest output |
|
|
342
|
+
| `ctrl+v` | attach the image on the clipboard (see [Images](#images)) |
|
|
339
343
|
| `@path` | complete a file path |
|
|
340
344
|
| `!command` | run a shell command directly, no model turn |
|
|
341
345
|
|
|
@@ -367,6 +371,44 @@ text](#selecting-and-copying-text) for the terminal's own selection.
|
|
|
367
371
|
HX does not emit OSC 133 prompt markers yet, so shell-integration features that
|
|
368
372
|
jump between prompts will not see HX's messages.
|
|
369
373
|
|
|
374
|
+
#### Images
|
|
375
|
+
|
|
376
|
+
Give the model a picture three ways, and each lands in the prompt as a token
|
|
377
|
+
such as `[Image #1]`:
|
|
378
|
+
|
|
379
|
+
- **`ctrl+v`** attaches whatever image is on the clipboard: a screenshot copied
|
|
380
|
+
with `cmd+ctrl+shift+4`, an image copied in a browser, or an image file
|
|
381
|
+
copied in Finder or a file manager. Terminals whose own paste sends nothing
|
|
382
|
+
when the clipboard holds a picture are caught too - an empty paste is read as
|
|
383
|
+
a request for the image.
|
|
384
|
+
- **Drag an image file** into the terminal. The terminal pastes its path, and a
|
|
385
|
+
paste that is nothing but paths to image files attaches them instead of
|
|
386
|
+
inserting the text. Quoted, backslash-escaped and `file://` paths all work.
|
|
387
|
+
- **Mention it.** `look at @docs/mockup.png` sends the path as text, and the
|
|
388
|
+
model opens it with `Read`, which returns images as images.
|
|
389
|
+
|
|
390
|
+
The token is the attachment: move it and the text refers to the picture in a
|
|
391
|
+
different place, delete it (one `backspace` takes the whole token) and the
|
|
392
|
+
image is not sent. Sent messages list their images underneath, with size and
|
|
393
|
+
weight. Numbers run for the whole session, so a message recalled from history
|
|
394
|
+
or restored by a rewind still carries its pictures.
|
|
395
|
+
|
|
396
|
+
PNG, JPEG, GIF, WebP, BMP and TIFF are accepted. An image within every route's
|
|
397
|
+
limits goes byte for byte; a larger one is scaled to 2000 px on its long side
|
|
398
|
+
and re-encoded to stay under 5 MB, which is what a retina screenshot usually
|
|
399
|
+
needs. Images an MCP tool returns - a browser screenshot, say - are handled the
|
|
400
|
+
same way rather than dropped.
|
|
401
|
+
|
|
402
|
+
Whether a model can see images comes from the catalogue: OpenRouter's input
|
|
403
|
+
modalities, the Codex catalogue, and Devin's model config. The `/model` picker
|
|
404
|
+
marks the ones that can with `images`. A model that cannot
|
|
405
|
+
is warned about when you attach, and is sent a line saying an image was left
|
|
406
|
+
out, rather than a request that fails. The transcript keeps the image either
|
|
407
|
+
way, so `/model` to one that can see it and ask again.
|
|
408
|
+
|
|
409
|
+
Over SSH the clipboard you copied into is on your own machine, so `ctrl+v`
|
|
410
|
+
says so; copy the file over and drag or paste its path instead.
|
|
411
|
+
|
|
370
412
|
#### Keybindings
|
|
371
413
|
|
|
372
414
|
Any key can be rebound in `~/.hx/keybindings.json`, keyed by the action ids in
|
|
@@ -398,14 +440,14 @@ than being silently resolved.
|
|
|
398
440
|
| `/cost` | tokens, cache savings, spend |
|
|
399
441
|
| `/compact [focus]` | summarise older turns now |
|
|
400
442
|
| `/clear` | fresh session, same directory |
|
|
401
|
-
| `/resume` |
|
|
443
|
+
| `/resume` | switch to another session - this directory's first, then the rest |
|
|
402
444
|
| `/rewind` | go back to an earlier prompt, restoring the files HX changed |
|
|
403
445
|
| `/title [text]` | show or set this session's name |
|
|
404
446
|
| `/prompt` | the system prompt this session is running with |
|
|
405
447
|
| `/todos` | show the current plan |
|
|
406
448
|
| `/skills` | installed skills |
|
|
407
449
|
| `/agents` | subagent types |
|
|
408
|
-
| `/mcp` | server status |
|
|
450
|
+
| `/mcp [login\|logout\|reconnect <server>]` | server status, and signing in to remote servers |
|
|
409
451
|
| `/hooks` | configured hooks, and any that were refused |
|
|
410
452
|
| `/theme [name]` | `dark`, `light`, `ansi`, or any theme in `~/.hx/themes` |
|
|
411
453
|
| `/queue [steer <n>\|clear]` | messages waiting for the turn to end, and what to do with them |
|
|
@@ -621,6 +663,13 @@ if you want a cheaper model for it — and it is counted in `/cost` like any oth
|
|
|
621
663
|
If the call fails the session is still named, from your first message. `/title
|
|
622
664
|
<text>` renames it.
|
|
623
665
|
|
|
666
|
+
`/resume` lists every session except the one you are in: this directory's
|
|
667
|
+
first, then other directories', each row naming where it lives. A session from
|
|
668
|
+
this directory is swapped in place. One from elsewhere belongs to that
|
|
669
|
+
directory - its sandbox, permission rules, prompt and tools - so HX restarts
|
|
670
|
+
itself there with `hx resume <id>`, keeping options like `--mode` and
|
|
671
|
+
`--model`.
|
|
672
|
+
|
|
624
673
|
### Themes
|
|
625
674
|
|
|
626
675
|
A theme is a JSON file: a `vars` block of raw colours, and a `colors` block
|
|
@@ -838,6 +887,10 @@ and is unchanged; anchors are a second shape, not a replacement. Turn the whole
|
|
|
838
887
|
thing off with `"tools": {"hashline": false}` and reads go back to plain
|
|
839
888
|
`cat -n`.
|
|
840
889
|
|
|
890
|
+
**Images.** `Read` on a PNG, JPEG, GIF, WebP, BMP or TIFF - or on a file with
|
|
891
|
+
no extension whose bytes are one - returns the image itself for the model to
|
|
892
|
+
look at, normalised the way a pasted one is (see [Images](#images)).
|
|
893
|
+
|
|
841
894
|
**Symbols** answers structural questions with a parse tree rather than a
|
|
842
895
|
regex — three modes, `outline` for one file's shape, `definition` for where a
|
|
843
896
|
name is defined, `references` for where it is used:
|
|
@@ -912,10 +965,41 @@ construction.
|
|
|
912
965
|
}
|
|
913
966
|
```
|
|
914
967
|
|
|
915
|
-
Or `hx mcp add local python server.py
|
|
968
|
+
Or `hx mcp add local python server.py`, or
|
|
969
|
+
`hx mcp add remote --url https://example.com/mcp`. Tools arrive namespaced
|
|
916
970
|
`mcp__<server>__<tool>` in a deterministic order. Servers connect concurrently
|
|
917
971
|
with a per-server timeout; one that is broken or slow logs a warning and is
|
|
918
|
-
dropped rather than taking the session with it.
|
|
972
|
+
dropped rather than taking the session with it. A server that changes its tool
|
|
973
|
+
list mid-session (`notifications/tools/list_changed`) has the new list swapped
|
|
974
|
+
in without a restart.
|
|
975
|
+
|
|
976
|
+
A remote server that asks for sign-in - Atlassian's, for one - is signed in to
|
|
977
|
+
over OAuth, with nothing to configure:
|
|
978
|
+
|
|
979
|
+
```json
|
|
980
|
+
{ "mcpServers": { "atlassian": { "url": "https://mcp.atlassian.com/v2/mcp" } } }
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
It shows as needing sign-in until you run `/mcp login atlassian` in a session
|
|
984
|
+
or `hx mcp login atlassian` in a shell. That opens the browser, and the tools
|
|
985
|
+
arrive as soon as you approve - no restart. HX follows the MCP authorization
|
|
986
|
+
spec: it finds the authorization server from the server's metadata, registers
|
|
987
|
+
itself as a client, signs in with PKCE, and keeps the token in `~/.hx/auth.json`
|
|
988
|
+
(mode 0600), refreshing it before it expires and again if the server rejects
|
|
989
|
+
it. Over SSH, paste the final redirect URL into the prompt instead.
|
|
990
|
+
`/mcp logout atlassian` forgets it.
|
|
991
|
+
|
|
992
|
+
A server that does not offer client registration needs a client you register
|
|
993
|
+
with it yourself, and anything else about the sign-in can be pinned the same
|
|
994
|
+
way:
|
|
995
|
+
|
|
996
|
+
```json
|
|
997
|
+
"oauth": { "clientId": "...", "clientSecret": "...", "scope": "read write", "callbackPort": 33418 }
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
To send a token of your own instead - an API key - give the server an
|
|
1001
|
+
`Authorization` header, and OAuth stays out of the way:
|
|
1002
|
+
`hx mcp add jira --url https://mcp.atlassian.com/v2/mcp --header "Authorization: Basic <base64 email:token>"`.
|
|
919
1003
|
|
|
920
1004
|
**Hooks** are shell commands HX runs at named points in a turn. Four events:
|
|
921
1005
|
`PreToolUse`, `PostToolUse`, `UserPromptSubmit` and `Stop`.
|