Harden dependency floors and update the Vitest toolchain to patched releases. - upgrade workspace vitest and @vitest/coverage-v8 dependencies to the 4.1 line across packages and plugins - pin transitive protobufjs via pnpm overrides and lockfile updates to patched versions - adapt Vitest configs, engine test helpers, and security-floor coverage for the new dependency baselines - add the published CLI changeset and related workspace/package metadata updates included in the task branch Files changed: .changeset/fn-6042-security-dependencies.md | 5 + AGENTS.md | 4 + Dockerfile | 3 + docs/PLUGIN_AUTHORING.md | 2 - package.json | 3 +- packages/cli/package.json | 4 +- packages/cli/vitest.config.ts | 2 +- packages/core/package.json | 4 +- packages/core/vitest.config.ts | 2 +- packages/dashboard/app/test/mockApi.ts | 4 +- packages/dashboard/package.json | 4 +- packages/dashboard/vitest.config.ts | 2 +- packages/desktop/package.json | 4 +- packages/desktop/vitest.config.ts | 2 +- packages/droid-cli/package.json | 2 +- packages/droid-cli/vitest.config.ts | 2 +- packages/engine/package.json | 4 +- .../engine/src/__tests__/executor-test-helpers.ts | 29 +- .../engine/src/__tests__/gridlock-detector.test.ts | 5 +- .../src/__tests__/heartbeat-scheduler.test.ts | 3 +- packages/engine/src/__tests__/scheduler.test.ts | 24 +- packages/engine/src/__tests__/self-healing.test.ts | 5 + packages/engine/tsconfig.json | 3 +- packages/engine/vitest.config.ts | 10 +- packages/i18n/package.json | 2 +- packages/i18n/vitest.config.ts | 7 + packages/mobile/package.json | 2 +- packages/mobile/vitest.config.ts | 2 +- packages/pi-claude-cli/package.json | 2 +- packages/pi-claude-cli/vitest.config.ts | 2 +- packages/pi-llama-cpp/package.json | 2 +- packages/pi-llama-cpp/vitest.config.ts | 2 +- packages/plugin-sdk/package.json | 2 +- packages/plugin-sdk/vitest.config.ts | 2 +- .../examples/fusion-plugin-auto-label/package.json | 2 +- .../fusion-plugin-auto-label/vitest.config.ts | 2 +- .../examples/fusion-plugin-ci-status/package.json | 2 +- .../fusion-plugin-ci-status/vitest.config.ts | 2 +- .../fusion-plugin-notification/package.json | 2 +- .../fusion-plugin-notification/vitest.config.ts | 2 +- .../fusion-plugin-settings-demo/package.json | 2 +- .../fusion-plugin-settings-demo/vitest.config.ts | 2 +- plugins/fusion-plugin-acp-runtime/package.json | 2 +- plugins/fusion-plugin-acp-runtime/vitest.config.ts | 2 +- plugins/fusion-plugin-agent-browser/package.json | 2 +- .../fusion-plugin-agent-browser/vitest.config.ts | 2 +- .../fusion-plugin-cli-printing-press/package.json | 2 +- .../vitest.config.ts | 2 +- .../package.json | 2 +- .../src/__tests__/orchestrator-live-output.test.ts | 4 +- .../vitest.config.ts | 2 +- plugins/fusion-plugin-cursor-runtime/package.json | 4 +- .../fusion-plugin-dependency-graph/package.json | 4 +- .../vitest.config.ts | 2 +- plugins/fusion-plugin-droid-runtime/package.json | 2 +- .../fusion-plugin-droid-runtime/vitest.config.ts | 2 +- plugins/fusion-plugin-even-cards/package.json | 2 +- plugins/fusion-plugin-even-cards/vitest.config.ts | 2 +- .../package.json | 2 +- .../vitest.config.ts | 2 +- plugins/fusion-plugin-hermes-runtime/package.json | 2 +- .../fusion-plugin-hermes-runtime/vitest.config.ts | 2 +- .../fusion-plugin-openclaw-runtime/package.json | 2 +- .../vitest.config.ts | 2 +- .../fusion-plugin-paperclip-runtime/package.json | 2 +- .../vitest.config.ts | 2 +- plugins/fusion-plugin-reports/package.json | 2 +- .../src/__tests__/review-panel.test.ts | 6 +- plugins/fusion-plugin-reports/vitest.config.ts | 2 +- plugins/fusion-plugin-roadmap/package.json | 2 +- plugins/fusion-plugin-roadmap/vitest.config.ts | 2 +- plugins/fusion-plugin-whatsapp-chat/package.json | 2 +- .../fusion-plugin-whatsapp-chat/vitest.config.ts | 2 +- pnpm-lock.yaml | 626 ++++++++------------- .../__tests__/dependency-security-floor.test.mjs | 95 ++++ 75 files changed, 475 insertions(+), 491 deletions(-) Fusion-Task-Id: FN-6042 Fusion-Task-Lineage: fff6a1cb-8937-435c-9a91-b7c7a59cc80e
Hermes Runtime Plugin
Drives the local hermes CLI (NousResearch/hermes-agent) as a subprocess, so a Fusion agent backed by this runtime delegates each prompt to a real Hermes Agent process running on the same machine.
What it does
For each promptWithFallback(session, prompt) call:
- Spawns
hermes chat -q <prompt> -Q --source tool(with--resume <id>on subsequent calls in the same session). - Captures the trailing
session_id: YYYYMMDD_HHMMSS_xxxxxxline from stdout. - Strips ANSI + TUI chrome (
╭─ Hermes ─╮,↻ Resumed session …, etc.) and forwards the cleaned response body tosession.callbacks.onText(...). - Persists the captured session id on the session object so the next call resumes the same Hermes session.
This is fundamentally different from the older "raw-model" approach that bypassed hermes entirely by calling @mariozechner/pi-ai directly. The CLI subprocess is now the source of truth — provider/model selection, auth, skills, and memory are all the responsibility of the user's local hermes install.
Prerequisites
You need the hermes Python CLI on PATH (or set binaryPath / HERMES_BIN). Install instructions:
# Recommended: use the upstream installer
curl -LsSf https://hermes-agent.nousresearch.com/install.sh | sh
# Or via pipx (cross-platform)
pipx install hermes-agent
After install, run hermes login (or hermes auth) to configure a provider. The Fusion plugin does not manage Hermes auth — it inherits whatever the local install has.
Verify with hermes --version.
Fusion skill auto-install
When the Hermes runtime plugin loads, it attempts to auto-install/mirror Fusion's bundled fusion skill into the active Hermes profile skill directory:
- default profile:
${HERMES_HOME:-~/.hermes}/skills/fusion - named profile:
${HERMES_HOME:-~/.hermes}/profiles/<profile>/skills/fusion
The installer is idempotent and self-healing:
- leaves an already-correct install untouched
- replaces prior Fusion installs it can positively identify
- avoids replacing unrelated user-managed directories
If the bundled Fusion skill source is missing or filesystem writes fail, the plugin logs a warning and still starts the Hermes runtime.
Limitations
Because we drive the CLI's chat -q mode:
- No per-token streaming. Hermes buffers output through prompt_toolkit; the full response arrives once the process exits.
onTextis called exactly once per turn. - No reasoning/thinking deltas.
-Qmode suppresses them. If you need streaming + reasoning, switch to Hermes's ACP mode (not yet implemented in this plugin). - No tool-call hooks. Hermes runs tools internally; Fusion only sees the final assistant text. Use
yolo: trueto skip Hermes's interactive approval prompts in non-interactive sessions. - No JS tool callbacks.
customToolscallback functions are still not executable through Hermes CLI mode; Hermes runs its own tool layer and Fusion receives final text. - Fusion context is prompt-mediated. The engine forwards requested Fusion skill names into
skills, and the adapter prepends Fusion system/runtime context on the first turn of each session so capability expectations (for example messaging/delegation flows) are not silently dropped on non-pi runtimes. AgentRuntimeOptions.cwd/sessionManagerare still adapter-noops in CLI mode.
Settings
| Key | Env var | Default | Notes |
|---|---|---|---|
binaryPath |
HERMES_BIN |
hermes |
Path to the hermes binary. Falls back to PATH lookup. |
model |
HERMES_MODEL_ID |
(Hermes default) | -m <model> (e.g. claude-sonnet-4-5, MiniMax-M3). |
provider |
HERMES_PROVIDER |
(Hermes default) | --provider <provider> — one of auto, anthropic, openrouter, gemini, openai-codex, copilot, copilot-acp, huggingface, zai, kimi-coding, minimax, minimax-cn, kilocode, xiaomi, nous. |
maxTurns |
HERMES_MAX_TURNS |
12 |
--max-turns N. Hermes's own default is 90; we cap lower. |
yolo |
HERMES_YOLO |
false |
--yolo — skip interactive approval. Required for non-interactive sessions that use shell-style tools. |
cliTimeoutMs |
HERMES_CLI_TIMEOUT_MS |
300000 (5 min) |
Hard kill on the Fusion side. |
Settings precedence: plugin settings → env var → default.
Public API
import {
HermesRuntimeAdapter,
resolveCliSettings,
invokeHermesCli,
buildHermesArgs,
parseHermesOutput,
probeHermesBinary,
type HermesCliSettings,
type HermesCliResult,
type HermesBinaryStatus,
} from "@fusion-plugin-examples/hermes-runtime";
probeHermesBinary({ binaryPath?, timeoutMs? }) runs hermes --version and returns { available, version, binaryPath, reason, probeDurationMs }. Used by the dashboard's "Runtimes → Hermes" settings card to power the install-status badge.
Metadata
- Plugin ID:
fusion-plugin-hermes-runtime - Runtime ID:
hermes - Package:
@fusion-plugin-examples/hermes-runtime
Development
pnpm --filter @fusion-plugin-examples/hermes-runtime test # 41 tests
pnpm --filter @fusion-plugin-examples/hermes-runtime build