feat: PyPI wheel packaging — pip install hermes-agent && hermes (salvage of #26350)#26593
Merged
Conversation
For pip-installed hermes-agent (no .git directory), fall back to querying PyPI's JSON API to compare __version__ against the latest published release, using stdlib only (urllib + json, no packaging dep).
…bootstrap Adds --ensure DEPS for pip-runtime dep installation and --postinstall for pip users who want the full post-install experience without cloning.
When cli-config.yaml.example is not present (e.g. pip wheel install), fall back to writing DEFAULT_CONFIG via save_config() instead of warning and requiring a manual fix.
…hermes/node_modules Extract PATH building into _build_service_path_dirs() that skips directories which don't exist on disk (e.g. node_modules/.bin for pip installs) and also includes ~/.hermes/node/bin and ~/.hermes/node_modules/.bin for agent-browser.
…m build Add _find_bundled_tui() that checks for hermes_cli/tui_dist/entry.js (present in wheel installs) and wire it into _make_tui_argv() between the HERMES_TUI_DIR prebuilt path and the npm install fallback.
…command Adds detect_install_method() to identify nixos/homebrew/git/pip installs, and recommended_update_command_for_method() to return the right upgrade command for each method. Updates recommended_update_command() to use these for pip-installed instances (no .git dir, not managed).
When .git is absent and detect_install_method returns "pip", fork hermes update to run `uv pip install --upgrade hermes-agent` (or `python -m pip install --upgrade hermes-agent` as fallback) instead of hard-exiting with "Not a git repository".
…ffold Match the full set of subdirs created by install.sh: pairing, hooks, image_cache, audio_cache, and skills are now pre-created alongside the existing cron, sessions, logs, logs/curator, and memories dirs. This makes hermes doctor checks cleaner without changing any runtime behaviour.
Includes paired change: browser tool now searches ~/.hermes/node_modules/.bin/ for agent-browser installed via install.sh --ensure browser.
…ate update command - banner.py: remove redundant `import json as _json` (json already at module level) - main.py: _cmd_update_pip now delegates to recommended_update_command_for_method instead of duplicating the uv-vs-pip detection logic - main.py: remove redundant `import subprocess as _sp` (subprocess already at module level)
_cmd_update_check() had its own `.git` gate separate from _cmd_update_impl. For pip installs, fork to _check_via_pypi() and display the result with the correct recommended_update_command().
Before: missing node → hard exit; missing browser → FileNotFoundError. After: both try ensure_dependency() first, which prompts interactively and delegates installation to install.sh --ensure. ripgrep and ffmpeg already degrade gracefully (grep fallback, skip conversion) so they don't need wiring. Also documents the design rationale in dep_ensure.py: detection and prompting live in Python (portable, instant, UX-integrated); only the actual installation delegates to install.sh (1900 lines of battle-tested OS/package-manager logic).
One-shot bootstrap that installs non-Python deps (node, browser, ripgrep, ffmpeg) via ensure_dependency(), then runs setup if no provider is configured. Closes the gap between `pip install` and the full user-facing experience. Also fixes 3 pre-existing test regressions caused by earlier commits: - test_recommended_update_command: mock detect_install_method for git env - test_check_for_updates_no_git_dir: now falls back to PyPI, not None - test_plist_path_includes_node_modules_bin: skip when dir absent
… CLI reference Document pip install hermes-agent as a first-class install option. Clarify that PyPI releases track tagged versions (major/minor), not every commit on main — git installer is for bleeding-edge.
- dep_ensure.py: use get_hermes_home() instead of hand-rolled env var - dep_ensure.py: add "chrome" to browser name list (was inconsistent with browser_tool.py) - main.py _cmd_update_check: use detect_install_method() directly instead of redundant .git check - main.py _cmd_update_pip: build command list directly instead of fragile split() on display string - banner.py: rename _check_via_pypi → check_via_pypi (cross-module public API)
… --check description - installation.md: add tip about `hermes postinstall` for upfront dep install - quickstart.md: show `hermes postinstall` in pip install flow - updating.md: fix --check description to mention PyPI path for pip installs
Contributor
🔎 Lint report:
|
Collaborator
|
Salvage/supersede of #26350 (by @alt-glitch) — cherry-picks all 19 commits with authorship preserved. If this merges, #26350 should be closed. |
5 tasks
This was referenced May 15, 2026
Closed
1 task
alt-glitch
added a commit
that referenced
this pull request
May 18, 2026
…sh,ps1}
Eliminates 687 lines of duplicated browser bootstrap code by routing all
bootstrap paths through dep_ensure.py -> install.{sh,ps1} --ensure.
install.sh:
- New ensure_browser() with agent-browser + camofox install, system browser
detection + .env writing, per-distro Playwright deps (apt/arch/fedora/suse)
- macOS app-bundle paths added to find_system_browser()
- configure_browser_env_from_system_browser() creates .env if missing
- postinstall_mode() uses ensure_browser() instead of inline duplication
install.ps1:
- New -Ensure and -PostInstall params (coexists with stage protocol)
- New functions: Resolve-NpmCmd, Resolve-NpxCmd, Find-SystemBrowser,
Write-BrowserEnv, Install-AgentBrowser (with -SkipPlaywright)
- Invoke-EnsureMode dispatches node/browser/ripgrep/ffmpeg
- Invoke-PostInstallMode runs full post-pip-install bootstrap
- ErrorActionPreference guards on all native command calls
- ASCII-only convention maintained (no Unicode)
- Mutual exclusion guard: -Ensure + -Stage = error
dep_ensure.py:
- Windows-aware: _IS_WINDOWS, _find_install_script returns (path, shell) tuple
- PowerShell invocation with powershell/pwsh guard + -ExecutionPolicy Bypass
- _has_hermes_agent_browser() checks platform-correct paths
- _has_system_browser() checks Windows browser names (chrome, msedge, chromium)
- env_extra parameter for forwarding install flags
config.py:
- stamp_install_method() writes ~/.hermes/.install_method
- detect_install_method() checks stamp first (before heuristics)
acp_adapter:
- _run_setup_browser() rewritten: ensure_dependency('node') + ensure_dependency('browser')
- acp_adapter/bootstrap/ deleted (399 + 288 lines)
Rebased onto main -- drops #26620 dependency (upstream stage protocol merged
via #27224). Closes follow-up from #26593.
|
Upon installation, e.g. |
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvage of #26350 by @alt-glitch — all 19 commits cherry-picked with authorship preserved.
Summary
Makes
pip install hermes-agent && hermesa complete experience.entry.js, andinstall.shinto the wheel beforeuv buildensure_dependency()inhermes_cli/dep_ensure.py— lazy prompts node / browser / ripgrep / ffmpeg viabash install.sh --ensure <dep>. Wired into the TUI launcher and browser toolhermes updateis pip-aware: detects PyPI installs viadetect_install_method()and runspip install --upgrade hermes-agent(usesuv pipwhen available)hermes update --checkqueries PyPI when not a git checkouthermes postinstallone-shot bootstrap (node + browser + ripgrep + ffmpeg + setup)hermes doctor --fixgenerates config fromDEFAULT_CONFIGwhencli-config.yaml.exampleisn't shipped/path/to/repo/venv/binentries for pip installsinstall.sh --ensure <dep>and--postinstallmodes added for targeted bootstrapValidation
tests/hermes_cli/(8 new files) +tests/acp/: 315 passed, 1 skippedhermes_cli/scripts/install.sh,hermes_cli/tui_dist/entry.js, AND our existingacp_adapter/bootstrap/bootstrap_browser_tools.{sh,ps1}— both bootstrap paths coexistFollow-up (not gating)
Consolidate the two browser-bootstrap paths. This PR's
ensure_dependency("browser")callsbash install.sh --ensure browser; our recently-merged #26234 shipsacp_adapter/bootstrap/bootstrap_browser_tools.shas a focused-on-ACP-registry slice. Both work, but they're duplicate paths now. A small follow-up PR can havehermes acp --setup-browsershell intoensure_dependency("browser")and retire the standalone bootstrap script. Worth doing but not blocking; doesn't break anything as-is.Windows note
ensure_dependency()callsbash install.sh, which is POSIX-only. On Windows the prompt prints "install.sh not found" and the user has to runinstall.ps1manually. Consistent with how the existinghermes setup/install.shdivide works today.Closes #26350.