From 7152bf009a10afadbc1263e7ff4d0b793d0a76c5 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 23 Oct 2026 00:47:07 -0700 Subject: [PATCH] fix(install): browser opt-out uses the name every PM release accepts install.sh --skip-browser / --no-playwright and install.ps1 -SkipBrowser now hand PM `--without agent-browser` again instead of `--without chromium`. The downloaded installer is the newest script, but by default it installs the stable tag, whose PM (v0.22.5) rejects `--without chromium` with "--without accepts only optional default packages (agent-browser, cua-driver)" and exits 1, failing the whole install. The new PM already reads `agent-browser` as `chromium` (pm.defaults.RETIRED_DEFAULTS), so the legacy spelling works against both the stable tag and main. Direct `hermes pm install --without chromium` stays valid on the new PM. --- pm/defaults.py | 5 +++-- scripts/install.ps1 | 4 +++- scripts/install.sh | 4 +++- tests/pm/test_retired_agent_browser.py | 4 ++-- .../install/test_install_ps1_managed_python_provenance.py | 5 +++-- .../install/test_install_sh_reuse_supported_python.py | 6 ++++-- website/docs/reference/package-management.md | 2 +- 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/pm/defaults.py b/pm/defaults.py index 800da77d31..cb2cec240e 100644 --- a/pm/defaults.py +++ b/pm/defaults.py @@ -23,8 +23,9 @@ DECLINED_FILENAME = "declined-packages.json" # A retired default whose opt-out carries over to the package that took its # place: `--without agent-browser` declined the browser, which is Chromium now. -# Read through on every load, so a record written by an older installer (or an -# old installer script passing the old name) keeps skipping the browser. +# Read through on every load, so a record written by an older installer keeps +# skipping the browser. The installers still pass the old name on purpose: the +# stable PM they install by default accepts only `agent-browser`. RETIRED_DEFAULTS = {"agent-browser": "chromium"} diff --git a/scripts/install.ps1 b/scripts/install.ps1 index c1a6345502..9bcdfb29bd 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -1286,7 +1286,9 @@ function Invoke-BootstrapPm { # Bare $SkipBrowser, like $InstallDir: under iex/scriptblock entry the # param() binding is not in $script: scope (see Initialize-ResolvedPaths). $pmArgs = @('install') - if ($SkipBrowser) { $pmArgs += @('--without', 'chromium') } + # Legacy spelling on purpose: the stable PM this script installs by + # default rejects 'chromium', and newer PMs read 'agent-browser' as 'chromium'. + if ($SkipBrowser) { $pmArgs += @('--without', 'agent-browser') } if ($SkipComputerUse) { $pmArgs += @('--without', 'cua-driver') } Invoke-Logged "Installing dependencies (hash-verified via uv.lock)" { & $bootPy -m pm.cli @pmArgs } if ($LASTEXITCODE) { Fail "dependency install failed" deps_install_failed } diff --git a/scripts/install.sh b/scripts/install.sh index 002c20d7e3..eb7308c17f 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1024,7 +1024,9 @@ bootstrap_pm() { local pm_args=(install) # PM records the opt-outs, so later installs and `hermes update` keep the # tools off until `hermes pm install ` opts back in. - [ "$SKIP_BROWSER" = true ] && pm_args+=(--without chromium) + # Legacy spelling on purpose: the stable PM this script installs by default + # rejects `chromium`, and newer PMs read `agent-browser` as `chromium`. + [ "$SKIP_BROWSER" = true ] && pm_args+=(--without agent-browser) [ "$SKIP_COMPUTER_USE" = true ] && pm_args+=(--without cua-driver) bootstrap_python # Refresh the sudo ticket cached in prerequisites (never prompts): the diff --git a/tests/pm/test_retired_agent_browser.py b/tests/pm/test_retired_agent_browser.py index d6c6555354..1ca0e1b978 100644 --- a/tests/pm/test_retired_agent_browser.py +++ b/tests/pm/test_retired_agent_browser.py @@ -2,8 +2,8 @@ The store, its facts and the recorded opt-outs of such an install still name agent-browser. Every reader must skip that fact, `pm gc` reclaims its entry, and -an opt-out recorded as `--without agent-browser` (the installers' old -`--skip-browser`) keeps skipping the browser, which is Chromium alone now. +an opt-out recorded as `--without agent-browser` (what the installers' +`--skip-browser` passes) keeps skipping the browser, which is Chromium alone now. Real pm code paths over a fixture store under a scratch HERMES_HOME and HERMES_RUNTIME_DIR; the real registry and pm/lock.json. diff --git a/tests/scripts/install/test_install_ps1_managed_python_provenance.py b/tests/scripts/install/test_install_ps1_managed_python_provenance.py index a8d3f572d3..adf9bf8d72 100644 --- a/tests/scripts/install/test_install_ps1_managed_python_provenance.py +++ b/tests/scripts/install/test_install_ps1_managed_python_provenance.py @@ -14,7 +14,8 @@ INSTALLER = Path(__file__).resolve().parents[3] / "scripts" / "install.ps1" @pytest.mark.parametrize("stage,exit_code,skip_browser", [ ("venv", 0, False), ("python-deps", 0, False), ("python-deps", 17, False), - # -SkipBrowser is PM's persisted opt-out, handed over as `--without`. + # -SkipBrowser is PM's persisted opt-out, handed over as `--without` under + # the legacy name every PM accepts (the stable one rejects `chromium`). ("python-deps", 0, True), ]) def test_python_stage_delegates_to_pin_without_touching_existing_env(tmp_path, stage, exit_code, skip_browser): @@ -83,7 +84,7 @@ exit $LASTEXITCODE ] if stage == "python-deps": assert json.loads(pm_log.read_text(encoding="utf-8-sig")) == ( - ["install", "--without", "chromium"] if skip_browser else ["install"]) + ["install", "--without", "agent-browser"] if skip_browser else ["install"]) else: assert not pm_log.exists() assert existing.read_text(encoding="utf-8-sig") == "previous generation" diff --git a/tests/scripts/install/test_install_sh_reuse_supported_python.py b/tests/scripts/install/test_install_sh_reuse_supported_python.py index 36392c944b..20a97b871a 100644 --- a/tests/scripts/install/test_install_sh_reuse_supported_python.py +++ b/tests/scripts/install/test_install_sh_reuse_supported_python.py @@ -33,8 +33,10 @@ def test_missing_value_fails_before_any_install_work(option: str, suffix: list[s @pytest.mark.parametrize("flags, expected", [ ([], ["-m", "pm.cli", "install"]), - (["--skip-browser"], ["-m", "pm.cli", "install", "--without", "chromium"]), - (["--no-playwright"], ["-m", "pm.cli", "install", "--without", "chromium"]), + # The legacy name: the stable PM this script installs by default accepts + # only `agent-browser`, and newer PMs read it as `chromium`. + (["--skip-browser"], ["-m", "pm.cli", "install", "--without", "agent-browser"]), + (["--no-playwright"], ["-m", "pm.cli", "install", "--without", "agent-browser"]), ]) def test_browser_skip_becomes_the_pm_opt_out(tmp_path: Path, flags: list[str], expected: list[str]) -> None: """The skip flag is PM's persisted opt-out, not a no-op and not --non-interactive.""" diff --git a/website/docs/reference/package-management.md b/website/docs/reference/package-management.md index 3869064302..db5265f675 100644 --- a/website/docs/reference/package-management.md +++ b/website/docs/reference/package-management.md @@ -532,7 +532,7 @@ hermes pm install chromium | Command | Effect | |---|---| | `pm install [names...]` | Install named packages. With no names, provision required tools plus Python, put those tools on PATH, and then sync the `all` extra. A bare install also installs the default optional tools (`chromium`, the browser Hermes launches, and `cua-driver`); a failed download of these prints a warning and does not fail the install. Naming a package you declined earlier undoes that choice. | -| `pm install --without NAME` | Do a bare install without the default optional package `NAME` (`chromium` or `cua-driver`), and record that choice. Later bare installs and `hermes update` also leave it out. The installers' `--skip-browser` / `-SkipBrowser` (`--without chromium`) and `--skip-computer-use` / `-SkipComputerUse` (`--without cua-driver`) use this. A choice recorded as the legacy `--without agent-browser` still skips `chromium`. | +| `pm install --without NAME` | Do a bare install without the default optional package `NAME` (`chromium` or `cua-driver`), and record that choice. Later bare installs and `hermes update` also leave it out. The installers' `--skip-browser` / `-SkipBrowser` and `--skip-computer-use` / `-SkipComputerUse` (`--without cua-driver`) use this. The browser opt-out passes the legacy name `--without agent-browser`, which every PM release accepts and this one reads as `chromium`; a choice recorded under that name still skips `chromium`. | | `pm install --tools-only` | Install that tool closure and put it on PATH, then stop. The venv sync does not run. | | `pm env [names...]` | Print installed packages' PM-contributed environment values as JSON. It does not install missing packages, though a cold Hermes launch may prepare its own Python runtime first. | | `pm doctor` | Check installed tool identities, files, and digests against the lock. |