fix: include terminal backend in quick setup wizard#21842
Conversation
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
🚨 CRITICAL Supply Chain Risk DetectedThis PR contains a pattern that has been used in real supply chain attacks. A maintainer must review the flagged code carefully before merging. 🚨 CRITICAL: Install-hook file added or modifiedThese files can execute code during package installation or interpreter startup. Files: Scanner only fires on high-signal indicators: .pth files, base64+exec/eval combos, subprocess with encoded commands, or install-hook files. Low-signal warnings were removed intentionally — if you're seeing this comment, the finding is worth inspecting. |
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-argument-type |
8 |
unsupported-operator |
3 |
unresolved-attribute |
3 |
not-subscriptable |
1 |
First entries
run_agent.py:2422: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `(Unknown & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | ... omitted 4 union elements`
tests/run_agent/test_provider_attribution_headers.py:156: [unsupported-operator] unsupported-operator: Operator `not in` is not supported between objects of type `Literal["X-OpenRouter-Cache-TTL"]` and `Unknown | str | dict[str, str] | ... omitted 3 union elements`
run_agent.py:2187: [invalid-argument-type] invalid-argument-type: Argument to function `query_ollama_num_ctx` is incorrect: Expected `str`, found `(str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 4 union elements`
run_agent.py:6655: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 3 union elements`
tests/run_agent/test_provider_attribution_headers.py:154: [not-subscriptable] not-subscriptable: Cannot subscript object of type `int` with no `__getitem__` method
tests/run_agent/test_provider_attribution_headers.py:155: [unsupported-operator] unsupported-operator: Operator `not in` is not supported between objects of type `Literal["X-OpenRouter-Cache"]` and `Unknown | str | dict[str, str] | ... omitted 3 union elements`
tests/run_agent/test_provider_attribution_headers.py:90: [unresolved-attribute] unresolved-attribute: Attribute `startswith` is not defined on `dict[str, str]` in union `Unknown | str | dict[str, str]`
run_agent.py:12548: [invalid-argument-type] invalid-argument-type: Argument to function `len` is incorrect: Expected `Sized`, found `(str & ~AlwaysFalsy) | (dict[Unknown, Unknown] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 3 union elements`
tests/agent/test_codex_cloudflare_headers.py:181: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["originator"]` and `(Unknown & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | ... omitted 3 union elements`
tests/agent/test_codex_cloudflare_headers.py:163: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str & ~AlwaysFalsy`, `int & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | ... omitted 3 union elements`
tests/agent/test_codex_cloudflare_headers.py:163: [unresolved-attribute] unresolved-attribute: Attribute `startswith` is not defined on `dict[str, str]` in union `Unknown | str | dict[str, str]`
run_agent.py:2419: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `(Unknown & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | ... omitted 4 union elements`
run_agent.py:2470: [invalid-argument-type] invalid-argument-type: Argument to function `get_model_context_length` is incorrect: Expected `str`, found `str | dict[str, str] | Any | ... omitted 3 union elements`
run_agent.py:6484: [invalid-argument-type] invalid-argument-type: Argument to function `_codex_cloudflare_headers` is incorrect: Expected `str`, found `Unknown | str | dict[str, str] | ... omitted 3 union elements`
run_agent.py:12545: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 3 union elements`
✅ Fixed issues (9):
| Rule | Count |
|---|---|
invalid-argument-type |
8 |
unresolved-attribute |
1 |
First entries
run_agent.py:6655: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 4 union elements`
run_agent.py:2187: [invalid-argument-type] invalid-argument-type: Argument to function `query_ollama_num_ctx` is incorrect: Expected `str`, found `(str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 5 union elements`
run_agent.py:6484: [invalid-argument-type] invalid-argument-type: Argument to function `_codex_cloudflare_headers` is incorrect: Expected `str`, found `Unknown | str | dict[str, str] | dict[Unknown, Unknown] | Divergent`
run_agent.py:2422: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `(Unknown & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | ... omitted 5 union elements`
run_agent.py:2470: [invalid-argument-type] invalid-argument-type: Argument to function `get_model_context_length` is incorrect: Expected `str`, found `str | dict[str, str] | Any | ... omitted 4 union elements`
run_agent.py:12548: [invalid-argument-type] invalid-argument-type: Argument to function `len` is incorrect: Expected `Sized`, found `(str & ~AlwaysFalsy) | (dict[Unknown, Unknown] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 4 union elements`
run_agent.py:2419: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `(Unknown & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | ... omitted 5 union elements`
run_agent.py:12545: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 4 union elements`
tests/agent/test_codex_cloudflare_headers.py:163: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | (dict[str, str] & ~AlwaysFalsy) | dict[Unknown, Unknown] | Divergent`
Unchanged: 4019 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
The quick setup flow (recommended for first-time users) silently defaulted terminal.backend to 'local' without ever presenting the choice. This meant new users who wanted Docker, SSH, Modal, Daytona, or any other backend had to know about 'hermes setup terminal' — which most wouldn't discover until later. Now the quick setup flow is: 1. Provider selection 2. API key 3. Terminal backend (local/Docker/Modal/SSH/Daytona/Vercel/Singularity) 4. Messaging platform 5. Done The terminal backend is a foundational decision (where ALL commands run) and belongs in the onboarding path alongside provider selection.
Problem
The quick setup flow (recommended for first-time users) silently defaulted
terminal.backendtolocalwithout presenting the choice. New users who wanted Docker, SSH, Modal, Daytona, or any other backend had to discoverhermes setup terminalon their own.Fix
Add
setup_terminal_backend(config)to_run_first_time_quick_setup()between provider selection and messaging setup.Quick setup flow is now:
Why terminal backend belongs in quick setup
hermes setupcompletion screen even mentionshermes setup terminalas a separate command, hinting that users were expected to run it manually — that's a UX gapTesting
tests/hermes_cli/test_setup_reconfigure.pyandtests/hermes_cli/test_setup.py— all pass