b469be8cc3
The previous commit claims every outbox before delivering and runs deliveries per target profile, but `drainBusy` still spanned the delivery phase: a `bot_relay.outbox.pending` push that arrived while one lane ran a long turn (up to RELAY_DELIVER_TIMEOUT_MS) only set `drainRerun`, and the new envelope was claimed after that turn — the reporter's step 3 (bot C mails D while A→B runs) still ended in `queued_expired`, because the gateway checks the TTL at the claim. Scope `drainBusy` to the claim phase and make the delivery lanes module state: `relayLanes` maps `target_connection::target_profile` to the tail of that target's in-flight deliveries, so a later drain appends to the running lane (same target stays ordered, one turn at a time) or starts a new one (other targets run now). Lane entries drop once idle; stopBotRelay clears them so a restart begins fresh. Tests: keep the contributor's red-on-base test (claims every outbox first, delivers to different targets concurrently) and replace the ordering-only test — green on base — with one that pins the mid-delivery claim plus the same-target ordering (red on base AND on the previous commit alone). Docs: bot-mode.md states the delivery concurrency contract. Part of #111587 (with the previous commit: Fixes #111587)
Bundled plugins
Drop a <name>/plugin.{ts,tsx} here that default-exports a HermesPlugin and
it registers automatically at boot (vite glob in ../contrib/plugins.ts), with
the same inventory + live enable/disable contract as runtime plugins.
Keep this tree for real shipped plugins (and the small authoring fixtures that
dogfood the SDK). One-off demos that rebuild a core chrome piece 1:1 do not
belong here — they double the UI and confuse Capabilities ▸ Plugins. Publish those
in the companion
hermes-example-plugins
repo instead.
User- and agent-authored plugins load at runtime from
$HERMES_HOME/desktop-plugins/<name>/plugin.js (the disk door) — see the
hermes-desktop-plugins skill.