17 Commits
Author SHA1 Message Date
Bailey Dixon 986ce3b12b fix(plugin): isolate profile-owned registrations 2026-08-13 10:50:14 -04:00
Bailey Dixon f5c2a2b888 feat(plugins): add live Android plugin surfaces 2026-08-02 18:14:42 -04:00
Bailey DixonandClaude Opus 4.8 b5d30287a9 chore(phone): remove temp [phone-diag] tracing; document Phase 2c device fixes
Reverts the temporary file-based [phone-diag] scaffolding (connect/loop/register
tracing) added to localize the two-way-reply failure. The genuine fixes stay:
PhoneAdapter.connect(is_reconnect=...) (3018a18), and the registration `except`
upgraded from silent debug to a visible warning.

- DEVLOG: record the device round-trip + both faults — the connect() signature
  TypeError, and a stale duplicate plugin copy in the user-plugins dir winning the
  loader's name-dedup so the gateway loaded old code and ignored every deploy.
- TODO: mark Phase 2c device-verified; add the installer-purge-stale-backups fix
  and the usability roadmap (outbound buffering first; threaded agent surface per
  the "separate lanes, unified surface" decision; per-thread chat_id; status; title).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 16:14:18 -04:00
Bailey DixonandClaude Opus 4.8 9081fb341c chore(phone): file-based [phone-diag] trace (gateway filters plugin logs)
The gateway journal suppresses plugin logs at every level, so the WARNING
trace was invisible. Switch the diagnostics to append to ~/.hermes/phone-diag.log
so we can see exactly which hop fires: registration, connect() entry/abort,
reply-loop start. TEMPORARY — reverted once the connect gap is fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 12:54:35 -04:00
Bailey DixonandClaude Opus 4.8 39cfedf776 chore(phone): temporary [phone-diag] WARNING tracing for reply-loop connect debug
TEMPORARY diagnostics (to be reverted) to localize why the gateway's phone
adapter never polls /phone/replies despite registration+env_enablement working
in isolation. Plugin INFO is filtered from the gateway journal, so these trace
at WARNING: registration outcome (was silently swallowed), connect() entry, and
reply-loop start. Also upgrades the previously-silent registration except from
DEBUG to WARNING — a real improvement worth keeping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 12:49:48 -04:00
Bailey DixonandClaude Opus 4.8 c39066808b feat(plugin): register paired phone as a Hermes platform (proactive push)
Add a push-only BasePlatformAdapter (PhoneAdapter) registered via the
upstream platform-plugin API so the agent can proactively message the
paired device: send_message target=phone and cron deliver=phone. send()
POSTs loopback to the relay (/phone/message); the relay forwards over the
existing phone WSS. Off by default behind PHONE_ENABLED; no fork.

Modeled on the bundled ntfy adapter, including a standalone_sender_fn so
out-of-process cron delivery works. Plugin stays kind=standalone;
registration wired into register() and guarded for older hosts.

22 unit tests cover gating, relay-URL precedence, payload build, and the
standalone sender over a fake httpx client.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 16:41:14 -04:00
Bailey Dixon 41b341ed09 feat(plugin): add relay agent context injection 2026-06-20 14:50:49 -04:00
Bailey DixonandClaude Opus 4.8 8eda3699f9 feat(plugin): env-key prompts, native install path, /relay slash commands, session-start hook
Adopt four upstream plugin surfaces for easier setup/use:
- requires_env rich form: declare the optional voice-provider keys (XAI/OpenAI/
  ElevenLabs) so `hermes plugins install` prompts for them with a "get yours"
  link instead of hand-editing ~/.hermes/.env. Standard path needs none.
- Native install: document/support `hermes plugins install
  Codename-11/hermes-relay/plugin` for tools-only setups (additive; the full
  relay still uses the curl install.sh).
- /relay slash commands (status/devices/pair) usable mid-chat from any platform,
  reusing existing relay logic; every path guarded.
- A minimal on_session_start hook: one 0.5s-timeout guarded /health ping,
  returns None, can't slow or crash the gateway.

Verified against upstream/main plugin contract (register_command, register_hook
on_session_start, requires_env shape, plugins install subdir).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 20:30:43 -04:00
Bailey Dixon 55a4227e4d feat(android): apply relay cockpit refresh 2026-06-09 22:29:25 -04:00
Bailey Dixon a5f3d0a2c3 fix(android): add bridge media sharing and mms handoff 2026-05-05 20:13:31 -04:00
Bailey Dixon c7f71903a7 feat: improve relay auth and Android connection handling 2026-05-04 19:19:22 -04:00
Bailey DixonandClaude Opus 4.7 7117e61afd chore: recapture alpha.1 server-side state into git + merge feature/desktop-tui-mvp
Closes the drift between hermes-host's running hermes-relay and what
main had committed. Three sources converge here:

(1) feature/desktop-tui-mvp (3 commits never merged to main):
    - plugin/relay/channels/tui.py (508 LOC) — THE tui channel
      handler that spawns tui_gateway. Main has been running on the
      server but absent from git for a week.
    - docs/relay-protocol.md (450 LOC) — formal WSS envelope spec.
    - plugin/tests/test_tui_channel.py (520 LOC).
    - scripts/tui-smoke{,-teardown}.sh.
    - plugin/relay/auth.py +4 lines.
    - 4-line addition to plugin/relay/server.py for tui dispatch.

(2) alpha.1 hot-fix drift (live on the server, untracked in git):
    - plugin/relay/channels/desktop.py (424 LOC) — Phase B tool
      command channel: desktop.command/response/status, UUID-future
      correlation, single-client MVP. MERGED with the alpha.6
      DesktopChannel (161 LOC, workspace-awareness) into one
      DesktopHandler class. Backwards-compat alias
      `DesktopChannel = DesktopHandler` preserves alpha.6 import
      sites in server.py.
    - plugin/tools/desktop_tool.py (349 LOC) — registers 5 desktop_*
      tools (read_file/write_file/terminal/search_files/patch) via
      tools.registry. Adopted verbatim from server's working tree.
    - plugin/__init__.py — extended to register desktop tools via the
      plugin context API + matching plugins.enabled documentation.
      Adopted verbatim from server.

(3) Conflict resolution in server.py:
    - bridge.close() → desktop.close() → tui.close() lifecycle
      (both alpha.1's desktop hook and feature branch's tui hook
      called during shutdown).
    - _on_disconnect: server.desktop.detach_ws(ws) +
      server.tui.detach_ws(ws, reason=...) both run on disconnect.
    - alpha.9 /clipboard/inbox endpoint preserved in route table.

After this lands on main, hermes-host can `git checkout -- .`
(its working tree drift now matches main verbatim) and `git pull
origin main --ff-only` cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:17:09 -04:00
Bailey DixonandClaude Opus 4.6 e9c3f824ba feat: /hermes-relay-pair skill + rename plugin hermes-android → hermes-relay
Three parallel workstreams landed together.

## 1. Skill authoring — new /hermes-relay-pair slash command

skills/hermes-relay-pair/SKILL.md (98 lines, agentskills.io-compatible):
- Proper YAML frontmatter (name, description, version, author, license,
  platforms: [linux, macos], metadata.hermes tags/category/homepage)
- Body sections: When to Use / Prerequisites / Procedure / Pitfalls /
  Verification — terse imperatives suitable for the agent's context window
- Tells the agent to run `python -m plugin.pair`, explains the venv path
  trap, walks through host-side verification (curl /health, clients
  count), warns about code expiration + QR terminal rendering gotchas
- Once installed to ~/.hermes/skills/, auto-registers as the
  /hermes-relay-pair slash command in every chat session + messaging
  platform.

## 2. Rename hermes-android → hermes-relay (user-facing, not Python)

The repo was rebranded on 2026-04-08 but the Python *package* / plugin
distribution name still said `hermes-android`. It's visible in
`hermes plugins list`, pypi-style imports, and a dozen user-docs /
README / install-snippet references. Renamed everywhere it's a package
name or user-visible string; Python module path `plugin` stays exactly
as-is (imports unchanged).

- pyproject.toml: name "hermes-android" → "hermes-relay",
  version "0.4.0" → "0.5.0", description rewritten
- plugin/plugin.yaml: name + version aligned with pyproject
- plugin/__init__.py: docstring updated
- install.sh: PLUGIN_NAME target dir is now ~/.hermes/plugins/hermes-relay
- README.md, AGENTS.md, docs/{security,relay-server,upstream-contributions}.md,
  user-docs/guide/getting-started.md, user-docs/reference/{relay-server,configuration}.md:
  install snippets + package references swept
- plugin/{android_tool,tools/android_tool}.py: package name strings updated
- relay_server/SKILL.md, skills/hermes-pairing-qr/*: deprecation notices
  updated to reference the new name
- Historical DEVLOG entries, plan.md build plan, and Python import
  paths left untouched on purpose (history and correctness)

## 3. user-docs additive pass for the slash command

user-docs/guide/getting-started.md and README.md now mention
/hermes-relay-pair as the primary "from a Hermes chat session" path
alongside the `hermes pair` CLI. Narrow additive edits only — no
section rewrites.

## Upstream gap discovered

Hermes v0.8.0 has `PluginContext.register_cli_command()` for third-party
plugins but main.py only wires `plugins.memory.discover_plugin_cli_commands()`
into the top-level argparser — the generic `_cli_commands` dict is
populated correctly but never consulted. Result: our `hermes pair` and
`hermes relay` sub-commands register cleanly but aren't callable from
the CLI until an upstream fix lands. The `register_cli_command` calls
in plugin/__init__.py are left in place so they'll start working the
moment main.py is patched.

Practical workaround: use /hermes-relay-pair (this skill) or a shell
shim at ~/.local/bin/hermes-pair that execs `python -m plugin.pair`
(deploy step — not in this commit).

Verified locally:
  pip install -e .           → hermes-relay 0.5.0
  python -c "import plugin.pair"
  python -m plugin.pair --help

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 13:17:28 -04:00
Bailey DixonandClaude Opus 4.6 118a2058a8 feat(relay): PTY terminal backend + consolidate relay_server into plugin/relay
Two changes packaged together since the PTY backend landed at the new
plugin/relay/channels/terminal.py location:

1. **PTY terminal backend** — rewrites the terminal channel stub into a
   real pty.openpty() + fork + TIOCSCTTY handler with non-blocking master
   fd plugged into asyncio.loop.add_reader(). Output batched on ~16ms
   frames (or 4 KiB overflow). TIOCSWINSZ resize, graceful SIGHUP →
   WNOHANG reap → SIGKILL teardown. Unix-only; import-guarded so the
   relay still starts on Windows with a clean "not supported" error on
   attach. Adds terminal_shell config field (RELAY_TERMINAL_SHELL env var).
   Per-client session cap of 4.

2. **Plugin consolidation (Phase 2 plan step)** — relay_server/ now lives
   at plugin/relay/ as the canonical location. relay_server/ is kept as a
   thin compat shim so `python -m relay_server` and existing docs keep
   working. Adds `hermes relay start` CLI sub-command wired through the
   plugin CLI registration system. Bumps plugin version 0.3.0 → 0.4.0,
   adds pyyaml to install_requires, libtmux to optional extras.

Deferred (still in the plan, not this commit): libtmux session
persistence, hermes relay status/sessions/kill sub-commands, bridge
channel protocol rewrite (still HTTP↔WS in plugin/android_relay.py on
its own port).

Verified locally:
  python -m plugin.relay --help
  python -m relay_server --help
  python -m py_compile plugin/relay/**/*.py
  gradlew :app:compileDebugKotlin (UP-TO-DATE)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:58:22 -04:00
Bailey DixonandClaude Opus 4.6 b379d02d4c chore: prepare v0.1.0 Play Store release
- Rename "Hermes Relay" -> "Hermes-Relay" across docs, app strings,
  scripts, workflows, plugin, and relay server (~57 files)
- Redesign user-docs landing: install section moved above features
  via home-hero-after slot (InstallSection.vue), hero image replaced
  with phone-framed demo video that crossfades to brand logo after
  12s of playback (HeroDemo.vue). Fix dead /guide/getting-started
  links in raw HTML hrefs that VitePress base-rewriting skipped.
- Add chat demo to README, docs landing hero, and Getting Started's
  Verify Connection section. Re-encode 20MB / 102fps source capture
  to 1.95MB / 30fps with extracted poster frame for instant LCP.
- Add smooth auto-scroll for streaming chat with Settings toggle --
  follows new tokens at the bottom, pauses when user scrolls up.
- Migrate SettingsScreen clipboard from deprecated LocalClipboardManager
  to LocalClipboard suspend API (Compose 1.7+).
- Migrate scripts/screenshots from monolithic .bat to thin wrapper
  + screenshots.py for Play Store screenshot capture.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 21:15:07 -04:00
Bailey DixonandClaude Opus 4.6 c2dc336045 feat: migrate hermes-pair to plugin CLI and add one-line installer
Replaces the standalone bash skill with a plugin-owned CLI sub-command
and adds a curl|bash installer so users can go from zero to connected
without cloning the repo.

Plugin migration:
- plugin/pair.py — pure-Python pairing logic (config reading, LAN IP
  detection, QR rendering, text fallback). Cross-platform socket-based
  LAN detection replaces Linux-only 'ip route'. Config fallback chain:
  config.yaml → ~/.hermes/.env → env vars → defaults
- plugin/cli.py — registers 'hermes pair' via v0.8.0 register_cli API
  with --png, --no-qr, --host, --port flags
- plugin/__init__.py — calls ctx.register_cli_command() wrapped in
  try/except so the 14 android_* tools still register on v0.7.0
- Pure-Python QR rendering via segno — no qrencode binary dependency
- Text block always shown alongside QR so pairing works inside Hermes
  Rich TUI and over limited SSH sessions where QR blocks garble
- Plugin version bumped to 0.3.0; segno>=1.6.0 added to requirements,
  setup.py, pyproject.toml

One-line installer:
- install.sh at repo root: curl|bash entry point that clones the plugin,
  installs Python deps, and prints next steps. Supports HERMES_HOME and
  HERMES_RELAY_BRANCH env overrides. Uses trap cleanup for temp dirs.
  Replaces the old plugin/install.sh (its URL comment already pointed
  to the root location)

Docs restructure:
- README 'Install' → 'Quick Start' with the one-liner front and center
- Homepage (user-docs/index.md) gets an 'Install in 30 seconds' block
  below the feature cards with scoped CSS
- Guide landing page leads with Quick Install
- Getting Started restructured into 3-step Quick Start flow
- CLAUDE.md key files table updated with plugin/cli.py and plugin/pair.py

Deprecation:
- skills/hermes-pairing-qr/SKILL.md gets deprecation frontmatter +
  notice in body pointing to 'hermes pair'
- skills/hermes-pairing-qr/hermes-pair prints a deprecation warning
  to stderr but stays functional for v0.7.0 users

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 09:18:01 -04:00
Bailey DixonandClaude Opus 4.6 5c03efc4ee refactor: restructure repo — promote Android project to root
Layout change:
- companion-app/ → root (app/, build.gradle.kts, gradlew, etc.)
- hermes-android-bridge/ → removed (absorbed into Compose rewrite)
- hermes-android-plugin/ → plugin/
- root tools/, skills/, tests/ → plugin/tools/, plugin/skills/, plugin/tests/
- root setup.py, pyproject.toml, requirements.txt → plugin/
- companion_relay/ → unchanged (Python package name = dir name)
- CI workflows updated for new paths

Android Studio now opens the repo root directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:59:42 -04:00