Nothing covered the update path, which is the worst thing to break: a broken updater strands users on the version that cannot fix itself. `hermes update` alone is ~2000 lines (hermes_cli/update_cmd.py) and had no end-to-end test. tests/install/install-update-e2e.sh installs a genuine earlier Hermes through the real one-liner (curl -fsSL https://…/install.sh | bash, served by dev-sandbox's MITM proxy at the canonical URL, cloning "github.com" through the upload-pack shim), which really installs uv, a managed Python, Node and the venv. It then applies ONE update route and requires the checkout to land on this commit with `hermes --version` still working -- so a pass means the venv and entry point survived, not merely that git moved. One route per run, each on a sandbox built from scratch. Sharing one install across routes -- or rewinding with `git reset --hard` between them -- leaves the second route running against a tree the first already updated (same venv, same console script, same __pycache__), which is not the state any real user is in: a route could pass only because its predecessor did the work, and a failure in the first left the second exercising something undefined. --install-ref chooses what to install first, so this covers "update from an older release", not just from the tip. Installer flags are probed against the target rather than assumed, because releases from months back predate flags current Hermes takes for granted: --skip-browser is read out of that ref's own install.sh, and `--yes` is asked of the installed `hermes update --help` (the update subcommand has lived in main.py, subcommands/update.py and update_cmd.py across the tags we sample, so a static parse rots silently -- and did). Without those probes, old releases die on "Unknown option: --skip-browser" and "unrecognized arguments: --yes" before doing any work. Installer output is streamed through tee rather than captured: a real install of uv, Python, Node and the venv IS the substance of this test, so it belongs in the job log, not only in an artifact. pipefail keeps the installer's exit status rather than tee's, so a failed install cannot look like a pass. The sandbox's own proxy log is printed in full on failure, since a rejected TLS handshake explains a failure that otherwise reads as a bare `curl: (35)`. Deliberately reuses dev-sandbox rather than adding a second harness. An earlier draft rewrote install.sh's hardcoded URLs with insteadOf and ran it against the host; that tested the installer LESS faithfully (bash install.sh instead of the real one-liner, host libs instead of a clean machine, ssh disabled to keep a failed rewrite from reaching real GitHub) while duplicating a fake Internet we already have. Shell, not pytest, so scripts/run_tests.sh and run_tests_parallel.py stay untouched: a pytest version needed an entry in the former's `env -i` credential allowlist and a _SKIP_PARTS exclusion in the latter, and every meaningful line was a command run inside the sandbox anyway. Two guards, both earned during bring-up. It prefers the `sandbox` wrapper and falls back to the raw script only when bwrap is on PATH (under Nix the wrapper supplies the PATH and DEV_SANDBOX_* vars, so the bare script exits 127). And it refuses to run on a dirty worktree: every dev-sandbox invocation re-derives fake main from the working copy, so uncommitted changes move the update target between the call that installs and the call that verifies -- a failure that looks like a broken updater but is a moving reference.
200 lines
6.0 KiB
Plaintext
200 lines
6.0 KiB
Plaintext
.DS_Store
|
|
/venv/
|
|
/venv.old/
|
|
/venv.stale.runtime-*/
|
|
/.hermes-runtime/
|
|
/_pycache/
|
|
*.pyc*
|
|
__pycache__/
|
|
act/
|
|
.act-sandbox-agent.*
|
|
.venv/
|
|
.venv
|
|
.vscode/
|
|
.env
|
|
.op.env
|
|
.env.local
|
|
.env.development.local
|
|
.env.test.local
|
|
.env.production.local
|
|
.env.development
|
|
.env.test
|
|
.hermes-docker/
|
|
.notebooklm-home/
|
|
.notebooklm-cli-venv/
|
|
.notebooklm-playwright/
|
|
.pip-cache/
|
|
.uv-cache/
|
|
compose.hermes.local.yml
|
|
export*
|
|
__pycache__/model_tools.cpython-310.pyc
|
|
__pycache__/web_tools.cpython-310.pyc
|
|
logs/
|
|
data/
|
|
.pytest_cache/
|
|
test_durations.json
|
|
.pytest-cache/
|
|
tmp/
|
|
temp_vision_images/
|
|
hermes-*/*
|
|
examples/
|
|
tests/quick_test_dataset.jsonl
|
|
tests/sample_dataset.jsonl
|
|
run_datagen_kimik2-thinking.sh
|
|
run_datagen_megascience_glm4-6.sh
|
|
run_datagen_sonnet.sh
|
|
source-data/*
|
|
run_datagen_megascience_glm4-6.sh
|
|
data/*
|
|
# No trailing slash: also matches node_modules SYMLINKS (worktrees often
|
|
# symlink node_modules to the main checkout; the dir-only pattern let one
|
|
# slip into a commit and break `npm ci` on CI with ENOTDIR).
|
|
node_modules
|
|
browser-use/
|
|
agent-browser/
|
|
# Private keys
|
|
*.ppk
|
|
*.pem
|
|
privvy*
|
|
images/
|
|
__pycache__/
|
|
hermes_agent.egg-info/
|
|
wandb/
|
|
testlogs
|
|
playwright-report/
|
|
test-results/
|
|
# Playwright visual regression baselines — cached from main in CI, not committed
|
|
*-snapshots/
|
|
|
|
# CLI config (may contain sensitive SSH paths)
|
|
cli-config.yaml
|
|
|
|
# Skills Hub state (lives in ~/.hermes/skills/.hub/ at runtime, but just in case)
|
|
skills/.hub/
|
|
ignored/
|
|
.worktrees/
|
|
environments/benchmarks/evals/
|
|
|
|
# Web UI build output
|
|
hermes_cli/web_dist/
|
|
# Cross-process web UI build lock (flock target, always empty)
|
|
.web_ui_build.lock
|
|
apps/desktop/build/
|
|
apps/desktop/dist/
|
|
|
|
# tsc-emitted artifacts (a stray `tsc -b` compiles into src/, and vite then
|
|
# resolves the stale .js OVER the .tsx — never track these)
|
|
apps/desktop/src/**/*.js
|
|
apps/desktop/src/**/*.js.map
|
|
apps/desktop/src/**/*.d.ts
|
|
!apps/desktop/src/global.d.ts
|
|
!apps/desktop/src/vite-env.d.ts
|
|
apps/shared/src/**/*.js
|
|
apps/shared/src/**/*.js.map
|
|
apps/shared/src/**/*.d.ts
|
|
apps/desktop/release/
|
|
*.tsbuildinfo
|
|
|
|
# Web UI assets — synced from @nous-research/ui at build time via
|
|
# `npm run sync-assets` (see web/package.json).
|
|
web/public/fonts/
|
|
web/public/ds-assets/
|
|
|
|
# Release script temp files
|
|
.release_notes.md
|
|
mini-swe-agent/
|
|
|
|
# Nix
|
|
.direnv/
|
|
.nix-stamps/
|
|
result
|
|
website/static/api/skills-index.json
|
|
# skills.json + skills-meta.json are build artifacts emitted by
|
|
# website/scripts/extract-skills.py during prebuild — keep them out of
|
|
# git for the same reason as skills-index.json (large, generated, change
|
|
# every build).
|
|
website/static/api/skills.json
|
|
website/static/api/skills-meta.json
|
|
# automation-blueprints-index.json is a build artifact emitted by
|
|
# website/scripts/extract-automation-blueprints.py during prebuild.
|
|
website/static/api/automation-blueprints-index.json
|
|
models-dev-upstream/
|
|
|
|
# Local editor / agent tooling (machine-specific; keep in global config, not the repo)
|
|
.codex/
|
|
.cursor/
|
|
.gemini/
|
|
.zed/
|
|
.mcp.json
|
|
opencode.json
|
|
config/mcporter.json
|
|
|
|
hermes_cli/tui_dist/*
|
|
hermes_cli/scripts/
|
|
docs/superpowers/*
|
|
# Working directory for the Hermes Agent's session state (~/.hermes/ at runtime;
|
|
# also created in-repo when an agent operates in this checkout). Plans, audit
|
|
# logs, and per-session caches are never artifacts of the codebase.
|
|
.hermes/
|
|
|
|
# Desktop/bootstrap install marker written into the managed checkout root by the
|
|
# bootstrap installer. It is Hermes-managed runtime state, never a code change —
|
|
# ignore it so `hermes update`'s `git stash push --include-untracked` does not
|
|
# treat it as a local edit and autostash it on every run (#38529).
|
|
.hermes-bootstrap-complete
|
|
|
|
# Persistent dev sandbox dir (scripts/dev-sandbox.sh --persistent)
|
|
.hermes-sandbox/
|
|
# Sandbox dirs used by the install/update E2E (tests/install/). The suffix is
|
|
# the route name, so each route gets its own tree and two can run at once.
|
|
.hermes-sandbox-e2e*/
|
|
|
|
# Interrupted-update breadcrumb + recovery lock written next to the shared venv
|
|
# by `hermes update` / launch-time self-heal. Runtime state, never a code change
|
|
# — ignore so `git status` stays clean and update's autostash skips them.
|
|
.update-incomplete
|
|
.update-incomplete.lock
|
|
|
|
# Checkout fingerprint the __pycache__ tree was last validated against
|
|
# (launch-time stale-bytecode sweep). Runtime state, never a code change.
|
|
.bytecode-fingerprint
|
|
.bytecode-fingerprint.tmp
|
|
|
|
# Installer-written method stamp in the managed checkout root (scripts/install.sh).
|
|
# Runtime metadata only — never a code change. Ignore so `git status` stays clean
|
|
# and `hermes update`'s untracked autostash does not treat it as a local edit (#66189 / #54855).
|
|
/.install_method
|
|
|
|
# Tool Search live-test harness output — non-deterministic model transcripts,
|
|
# regenerated by scripts/tool_search_livetest.py. Never an artifact of the repo.
|
|
scripts/out/
|
|
|
|
# Per-release changelog drafts. These exist only transiently during a release
|
|
# cut (passed to `gh release create --notes-file`); the GitHub Release itself
|
|
# stores the published notes. They are not a build artifact and must never be
|
|
# committed to the repo root. See the hermes-release skill.
|
|
RELEASE_v*.md
|
|
|
|
# Desktop demo-run scratch output (hermes writes demo/*.txt during recorded
|
|
# walkthroughs). Throwaway artifacts, never part of the app.
|
|
apps/desktop/demo/
|
|
|
|
# PR infographics are rendered locally and embedded in PR descriptions via the
|
|
# image-provider (fal.media) URL — they are NEVER committed to the repo. The
|
|
# PR body is the archive. See the hermes-agent-dev skill's
|
|
# pr-infographic-workflow reference (storage rule + lapse #8 / #COMMIT-1).
|
|
#
|
|
# Spelling variants are listed because a single `infographic/` pattern was
|
|
# sidestepped by an `infograficos/` directory (#70552). .gitignore is only
|
|
# the first line of defence and cannot stop `git add -f` at all — the
|
|
# infographic-check CI job is what actually enforces this.
|
|
infographic/
|
|
infographics/
|
|
infograficos/
|
|
infografico/
|
|
native/fts5_cjk/*.so
|
|
# Runtime marker written by hermes update when a lazy dependency refresh is
|
|
# interrupted; consumed by launch-time recovery. Never commit it (was tracked
|
|
# by accident via 3a69e34702, removed in the #72002 salvage).
|
|
.lazy-refresh-incomplete
|