hermes-agent/hermes_cli
ygd58 866cdce209 fix(managed-uv): retry with explicit patch when bare-minor SQLite repair still resolves vulnerable
Fixes #71250.

`hermes update` could not repair the embedded Python runtime's
vulnerable SQLite (WAL-reset bug range 3.7.0-3.51.2, except backports
3.50.7/3.44.6) on installs where `uv python install <minor>` (bare
request, e.g. "3.11") resolves to an older cached/indexed patch that
still links a vulnerable SQLite build, even though a newer
non-vulnerable patch on the same minor line is available and known to
uv. The smoke test correctly rejected the vulnerable candidate every
time, but the provisioner gave up immediately after one attempt,
leaving the repair permanently stuck in the same failing loop on every
`hermes update` run.

Implements option D from the issue (query the index, retry with an
explicit newer patch), which the reporter identified as cleanest:

- New `_list_available_patches()`: runs `uv python list <minor>
  --all-versions --only-downloads --output-format json --no-config`,
  filters to cpython/default-variant entries (excluding pypy/graalpy),
  and returns known patch versions newest-first. Fails safe (returns
  []) on any network/parse error.
- Refactored the single install+find+probe cycle out of
  `_install_safe_python_generation()` into `_attempt_install_generation()`,
  reusable per attempt with its own generation directory (so a
  rejected candidate's files are fully cleaned up before the next
  attempt, matching the existing --reinstall semantics).
- `_install_safe_python_generation()` still tries the bare minor-line
  request first (preserves the original comment's rationale: for a
  given exact patch, python-build-standalone may have no artifact with
  fixed SQLite at all). If that resolves vulnerable, it now queries
  `_list_available_patches()` and retries with explicit newer patches,
  newest-first, bounded to `_MAX_PATCH_RETRIES` (5) attempts -- each
  attempt is a real download+install+probe cycle, so the cap keeps
  worst-case repair time bounded.

Sanity-checked `_list_available_patches()` against the real `uv`
binary (0.11.7) in this environment: correctly parses live `uv python
list --all-versions --output-format json 3.11` output, returns 14
patches sorted newest-first starting at 3.11.15.

9/9 new tests pass (retry succeeds with a newer patch, exhausts
gracefully when every known patch is vulnerable, empty patch list
degrades to None without crashing, retry count is bounded, plus direct
JSON-parsing unit tests for realistic/malformed/empty uv output);
47/47 in the full tests/hermes_cli/test_managed_uv.py file (including
the 3 pre-existing tests for the original bare-minor success path,
confirming no regression there).
2026-07-25 16:42:49 -07:00
..
dashboard_auth fix(dashboard): add lightweight /api/health liveness endpoint 2026-07-24 19:43:44 -05:00
proxy rip out brew + pip/PyPI wheel support (#68217) 2026-07-22 16:51:01 -04:00
subcommands feat(slack): support long app descriptions in the manifest generator 2026-07-23 12:01:24 -07:00
__init__.py chore: release v0.19.0 (2026.7.20) (#68175) 2026-07-20 11:35:21 -07:00
_early_recovery.py fix(ssl): detect and repair a missing certifi cacert.pem via existing venv-repair infra 2026-07-24 15:53:38 -07:00
_parser.py feat(cli): restore cwd on resume (--no-restore-cwd) 2026-07-12 05:08:13 -04:00
_subprocess_compat.py fix(windows): suppress console window flashes in env probes, lazy installs, and platform.win32_ver() 2026-07-23 18:20:24 -07:00
active_sessions.py fix(tui): preserve live session identity across compression (#49041) 2026-06-24 00:54:18 +05:30
auth.py fix(cli): add explicit encoding to read_text/write_text calls 2026-07-24 17:10:39 -07:00
auth_commands.py fix(auth): make xAI OAuth pools multi-account resilient 2026-07-17 11:37:25 +05:30
azure_detect.py fix(security): secure Azure catalog probes 2026-07-11 12:28:55 +05:30
backup.py fix(state): cross-process quarantine lock + oversized DB pruning suppression (#68805) 2026-07-24 23:06:05 -07:00
banner.py fix(cli): add explicit encoding to read_text/write_text calls 2026-07-24 17:10:39 -07:00
blueprint_cmd.py refactor(cron): rebrand Cron Recipes -> Automation Blueprints 2026-06-11 10:49:47 -07:00
browser_connect.py fix: /browser connect times out when another app squats the CDP port 2026-07-18 02:49:28 -07:00
build_info.py
bundles.py
callbacks.py fix(clarify): one canonical timeout across CLI, TUI/desktop, and gateway (#69774) 2026-07-22 23:25:13 -05:00
checkpoints.py fix(checkpoints): bind an empty orphan preview to an empty deletion allowlist 2026-07-24 16:01:06 -07:00
claw.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
cli_agent_setup_mixin.py fix(timeline): persist typed display events (#69771) 2026-07-23 14:46:24 -04:00
cli_billing_mixin.py feat(cli): plan catalog on Free + plan= deep link + top-up/auto-refill copy split (#68689) 2026-07-22 08:11:09 +05:30
cli_commands_mixin.py feat(relay): Phase 1 parity — supported_ops discovery, wire identity fields, /handoff aliasing, provision displayName (#71300) 2026-07-25 20:36:16 +10:00
cli_output.py
clipboard.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
codex_models.py fix(codex): send ChatGPT-Account-Id on /models probes 2026-07-21 05:27:13 -07:00
codex_runtime_plugin_migration.py
codex_runtime_switch.py refactor(codex-runtime): tidy reapply-migration control flow 2026-07-01 23:51:54 +05:30
colors.py
commands.py fix: repair sweep fallout — duplicate encoding kwargs, non-subprocess call sites, kwarg-snapshot tests 2026-07-24 11:45:57 -07:00
completion.py fix: batch of small robustness/correctness fixes from @kyssta-exe 2026-06-01 19:51:03 -07:00
config.py feat(aux): force streaming for providers that reject non-stream requests 2026-07-25 14:58:04 -07:00
console_engine.py rip out brew + pip/PyPI wheel support (#68217) 2026-07-22 16:51:01 -04:00
container_boot.py fix: add encoding="utf-8" to Path.write_text() calls (P1) 2026-07-24 17:10:39 -07:00
context_switch_guard.py fix(cli): honor custom_providers in preflight shrink warning 2026-07-22 21:17:21 -07:00
copilot_auth.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
credential_lifecycle.py fix(credentials): unified provider key delete/update across .env, auth.json, config.yaml (#67213) 2026-07-19 03:02:21 -07:00
cron.py fix(cron): preserve jobs.json ownership on root rewrite + surface failing-tick reason 2026-07-24 15:52:13 -07:00
curator.py feat(curator): add hermes curator usage — all-skills usage view 2026-07-06 12:26:21 -07:00
curses_ui.py Nous portal model pricing (#69579) 2026-07-22 16:47:06 -04:00
dashboard_register.py fix(cli): correct stale hermes auth login nous hints to hermes auth add nous (#53929) 2026-06-27 21:30:37 -07:00
debug.py fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336) 2026-07-05 13:42:46 -07:00
default_soul.py fix(soul): installers seed the real default persona, upgrade legacy empty templates (#52246) 2026-06-24 18:56:26 -07:00
dep_ensure.py fix(security): centralize credential-safe subprocess env (#29157) 2026-06-27 20:45:31 -07:00
diagnostics_upload.py feat(debug): drop dead confirm step from --nous upload (stateless NAS) 2026-06-30 17:29:23 -07:00
dingtalk_auth.py refactor(setup): route dependency installs through the canonical uv→pip→ensurepip ladder 2026-07-07 04:09:35 -07:00
doctor.py fix(cli): add explicit encoding to read_text/write_text calls 2026-07-24 17:10:39 -07:00
dump.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
env_loader.py fix(config): preserve opaque .env values 2026-07-24 16:02:08 -07:00
fallback_cmd.py
fallback_config.py fix(auth): honor per-entry key_env when resolving fallback providers 2026-07-16 07:19:36 -07:00
gateway.py fix(windows): sweep remaining bare read_text/write_text sites + linter rule 2026-07-24 17:10:39 -07:00
gateway_enroll.py feat(gateway): generic OIDC client-credentials relay provisioning (NAS-free) (#60730) 2026-07-08 16:55:32 +10:00
gateway_windows.py fix: repair sweep fallout — duplicate encoding kwargs, non-subprocess call sites, kwarg-snapshot tests 2026-07-24 11:45:57 -07:00
goals.py fix(goals): auto-pause goal loop on consecutive transport failures 2026-07-20 05:38:25 -07:00
gui_uninstall.py feat: uninstall the Chat GUI without removing the agent (CLI + desktop UI) (#40355) 2026-06-06 18:22:38 -07:00
hooks.py feat(agent): add pre_verify hook and verify-on-stop coding guidance 2026-06-30 00:59:29 -05:00
input_sanitize.py fix(input): strip bracketed-paste leaks before prompt persistence (#62557) 2026-07-15 07:39:42 -07:00
inventory.py fix(api-server): expose model options inventory 2026-07-24 11:20:07 -07:00
journey.py fix(cli): render /journey color instead of leaking raw ANSI 2026-07-01 16:25:48 -05:00
kanban.py fix(kanban): harden delegated-child mutation boundary 2026-07-23 07:33:36 -07:00
kanban_db.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
kanban_decompose.py fix(auxiliary): route direct-create aux callers through call_llm (#65029) 2026-07-15 07:39:17 -07:00
kanban_diagnostics.py fix(kanban): clear failure/crash diagnostics while a retry is in flight 2026-07-09 16:13:59 -05:00
kanban_specify.py fix(auxiliary): route direct-create aux callers through call_llm (#65029) 2026-07-15 07:39:17 -07:00
kanban_swarm.py refactor(kanban): fold worker/orchestrator skills into injected guidance (#50473) 2026-06-21 17:06:48 -07:00
logs.py fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336) 2026-07-05 13:42:46 -07:00
main.py fix(sessions): point failed in-place repair at offline recovery 2026-07-25 16:42:31 -07:00
managed_scope.py fix(managed-scope): honor managed scope in all standalone config loaders 2026-06-19 07:46:33 -07:00
managed_uv.py fix(managed-uv): retry with explicit patch when bare-minor SQLite repair still resolves vulnerable 2026-07-25 16:42:49 -07:00
mcp_catalog.py feat(mcp): enforce exact version pins across the whole MCP catalog 2026-07-15 04:56:25 -07:00
mcp_config.py fix(mcp): close hosted OAuth lifecycle gaps 2026-07-17 04:50:47 -07:00
mcp_picker.py
mcp_security.py fix(security): close hermes-0day MCP-persistence attack surface 2026-06-21 19:05:27 -07:00
mcp_startup.py fix(mcp): allow background discovery retry after a run that connected nothing 2026-07-21 12:43:27 -07:00
memory_oauth.py feat(memory): Honcho OAuth connect — desktop and CLI flows + token refresh (#44335) 2026-06-22 19:16:47 -05:00
memory_setup.py fix(memory-setup): sanitize .env values in the core writer too 2026-07-24 13:00:53 +05:30
middleware.py fix(middleware): single-use next_call guard + deepcopy-safe request copies 2026-06-06 23:07:25 +05:30
migrate.py
moa_cmd.py feat(moa): add reference model toggles 2026-07-23 18:11:57 -07:00
moa_config.py feat(moa): default advisor fanout to user_turn — the cheapest cadence 2026-07-23 21:07:18 -07:00
model_catalog.py feat(models): catalog-labeled silent default — GLM-5.2 marked "default": true in the model catalog 2026-07-15 00:10:31 -07:00
model_cost_guard.py fix(model): require confirmation for expensive model selections 2026-06-10 00:24:06 -07:00
model_normalize.py fix(gemini): strip native self prefixes before generateContent (#36141) 2026-06-13 13:47:08 -07:00
model_setup_flows.py fix(cli): store custom endpoint API key in .env instead of config.yaml 2026-07-24 21:12:53 -05:00
model_switch.py fix(models): resolve custom provider model ids 2026-07-24 21:24:36 -05:00
models.py feat(models): add anthropic/claude-opus-5 to OpenRouter and Nous Portal catalogs 2026-07-24 13:00:15 -07:00
nous_account.py feat(billing): /credits command — balance + portal top-up handoff (#44776) 2026-06-12 08:51:10 +00:00
nous_auth_keepalive.py fix Nous auth refresh for idle agents 2026-06-21 22:43:48 -07:00
nous_billing.py fix(billing): rename user-facing "terminal billing" copy to Remote Spending (#68355) 2026-07-21 12:20:25 +05:30
nous_subscription.py fix(browser): validate agent-browser is runnable, not just present (#51740) 2026-06-24 00:14:49 -07:00
onepassword_secrets_cli.py fix: extend UTF-8 encoding to _op_version probe (#53428) 2026-07-24 11:45:57 -07:00
oneshot.py fix: preserve named custom provider vision overrides 2026-07-23 17:57:33 +05:30
pairing.py
partial_compress.py feat(commands): /compact alias + --preview/--dry-run flags for /compress (#3243 salvage) 2026-07-02 05:10:31 -07:00
pets.py feat(pets): generation RPCs, non-blocking gallery + gateway plumbing 2026-06-24 13:48:38 -05:00
platforms.py
plugins.py fix(windows): sweep remaining bare read_text/write_text sites + linter rule 2026-07-24 17:10:39 -07:00
plugins_cmd.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
portal_cli.py fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336) 2026-07-05 13:42:46 -07:00
profile_describer.py fix(auxiliary): route direct-create aux callers through call_llm (#65029) 2026-07-15 07:39:17 -07:00
profile_distribution.py revert(windows): roll back terminal-popup PRs #53791 #53810 #53829 (#53853) 2026-06-27 15:59:00 -07:00
profiles.py fix: add encoding="utf-8" to Path.write_text() calls (P1) 2026-07-24 17:10:39 -07:00
projects_cmd.py feat(projects): add per-profile project store 2026-06-25 16:40:26 -05:00
projects_db.py feat(desktop): configure repository discovery (supersedes #67630) (#68642) 2026-07-21 10:09:31 -04:00
prompt_size.py fix(prompt-size): respect enabled/disabled toolsets per platform 2026-07-05 19:13:20 -07:00
provider_catalog.py feat(moa): expose MoA presets as selectable virtual models (#46081) 2026-06-25 13:52:06 -07:00
providers.py fix(vertex,moa): register vertex in PROVIDER_REGISTRY and HERMES_OVERLAYS 2026-07-23 16:55:41 -07:00
proxy_cli.py Reapply "Merge pull request #30179 from NousResearch/feat/iron-proxy" 2026-07-24 09:49:00 -07:00
psutil_android.py
pt_input_extras.py
pty_bridge.py fix(pty-bridge): mark os.killpg/getpgid windows-footgun-ok (POSIX-only module) 2026-06-08 07:03:12 -07:00
pty_session.py feat(pty): periodic reaper wired into dashboard lifespan 2026-07-07 15:15:37 -07:00
relaunch.py revert(windows): roll back terminal-popup PRs #53791 #53810 #53829 (#53853) 2026-06-27 15:59:00 -07:00
route_identity.py fix: restore base_url rstrip, extract should_clear_context_pin helper 2026-07-22 11:19:37 +05:30
runtime_provider.py fix(tui_gateway): recover custom provider identity from the session's model name 2026-07-24 10:47:32 -07:00
secret_prompt.py feat(memory): improve OpenViking setup UX 2026-06-17 01:04:26 +08:00
secrets_cli.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
security_advisories.py fix(stt,tts): restore mistralai — 2.4.8 is clean, ban lifted (#34841) 2026-05-29 13:24:12 -07:00
security_audit.py
security_audit_startup.py style(security-audit): add explicit encoding to read_text calls (ruff PLW1514) 2026-06-21 19:05:27 -07:00
send_cmd.py fix(managed-scope): honor managed scope in config→env bridges too 2026-06-19 07:46:33 -07:00
service_manager.py fix: add encoding="utf-8" to Path.write_text() calls (P1) 2026-07-24 17:10:39 -07:00
session_export.py feat: add prompt-only session export 2026-07-07 13:29:58 -07:00
session_export_html.py fix(session-export): escape html tool call names 2026-07-09 19:54:02 -07:00
session_export_md.py feat(sessions): full prune-filter set + --redact on sessions export 2026-07-07 12:36:41 -07:00
session_filters.py feat(sessions): full filter surface for prune + bulk archive subcommand (#59327) 2026-07-05 22:04:52 -07:00
session_listing.py feat(gateway): add /sessions search <query> (#57685) 2026-07-03 13:44:00 -07:00
session_recap.py fix(cli): sanitize terminal escapes when replaying stored history (/resume recap, /status recap) 2026-07-17 04:53:38 -07:00
session_recovery.py fix(sessions): add offline state database recovery 2026-07-25 16:42:31 -07:00
setup.py fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
setup_whatsapp_cloud.py fix(whatsapp-cloud): review follow-ups for #43921 2026-06-11 07:51:01 -07:00
skills_config.py fix(cli): normalize malformed skills config in get_disabled_skills (#61797) 2026-07-09 19:57:54 -07:00
skills_hub.py fix: widen UTF-8 BOM tolerance to all sibling frontmatter parsers 2026-07-17 04:52:02 -07:00
skin_cmd.py feat(themes): hermes skin set — deterministic one-color tweak, bg untouched 2026-07-21 21:00:43 -05:00
skin_engine.py feat(themes): dedicated code-syntax palette keys 2026-07-21 21:00:43 -05:00
slack_cli.py feat(slack): support long app descriptions in the manifest generator 2026-07-23 12:01:24 -07:00
sqlite_runtime.py fix(runtime): repair vulnerable managed SQLite builds (E-949) 2026-07-24 16:00:03 -07:00
sqlite_util.py feat(projects): add per-profile project store 2026-06-25 16:40:26 -05:00
status.py fix(cron): accept UTF-8 BOM when reading jobs.json 2026-07-18 02:31:20 -07:00
stdio.py
suggestions_cmd.py fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336) 2026-07-05 13:42:46 -07:00
telegram_managed_bot.py Add CLI Telegram QR onboarding 2026-06-05 03:20:10 -07:00
timeouts.py
tips.py fix(cli): widen startup worktree pruning to all .worktrees/ trees and detect squash-merged work (#69831) 2026-07-23 07:33:07 -07:00
tools_config.py fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
toolset_validation.py fix(config): surface invalid platform_toolsets instead of silently dropping tools (#38798) 2026-06-26 14:07:43 +05:30
uninstall.py fix: add encoding="utf-8" to Path.write_text() calls (P1) 2026-07-24 17:10:39 -07:00
urllib_security.py fix(security): order sanitizer after installed hooks 2026-07-11 12:28:55 +05:30
voice.py
web_git.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
web_server.py Merge pull request #71141 from NousResearch/bb/custom-endpoint-keys-and-models 2026-07-24 22:09:53 -05:00
webhook.py fix: repair sweep fallout — duplicate encoding kwargs, non-subprocess call sites, kwarg-snapshot tests 2026-07-24 11:45:57 -07:00
win_pty_bridge.py feat(windows): enable dashboard /chat tab via ConPTY (win_pty_bridge) + tests (#42251) 2026-06-08 11:32:43 -07:00
windows_ssh_runtime.py fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
write_approval_commands.py refactor(memory,skills): replace tri-state write_mode with boolean write_approval (default off) (#43354) 2026-06-09 23:21:14 -07:00
xai_retirement.py fix(config): guard xai migration writer + drop gratuitous annotation 2026-07-05 23:00:34 +05:30