feat: add Hermes integration panel to Settings → Integrations

Server-side:
- New hermes-integration module (runtime.js + routes.js + tests)
  exposing GET /api/openchamber/hermes/status
- Reports availability of agent-activity, session-steer, and plan-gate
  runtimes plus plan-gate default config
- Wired into feature-routes-runtime.js alongside existing integrations

UI:
- New HermesIntegration.tsx collapsible panel in Integrations page
- Connection status indicator (green/red dot) with 30s polling
- Plan gate default toggle (persists via updateDesktopSettings +
  recordDeferredOpenCodeRestart)
- Read-only status rows for activity stream, steer channel, plan gate
- Server version and uptime display

Settings:
- hermesPlanGateDefault field in settings registry and useUIStore
- Search index entry with keywords: hermes, agent, integration, etc.
- i18n keys for all 12 locales (English text as fallback)

Verification:
- Server tests: 7/7 passed (runtime + routes)
- UI tests: 4/4 passed (HermesIntegration.test.tsx)
- Typecheck: clean (no new errors)
- oxlint: clean on all new/modified files
This commit is contained in:
2026-09-10 11:25:51 +00:00
parent d37c58bae3
commit be159dac19
14 changed files with 669 additions and 1 deletions
@@ -28,6 +28,7 @@ import { registerMarkdownImageGrantRoutes } from '../markdown-image-grants/route
import { registerAgentActivityRoutes } from '../agent-activity/runtime.js';
import { registerSessionSteerRoutes } from '../session-steer/runtime.js';
import { registerPlanGateRoutes } from '../plan-gate/runtime.js';
import { registerHermesIntegrationRoutes } from '../hermes-integration/routes.js';
import { registerSkillRoutes } from './skill-routes.js';
import { registerPluginRoutes } from './plugin-routes.js';
import { getNpmInfo, clearCache as clearNpmCache } from './npm-registry.js';
@@ -145,6 +146,7 @@ export const createFeatureRoutesRuntime = (dependencies) => {
agentActivityRuntime,
sessionSteerRuntime,
planGateRuntime,
hermesIntegrationRuntime,
} = routeDependencies;
registerSettingsUtilityRoutes(app, {
@@ -216,6 +218,10 @@ export const createFeatureRoutesRuntime = (dependencies) => {
registerSessionSteerRoutes(app, sessionSteerRuntime);
registerPlanGateRoutes(app, planGateRuntime);
if (hermesIntegrationRuntime) {
registerHermesIntegrationRoutes(app, hermesIntegrationRuntime);
}
registerMarkdownImageGrantRoutes(app, {
fsPromises,
path,