hermes-bsd/hermes_cli
Ben b28b3f51d3
fix(service_manager): friendly errors for missing slots and s6-svc failures
PR #30136 review caught: `S6ServiceManager.start/stop/restart` called
`subprocess.run(check=True)` on `s6-svc`, so any failure surfaced as
a raw `CalledProcessError` traceback. The two cases operators
actually hit are:

  1. The service slot doesn't exist — most commonly because the user
     typed a profile name wrong (`hermes -p typo gateway start`).
  2. s6-svc itself fails — most commonly EACCES on the supervise
     control FIFO when running unprivileged.

Both deserve named errors with actionable messages, not stacktraces.

Changes:

* Add `S6Error` base + two concrete errors in `hermes_cli.service_manager`:
    - `GatewayNotRegisteredError(profile)` — carries the unprefixed
      profile name; message: `no such gateway 'typo': register it
      with `hermes profile create typo` first, or pass an existing
      profile name via `-p <name>``.
    - `S6CommandError(service, action, returncode, stderr)` — carries
      the s6-svc rc and stderr; message: `s6-svc start on
      'gateway-coder' failed (rc=111): <stderr>`.

* Factor lifecycle dispatch through `_run_svc(flag, label, name)`:
  pre-checks that the service directory exists (raises
  GatewayNotRegisteredError before invoking s6-svc), then runs
  s6-svc and translates any CalledProcessError into S6CommandError.

* `_dispatch_via_service_manager_if_s6` in `hermes_cli.gateway`
  catches both errors and prints `✗ <message>` + `sys.exit(1)`
  instead of letting the exception bubble. The dispatch path that
  used to dump a traceback at the user now gives an actionable
  one-liner.

Tests: 6 new tests for the error types and their CLI rendering;
existing lifecycle test pre-seeds the slot directory before calling
`mgr.start` etc.
2026-05-24 18:05:33 -07:00
..
proxy fix(security): validate Nous Portal inference_base_url against host allowlist 2026-05-22 14:17:40 -07:00
__init__.py
_parser.py Fix CLI verbose tool progress config fallback 2026-05-23 21:03:51 -07:00
_subprocess_compat.py
auth.py security: harden API server key placeholder handling (#30738) 2026-05-24 04:25:32 -07:00
auth_commands.py
azure_detect.py
backup.py
banner.py
browser_connect.py feat: auto-launch Chromium-family browser for CDP 2026-05-19 22:34:05 -07:00
bundles.py feat(skills): add skill bundles — alias /<name> loads multiple skills (#28373) 2026-05-18 21:38:05 -07:00
callbacks.py
checkpoints.py
claw.py
cli_output.py
clipboard.py
codex_models.py
codex_runtime_plugin_migration.py
codex_runtime_switch.py
colors.py
commands.py feat(skills): add opt-in AST deep diagnostics 2026-05-23 17:47:26 -07:00
completion.py
config.py feat(docker): remove gosu from bundled image; s6-setuidgid handles privilege drop 2026-05-24 18:05:33 -07:00
container_boot.py fix(container_boot): always register gateway-default slot 2026-05-24 18:05:33 -07:00
copilot_auth.py
cron.py
curator.py
curses_ui.py fix(cli): clamp curses color 8 for 8-color terminals (Docker) 2026-05-21 23:40:58 -07:00
debug.py fix(debug): redact BlueBubbles webhook secrets 2026-05-24 15:43:48 -07:00
default_soul.py
dep_ensure.py
dingtalk_auth.py
doctor.py docs(s6): document container supervision; doctor + skill + user-guide updates 2026-05-24 18:05:33 -07:00
dump.py fix(skills): prune dependency/venv dirs from all skill scanners (#30042) 2026-05-21 14:18:02 -07:00
env_loader.py feat(secrets/bitwarden): EU Cloud + self-hosted server URL support (#31378) 2026-05-24 02:19:57 -07:00
fallback_cmd.py fix(fallback): merge fallback_providers with legacy fallback_model configurations 2026-05-23 05:24:57 -07:00
fallback_config.py fix(fallback): merge fallback_providers with legacy fallback_model configurations 2026-05-23 05:24:57 -07:00
gateway.py fix(service_manager): friendly errors for missing slots and s6-svc failures 2026-05-24 18:05:33 -07:00
gateway_windows.py fix(gateway-windows): atomic write for .cmd and startup launcher scripts 2026-05-23 02:30:41 -07:00
goals.py
hooks.py
inventory.py
kanban.py feat(kanban): --ids bulk promote + AUTHOR_MAP entry for #29464 2026-05-23 23:10:36 -07:00
kanban_db.py fix(kanban): scratch tasks must not inherit board.default_workdir (#28818) 2026-05-24 15:48:58 -07:00
kanban_decompose.py fix: assign single-task kanban decompositions 2026-05-18 20:26:02 -07:00
kanban_diagnostics.py fix(kanban): honor severity thresholds in diagnostics 2026-05-18 20:47:01 -07:00
kanban_specify.py
kanban_swarm.py feat(cli): add kanban swarm topology helper 2026-05-18 21:10:12 -07:00
logs.py
main.py feat(security): on-demand supply-chain audit via OSV.dev (#31460) 2026-05-24 15:15:16 -07:00
mcp_config.py
memory_setup.py
migrate.py feat(cli): hermes migrate xai [--apply] [--no-backup] 2026-05-20 09:18:23 -07:00
model_catalog.py
model_normalize.py
model_switch.py fix(model-switch): mark bare custom provider as current 2026-05-19 10:57:35 -07:00
models.py
nous_subscription.py
oneshot.py fix(provider): make config.yaml model.provider the single source of truth (#31222) 2026-05-23 18:18:41 -07:00
pairing.py
platforms.py
plugins.py feat(tts): add register_tts_provider() plugin hook (closes #30398) 2026-05-24 18:04:54 -07:00
plugins_cmd.py fix(plugins): widen _sanitize_plugin_name for category-namespaced names 2026-05-22 19:50:32 -07:00
portal_cli.py feat(portal): one-shot setup, status CLI, and Nous-included markers (#30860) 2026-05-23 02:39:09 -07:00
profile_describer.py fix(skills): prune dependency/venv dirs from all skill scanners (#30042) 2026-05-21 14:18:02 -07:00
profile_distribution.py fix(skills): prune dependency/venv dirs from all skill scanners (#30042) 2026-05-21 14:18:02 -07:00
profiles.py feat(docker): per-profile s6 supervision + container-restart reconciliation 2026-05-24 18:05:33 -07:00
providers.py
pt_input_extras.py
pty_bridge.py
relaunch.py
runtime_provider.py fix(custom): pass custom provider extra body 2026-05-21 07:48:53 -07:00
secrets_cli.py feat(secrets/bitwarden): EU Cloud + self-hosted server URL support (#31378) 2026-05-24 02:19:57 -07:00
security_advisories.py
security_audit.py feat(security): on-demand supply-chain audit via OSV.dev (#31460) 2026-05-24 15:15:16 -07:00
send_cmd.py
service_manager.py fix(service_manager): friendly errors for missing slots and s6-svc failures 2026-05-24 18:05:33 -07:00
session_recap.py
setup.py fix(matrix,gateway): Matrix E2EE installs full dep set; plugins respect is_connected 2026-05-24 15:16:03 -07:00
skills_config.py
skills_hub.py refactor(skills): slim AST diagnostic to single entry point 2026-05-23 17:47:26 -07:00
skin_engine.py
slack_cli.py
status.py refactor(ntfy): convert built-in adapter to platform plugin 2026-05-23 16:13:01 -07:00
stdio.py
timeouts.py perf(agent-loop): cut 47% of per-conversation function calls via 3 targeted hot-path optimizations (#28866) 2026-05-19 14:25:10 -07:00
tips.py feat: auto-launch Chromium-family browser for CDP 2026-05-19 22:34:05 -07:00
tools_config.py feat(tts): add register_tts_provider() plugin hook (closes #30398) 2026-05-24 18:04:54 -07:00
uninstall.py
vercel_auth.py
voice.py
web_server.py Protect dashboard OAuth credentials with the same file-safety guarantees as other auth paths 2026-05-24 17:47:24 -07:00
webhook.py fix(state): restrict sensitive store file permissions 2026-05-24 04:55:18 -07:00
xai_retirement.py fix(xai): align migrate retirement map with docs 2026-05-20 09:18:23 -07:00