hermes-agent/tests/cli
teknium1 776c43befe perf(cli): cut hermes -w startup from ~14s to ~1.8s by parallelizing + caching the worktree prune
`_prune_stale_worktrees` runs synchronously before the banner on every
`hermes -w` launch and shells out to git several times per candidate
worktree. On a repo with dozens of accumulated worktrees this dominated
startup: measured 18.5s of a 20.6s cold start, 11.6s on warm repeats.

The `git cherry` patch-equivalence probe was the single largest cost
(9.4s of 11.5s across 24 trees). It is also pure waste on repeat runs: a
tree preserved because it holds unpushed work is re-diff-hashed on every
launch, forever, always reaching the same verdict. On this repo 19 of 24
aged trees were unreapable, so ~11s per launch bought zero reaps.

Two changes, both verdict-preserving:

- Split the loop into a stat-only age filter, a parallel read-only
  classification phase (thread pool, bounded to min(8, cpu_count)), and
  a serial mutation phase. Only reads are concurrent; unlock/remove/
  branch -D stay ordered, so log output and removal order are unchanged.
  A pool failure falls back to serial rather than blocking startup.
- Memoize `git cherry` verdicts to
  $HERMES_HOME/cache/worktree_merge_verdicts.json, keyed on the exact
  `(base_sha, head_sha, max_ahead)` range the verdict was computed from.
  Because that key is the complete input to the git call, a cache hit is
  identical to recomputation by construction: if either ref moves, the
  key changes and real git runs again. Bounded to 1000 entries, written
  atomically, and a corrupt/hand-edited cache degrades to recomputation.

Measured on a 44-worktree repo (24 aged candidates):

  _prune_stale_worktrees   before 11.5s   after 2.05s cold / 0.42s warm
  hermes -w to banner      before 13.9s   after 1.79s

Work-preservation is unchanged: all 44 worktrees survived, and every
dirty/unpushed/live-locked guard still fires. Verified the 24 real-tree
verdicts are byte-identical across serial, cold-cache, and warm-cache
runs.

Tests: 75/75 in tests/cli/test_worktree.py (67 existing + 8 new). The
new cache tests were sabotage-verified — swapping the exact-sha key for a
naive path-only key makes two of them fail by deleting a worktree that
had gained unmerged work, which is the data-loss case the key prevents.
2026-07-25 16:41:52 -07:00
..
__init__.py
test_bracketed_paste_timeout.py
test_branch_command.py test: update mock assertions for conversation_history kwarg 2026-07-22 10:00:39 +05:30
test_busy_input_mode_command.py
test_chat_q_exit_clear.py fix(cli): preserve chat -q answer by gating exit-summary screen clear (#53009) 2026-07-08 07:59:24 -07:00
test_cli_active_agent_ref_wiring.py
test_cli_approval_ui.py fix(approval): scope smart deny owner overrides to one operation 2026-07-13 04:31:55 -07:00
test_cli_async_delegation_delivery.py fix(cli): scope async delegation delivery to session 2026-07-14 22:14:10 -07:00
test_cli_background_status_indicator.py
test_cli_background_tui_refresh.py
test_cli_bracketed_paste_sanitizer.py
test_cli_browser_connect.py test: stub discover_local_cdp_url in CLI connect context-note test 2026-07-18 02:49:28 -07:00
test_cli_codex_context_reference.py fix(context): scope Codex catalogue cache by credential 2026-07-21 04:29:34 -07:00
test_cli_context_warning.py
test_cli_copy_command.py
test_cli_delegate_background_notice.py
test_cli_extension_hooks.py
test_cli_external_editor.py fix(cli,tui): recall real paste content on up-arrow 2026-07-20 23:23:40 -05:00
test_cli_file_drop.py
test_cli_force_redraw.py
test_cli_goal_interrupt.py fix: migrate CLI kanban gate + remaining mocks to 5-value judge contract 2026-07-20 05:38:25 -07:00
test_cli_image_command.py
test_cli_init.py refactor: drop platform kwarg, fix PTY test cleanup 2026-07-21 11:18:28 +05:30
test_cli_insights_command.py
test_cli_interrupt_ack_race.py test(cli): cover noted multimodal persistence handoff 2026-07-14 03:32:46 +05:30
test_cli_interrupt_drain_regression.py fix(cli): re-land interrupt_queue drain so finished turns flush stray input 2026-07-01 00:12:32 -07:00
test_cli_interrupt_subagent.py fix(ci): make tests, workflows, and attribution reliable under load (#66373) 2026-07-17 20:55:24 +00:00
test_cli_light_mode.py
test_cli_loading_indicator.py
test_cli_markdown_rendering.py
test_cli_mcp_config_watch.py fix(mcp): move auto-reload opt-out to top-level mcp: section + regression tests 2026-07-20 00:41:05 -07:00
test_cli_new_session.py refactor: address Phase-2 review findings on /new boundary handoff 2026-07-09 03:21:54 +05:30
test_cli_pet_pane.py
test_cli_prefix_matching.py
test_cli_preloaded_skills.py
test_cli_provider_resolution.py test: cover custom endpoint key storage and model-list persistence 2026-07-24 21:12:59 -05:00
test_cli_reload_skills.py
test_cli_resume_command.py fix(timeline): persist typed display events (#69771) 2026-07-23 14:46:24 -04:00
test_cli_retry.py
test_cli_save_config_value.py
test_cli_secret_capture.py
test_cli_shift_enter_newline.py
test_cli_shutdown_memory_messages.py fix(session): preserve clean shortened close snapshots 2026-07-14 03:32:46 +05:30
test_cli_skin_integration.py
test_cli_status_bar.py fix(test): pin monotonic clock in spinner-elapsed test to fix CI flake (#54203) 2026-06-28 04:16:25 -07:00
test_cli_status_command.py Reapply "Merge pull request #30179 from NousResearch/feat/iron-proxy" 2026-07-24 09:49:00 -07:00
test_cli_steer_busy_path.py
test_cli_terminal_response_sanitizer.py
test_cli_terminal_shortcuts.py
test_cli_tools_command.py
test_cli_user_message_preview.py
test_cli_yolo_toggle.py
test_compress_flags.py feat(commands): /compact alias + --preview/--dry-run flags for /compress (#3243 salvage) 2026-07-02 05:10:31 -07:00
test_compress_focus.py
test_compress_here.py fix: prevent stale lock-skip signal leaking between compress_context calls 2026-07-23 08:19:14 -07:00
test_compress_type_ahead.py test(cli): prove /compress type-ahead queue-drain; map contributor email 2026-07-23 07:24:46 -07:00
test_cpr_local_leak.py refactor: drop platform kwarg, fix PTY test cleanup 2026-07-21 11:18:28 +05:30
test_cprint_bg_thread.py
test_ctrl_enter_newline.py
test_cwd_env_respect.py
test_destructive_slash_confirm.py
test_destructive_slash_inline_skip_e2e.py
test_exit_delete_session.py
test_exit_summary_resume_hint.py
test_exit_watchdog_signal_arm.py fix(cli): arm exit watchdog on shutdown signal, not at chat startup (#66278) 2026-07-17 06:49:04 -07:00
test_fast_command.py fix: session-scoped /fast + full /new reset to config defaults (#67979) 2026-07-20 03:27:22 -07:00
test_manual_compress.py fix(compress): classify unconfirmed lock-acquire failures and cover all manual-compress surfaces 2026-07-23 08:19:14 -07:00
test_moa_command.py feat(moa): add reference model toggles 2026-07-23 18:11:57 -07:00
test_partial_compress.py
test_personality_none.py
test_prefill_config.py
test_prepend_note_to_message.py
test_prompt_text_input_thread_safety.py
test_quick_commands.py
test_reasoning_command.py fix: session-scoped /fast + full /new reset to config defaults (#67979) 2026-07-20 03:27:22 -07:00
test_resume_display.py fix(timeline): persist typed display events (#69771) 2026-07-23 14:46:24 -04:00
test_resume_quiet_stderr.py
test_save_conversation_location.py
test_session_boundary_hooks.py
test_single_query_session_finalize.py test(cli): update FakeCLI._print_exit_summary for new clear_screen kwarg 2026-07-08 07:59:24 -07:00
test_slash_command_interrupt.py
test_slash_confirm_windows.py
test_steer_inline_repaint_34569.py
test_stream_delta_think_tag.py fix: make streaming reasoning-tag filter case-insensitive 2026-07-01 03:25:02 -07:00
test_stream_partial_line_flush.py perf(cli): TTFT round 2 — live reasoning by default, partial-line streaming, prompt-build cache, stale budget-warning docs (#59389) 2026-07-06 00:16:38 -07:00
test_surrogate_sanitization.py
test_terminal_interrupt_recovery.py refactor(cli): extract interrupt recovery to a testable helper 2026-06-28 01:08:09 -07:00
test_tool_progress_scrollback.py
test_tui_terminal_reset_on_exit.py
test_update_command.py rip out brew + pip/PyPI wheel support (#68217) 2026-07-22 16:51:01 -04:00
test_version_command.py
test_worktree.py perf(cli): cut hermes -w startup from ~14s to ~1.8s by parallelizing + caching the worktree prune 2026-07-25 16:41:52 -07:00
test_worktree_security.py fix(cli): read .worktreeinclude and .gitignore as UTF-8 in worktree setup 2026-07-24 17:10:39 -07:00
test_worktree_sync_base.py