feat(plugins): generic session execution targets, hook identity, setup and Desktop session viewers - #104567
feat(plugins): generic session execution targets, hook identity, setup and Desktop session viewers#104567Zeus-Deus wants to merge 11 commits into
Conversation
Realms status-polling fix — automated verification updateThis follow-up fixes the flashing “Realm unavailable” sidebar badges and “Realm status unavailable · Retry” thread row when the desktop UI is enabled but a session has no confirmed realm.
Verification: regression tests cover polling through pending/error transitions, cached-badge recovery and ownership boundaries. A separate native Electron DEV instance reproduced the flashing against a real disabled backend; the fixed build stayed quiet with both disabled and enabled backends. No provider credentials or model turns were used. This is status/UI regression verification, not a new end-to-end validation of compositor creation, Watch/Pop out or takeover. The existing draft state and prerequisite dependency are unchanged. Pushed in a5837e0. Focused checks on the PR branch: 9 frontend tests and 15 Python tests passed, plus Desktop typecheck, targeted ESLint and Ruff. GitHub verification is now complete for this commit: CI, Docker, and Nix all passed. The PR remains a draft pending its existing prerequisite. |
Follow-up: keep Watch connectedCommit
Verification:
Only worktree source and disposable test resources were changed; no installed Desktop build or existing agent/VM was updated or restarted. Diff and commit text were scrubbed for private paths/identifiers; no raw rig logs or screenshots are attached. GitHub sees the new head, but all three workflow runs currently report |
|
CI for the current head (
Could a maintainer please approve the workflows and re-run CI? Heads-up on placement: following CONTRIBUTING and the new plugin catalog, I'm moving Realms out of this tree. Realms itself will ship from its own repo (Zeus-Deus/hermes-realms) with a
I'll update the title and description when that lands. If you'd rather keep it bundled, say so and I'll stop. |
Give plugin hooks, slash commands and pre_tool_call a trusted owner identity (runtime/stored session ids, profile, hermes_home, source/surface and session_origin) and publish it through a new on_session_identity hook from the CLI, gateway and TUI/Desktop lifecycles. Hooks run in the owning profile.
Add a session execution context API so a plugin can route a session's terminal, file, process and computer-use work into an environment it owns. Named terminal/computer_use targets are registered by plugins and require an explicit, non-provisioning selector; selections are revalidated before use, background processes keep their routed cwd, the code-exec sandbox refuses a named target instead of falling back, and computer-use backend admission retries are bounded. load_config_readonly(home=...) reads another profile without writing to it.
Plugins may declare a setup entrypoint that runs only after the user reviews and consents to a profile- and revision-bound proposal (CLI, dashboard and plugins.manage). Bundled plugin rows report default_enabled separately from status. A new on_session_idle hook lets a plugin submit one owner-pinned native turn at an idle boundary to continue work it was asked to do.
Let desktop plugins contribute session-scoped UI (status stack, session tile, sidebar row), open sandboxed isolated preview viewers and native viewer windows with keep-alive renewal, render a plugin settings slot, and review native plugin setup before enabling. Viewer popups are revealed without focus stealing on Wayland.
dd23bd6 to
bf4dd5e
Compare
…-Watch A plugin viewer bootstraps from a one-time #ticket= fragment that it strips on load. The workspace-edit auto-reload treated the loopback viewer like a dev server and reloaded it ticketless, which ended the view and its keep-alive. Isolated viewer tabs are now never auto-reloaded. Isolated tabs were also reused only on an exact URL match, so every Watch (fresh ticket) opened another tab and left dead ones behind. Reuse now matches the viewer location without the fragment, so a new Watch replaces the old tab. The new ticket's keep-alive binds to the rebuilt guest document, never the one it replaced.
…ager Route the catalog card's agent switch through the reviewed setup-consent toggle, take the setup lock only for plugins that declare native setup so the admission transaction keeps its own concurrency, and move the branch's tests onto the platforms(...) marks, ruamel YAML and the current plugin-set helpers.
# Conflicts: # apps/desktop/src/store/preview.ts # tools/terminal_tool.py
# Conflicts: # hermes_cli/plugins_manifest.py
Update 2026-09-28: ported onto current main. Merged
origin/main(no rebase). Upstream had splitplugins_cmd.pyintoplugins_cmd_*modules and moved enable/install/picker onto the PM admission transaction, so setup consent now runs inside that path.plugins enable, install, the picker, packs, the dashboard/RPC toggle and the new catalog-card switch all go through the reviewed setup gate. The setup lock is taken only for plugins that declaresetup:; other plugins keep the admission transaction's own concurrency. Conflicts were also resolved in the terminal/file/process routing (upstream's task-key qualification and container-visible cwd are kept alongside the routed-target cwd), in the computer-use backend (a session-owned target never falls back to the terminal sandbox), and in the Plugins tab, install modal, status stack and agent-plugins store. Tests now useplatforms(...)marks and ruamel YAML, matching main. No behaviour change intended.Generic plugin session surfaces
This PR adds the generic core surfaces that let a plugin own a private execution environment for a session. It contains no product-specific plugin; every surface is plugin-neutral and tested with a small neutral test plugin (
sample-target).It supersedes #103690, which is folded in here, so there is one core PR.
What it adds
register_terminal_target_resolver) and acomputer_usetarget resolver.terminal(target="<name>", ...). Ordinary tools, files and cwd are unchanged.computer_usebackend admission retries are bounded.on_session_identity, plus session start/finalize/reset) and can deliver an idle continuation into the owning session (on_session_idle).setup:entrypoint inplugin.yaml,setup_consentinplugins.manage,default_enabled), with progress that survives UI remounts and timeout cleanup of the whole process group.session-execution-context-api.md,session-hook-identity-api.md,plugin-idle-continuations.md,desktop-plugin-sdk.md,plugins/index.mdandapps/desktop/docs/plugin-session-viewers.md.Where the example plugin went
The optional Realms plugin that drove this work now ships as a standalone plugin, per CONTRIBUTING.md ("Ship as a Standalone Plugin"): https://github.com/Zeus-Deus/hermes-realms (v0.2.0). Its catalog entry will be proposed separately after this PR merges. Core no longer bundles, packages or special-cases it, and
pyproject.tomlanduv.lockare unchanged frommain.Verification
main; the 35 affected test files (608 tests) pass after the rebase. Full Python suite viascripts/run_tests.sh: no failures unique to this branch. The remaining local failures also fail on plainmainlocally (no DNS / host-specific) or were load flakes that pass on rerun.tests/e2ematchesmain.--check, ruff, the lint.yml gates anduv lock --checkpass.hermes plugins install(v0.2.0, not bundled; its desktop half loaded from the install) and drove a private VM target: a targeted command ran inside the VM, whilegh auth statusandgitran normally on the host. The plugin declaresrequires_hermes >=0.22, so the private build carried a local version bump for this check only.CI for this fork PR still needs maintainer approval to run.