10 Commits

Author SHA1 Message Date
ethernet
5093154cef fix(windows): create protected token descriptors on ARM64 2026-09-21 14:13:07 -04:00
ethernet
9de542c15b merge origin/main (16 commits) into ethie/pm-clean
main folded the auto-archive housekeeping into per-profile state.db maintenance; the plugin
update-check chore stays. The consolidated-away TestWorkdirParallelPool stays removed. Two new
utf-8 reads in gateway/host_rendezvous.py read utf-8-sig.
2026-09-21 06:09:56 -04:00
teknium1
f9b8cf7c42 fix(gateway): a failed host attach never exits 0, and SIGTERM clears the record
Reviewer findings on the host rendezvous record + serve attach.

- Attach now PROVES the owner before exiting 0: a bounded TCP connect to the
  recorded endpoint plus a token-authenticated GET /api/host/identity that must
  answer as the recorded pid+role. A supervisor or `hermes update` relaunch
  landing in the old process's graceful-shutdown window (socket closed, atexit
  not yet run) previously exited 0 with NOTHING listening, so the service
  reported success for a dead backend. Anything short of a proven owner falls
  through to the bind.
- Unprovable liveness (no psutil, an unexpected psutil error) is a CANDIDATE,
  not an owner: it goes to the same probe instead of exiting 0, which is what
  turned a record for a long-dead pid into a permanent silent outage.
- An explicitly typed --port/--host the owner cannot serve is a non-zero refusal
  naming the owner, never a silent loopback redirect; and a `hermes dashboard`
  user is never routed to a headless `serve` backend (servesSpa in the identity
  answer).
- SIGTERM — the NORMAL stop (systemd stop, docker stop, the update relaunch) —
  now clears the record and the 0600 token and releases the host lock. atexit
  does not run on it: uvicorn's capture_signals re-raises into the default
  disposition, so a live session token outlived its process indefinitely. The
  handler only prepends cleanup and hands off to the previous handler, leaving
  the shutdown sequence unchanged.
- Host lock claim is tri-state (acquired / held-by-other / could-not-open) and
  logs the OSError: an unwritable lock dir used to be reported as "another
  gateway owns this host", sending operators hunting a process that never
  existed. Its handle cache is keyed by (role, resolved lock path), so a changed
  lock dir can no longer make owns_host_lock() lie.
- Windows: the token is written through the SSH runtime's protected
  owner+SYSTEM DACL writer (os.open(0o600) sets no ACLs there, and os.replace
  fails against an open reader); read_token's docstring no longer claims the
  mode bits prove same-OS-user.
- gateway/status: a RELATIVE $XDG_STATE_HOME is ignored per the XDG spec — it
  made the host lock dir CWD-relative, so two serves started from different
  directories shared no singleton.

Live A/B (real processes): kill -TERM of a fully started `hermes serve` left
host-serve.json + host-serve.token on disk on base, removes both on head (exit
status -15 unchanged). A record with a LIVE pid and a closed port made base exit
0 with no bind; head binds. `serve --port 8899` against an owner on another port
exits 1 naming the owner.
2026-09-21 02:51:58 -07:00
ethernet
5e4a2a3d24 refactor(pm): remove legacy dependency and launch managers
Competing installers and checkout-local venv assumptions bypassed PM
selection, install consent, and generation lifetimes. Route consumers
through PM and installation-bound launchers. Refresh source launchers
before obsolete Python entries can be collected.

Remove Node, browser, and CUA acquisition engines, obsolete venv-holder
handling, detached sync, and unused PM APIs. Keep historical updater
exports inert and preserve external tool ownership and native integration.

Share product freshness and prepared inputs across builders. Align plugin
admission, Docker provisioning, setup instructions, and behavioral tests.

Verified targeted Python and JavaScript tests, desktop and web typechecks,
scoped lint, real product builds, and the Docker frontend smoke test.
The missed post-setup test cleanup is included and verified.

Native Windows/macOS execution, full Rust compilation, and the complete
repository suite remain unverified. Historical compatibility requirements
were preserved and extended, not fully rescanned.
2026-09-12 14:57:38 -04:00
Teknium
71a0a35e88 refactor(web_server helpers): second pass — helper dedupe in windows_ssh_runtime, webhook via atomic_json_write, table packing
- windows_ssh_runtime: _open_existing shared by _read_shared/remove_artifact; _win32 builds
  its namespace via importlib; reparse/path checks folded
- webhook: _save_subscriptions -> utils.atomic_json_write(mode=0o600) (same fchmod-before-
  rename + post-replace chmod semantics); base URL builder tightened
- web_server_messaging: override table tuples single-line, catalog entry builder flattened,
  WhatsApp payload from a field tuple; channel keys as one comprehension
- web_server_oauth: poller bodies read sess fields inline; status dicts packed
- web_server_gateway: health URL normalisation via one regex; Popen detach kwargs inline;
  topology cache getter collapsed
- web_server_cron/xai_retirement/win_pty_bridge/worktree_gc: small collapses

Verification: routes identical, --help byte-identical (webhook/worktree + subcommands),
golden corpus identical, 189 test files / 2925 passed / 0 failed.
2026-09-02 23:08:44 -07:00
Teknium
f0a451f1da refactor(web_server helpers): compact gateway/messaging/cron/oauth helpers and CLI utils (-21% LOC, zero behavior change)
- web_server_cron: one _cron_store_scope ctx manager replaces 3 copies of the
  set_hermes_home_override + use_cron_store + reset pattern
- web_server_oauth: _token_status helper for the 2 credential-status dict builders,
  logged-out sentinel, catalog table packed one card per 2-3 lines (key order kept)
- web_server_messaging: telegram request collapsed to shared detail strings, catalog
  loop unified, env-prefix aliases lifted to a module table, catalog tuples single-line
- web_server_gateway: mode ladder -> dict lookup, owned-platforms comprehension,
  action log table derived; docstrings compacted (every WHY kept)
- windows_ssh_runtime: _read_shared/_write_new/_check/_sid_str helpers, dispatch()
  if-chain -> _OPERATIONS table (arity-checked), _win32 returns a namespace
- worktree_gc/webhook/xai_retirement/write_approval_commands/win_pty_bridge/
  worktree_cmd: dead _require_webhook_enabled/_repo_root inlined, _run helper,
  duplicated except branches merged, docstrings compacted

Parity: route table identical, webhook/worktree --help byte-identical, golden
corpus of 27 pure-function outputs identical vs base 113f04616b.
2026-09-02 21:54:36 -07:00
Cad from Arca
5cb19d7af5 fix(desktop): keep Windows SSH runtime at machine root 2026-08-01 14:30:16 -07:00
teknium1
5b751dc0ad chore: remove unused imports and dead locals (ruff F401/F841 sweep)
Cleans F401 unused imports and F841 dead local assignments across
root *.py, agent/, hermes_cli/, tools/, gateway/, cron/, tui_gateway/
(tests/, plugins/, skills/ excluded).

Intentionally KEPT (false positives / test-patch surfaces):
- agent/transports/__init__.py package re-exports
- cli.py browser_connect re-exports (DEFAULT_BROWSER_CDP_URL area,
  used by tests/cli/test_cli_browser_connect.py)
- hermes_cli/main.py _prompt_auth_credentials_choice /
  _model_flow_bedrock_api_key (accessed via main_mod attr in tests)
- gateway/run.py aliased replay_cleanup + whatsapp_identity re-exports
  and _PORT_BINDING_PLATFORM_VALUES (test-referenced)
- hermes_cli/web_server.py get_running_pid (tests monkeypatch it) and
  _OAUTH_TOKEN_URL availability probe
- hermes_cli/config.py get_process_hermes_home re-export (noqa'd F811
  chain) and yaml availability-probe import
- hermes_cli/nous_subscription.py managed_nous_tools_enabled
  (tests patch hermes_cli.nous_subscription.managed_nous_tools_enabled)
- try/except ImportError availability probes (env_loader, tts_tool,
  mcp_tool, web_server anthropic OAuth block)
- tools/web_tools.py noqa F401 re-exports
- hermes_cli/setup_whatsapp_cloud.py:263 'proceed' skipped: possible
  missing-guard bug, flagged for separate review
- unused function parameters (signature changes out of scope)

Side-effect RHS calls preserved where only the binding was dead
(e.g. web_server proc = _spawn_hermes_action -> bare call).
2026-07-29 11:53:39 -07:00
teknium1
d4b867cf9f fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide
AST-driven pass over every subprocess.run/Popen/check_output/check_call/call
with text=True (or universal_newlines=True) and no explicit encoding=:
append encoding='utf-8', errors='replace' at the kwarg site. 136 call
sites across 28 files (cli.py, hermes_cli/main.py, tools_config.py,
environments, computer_use, gateway, scripts, skills helpers, agent/*).

Together with the salvaged #55339/#60741 commits this closes out issue
#53428's bug class; the salvaged #60751 linter rule in
check-windows-footguns.py now enforces it repo-wide (verified: 807 files
scanned, zero findings).
2026-07-24 11:45:57 -07:00
yoniebans
00e9f6dd4d feat(serve): add Windows remote backend runtime for Desktop SSH
Add hermes_cli/windows_ssh_runtime.py: a native Windows trust boundary
invoked over SSH to manage the Desktop SSH backend lifecycle — ACL-locked
one-shot token file (owner+SYSTEM only, SE_DACL_PROTECTED, read-once via
DELETE_ON_CLOSE), ownership lock, and detached serve spawn with
CREATE_BREAKAWAY_FROM_JOB so the backend survives the SSH session's Job
Object teardown. Process ownership is proven by exact pid + creation-time +
argv + owner-nonce; state is tri-state (owned / stale / indeterminate) so a
live-but-unreadable process is never mistaken for stale.

Route _read_ssh_session_token_file to the Windows reader on win32, and move
the POSIX token root from a hardcoded ~/.hermes to get_hermes_home() so both
platforms honor the active profile.
2026-07-17 18:23:22 +02:00