Self-review of #38465 surfaced three real items:
1. SystemExit escape (defense): `_login_nous` raises SystemExit(130)/(1) on
cancel/failure. The logged-out login path inside `_model_flow_nous` catches
it, but the expired-session re-login path (main.py) only catches Exception,
so a Ctrl-C during re-auth could propagate past `_run_portal_one_shot` and
kill the CLI. Add SystemExit to the portal handler so all cancel/abort cases
end with the graceful 'Setup cancelled / retry later' message.
2. Doc sweep: the model-pick step was only added to the bare-`hermes portal`
prose. Propagate it to the surfaces describing `hermes setup --portal`
behavior that still omitted model selection:
- `--portal` argparse help (main.py)
- nous-portal.md intro + the numbered 'what it does' step list (EN + zh-Hans)
- run-hermes-with-nous-portal.md 'default model after setup --portal' line,
which was now contradictory (there's a picker, not a forced default) (EN + zh)
3. Test coverage: add parametrized regression test asserting the portal handler
swallows KeyboardInterrupt / EOFError / SystemExit (returns None, no escape).
Note on 'Skip (keep current)': delegating to _model_flow_nous means picking
Skip preserves the prior provider instead of force-switching to nous — this is
intentional and matches quick setup exactly; docs now say 'sets Nous as your
provider (when you pick a model)' rather than unconditionally.
`hermes portal` / `hermes setup --portal` previously logged in and set
provider=nous but left the model UNSELECTED (blank -> runtime default) and
never showed a picker — unlike the first-time quick setup, which runs the
model picker.
Route `_run_portal_one_shot` through `_model_flow_nous` — the exact same
routine quick setup (`_run_first_time_quick_setup`) and `hermes model` -> Nous
use. It handles both the logged-out path (device-code OAuth, which picks a
model internally) and the logged-in path (curated Nous model picker), then
offers the Tool Gateway opt-in and sets provider=nous. Net effect: `hermes
portal` now offers a model picker every time and is a true single-command
collapse of quick setup's Nous step.
Removes the hand-rolled auth_add_command + manual provider write + separate
Tool Gateway prompt (now a single source of truth). Re-syncs the in-memory
config from disk afterward so a caller's later save_config can't clobber the
model/provider written by the login flow.
Docs (CLI help, portal_cli docstrings, nous-portal EN + zh-Hans) updated to
mention model selection. New regression test asserts `_run_portal_one_shot`
delegates to `_model_flow_nous`.
Verified live: `hermes portal` now shows the 27-model curated picker, 'Skip
(keep current)' preserves prior provider/model.
`hermes portal` (no subcommand) now runs the one-shot Nous Portal onboarding
— OAuth login, switch provider to Nous, offer Tool Gateway — identical to
`hermes setup --portal` and the human-readable alias for
`hermes auth add nous --type oauth` (which still works).
The prior status default moves to `hermes portal info`; `status` is kept as a
hidden back-compat alias. `open`/`tools` subcommands are unchanged.
User-facing hints and docs (status.py, conversation_loop 401 guidance,
SystemPage, README, website docs + zh-Hans) now point at `hermes portal` /
`hermes portal info`. `--manual-paste` references keep the explicit auth
command since `hermes portal` does not expose that flag.