Initial import of NousResearch/hermes-agent
Deploy Site / deploy-vercel (push) Has been cancelled
Deploy Site / deploy-docs (push) Has been cancelled
Docker / shell lint / Lint Dockerfile (hadolint) (push) Has been cancelled
Docker / shell lint / Lint docker/ shell scripts (shellcheck) (push) Has been cancelled
Docker Build and Publish / build-amd64 (push) Has been cancelled
Docker Build and Publish / build-arm64 (push) Has been cancelled
Lint (ruff + ty) / ruff + ty diff (push) Has been cancelled
Lint (ruff + ty) / ruff enforcement (blocking) (push) Has been cancelled
Lint (ruff + ty) / Windows footguns (blocking) (push) Has been cancelled
Nix Lockfile Fix / auto-fix-main (push) Has been cancelled
Nix Lockfile Fix / fix (push) Has been cancelled
Nix / nix (macos-latest) (push) Has been cancelled
Nix / nix (ubuntu-latest) (push) Has been cancelled
OSV-Scanner / Scan lockfiles (push) Has been cancelled
Build Skills Index / build-index (push) Has been cancelled
Tests / test (1) (push) Has been cancelled
Tests / test (2) (push) Has been cancelled
Tests / test (3) (push) Has been cancelled
Tests / test (4) (push) Has been cancelled
Tests / test (5) (push) Has been cancelled
Tests / test (6) (push) Has been cancelled
Tests / e2e (push) Has been cancelled
uv.lock check / uv lock --check (push) Has been cancelled
Docker Build and Publish / merge (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
Tests / save-durations (push) Has been cancelled
Deploy Site / deploy-vercel (push) Has been cancelled
Deploy Site / deploy-docs (push) Has been cancelled
Docker / shell lint / Lint Dockerfile (hadolint) (push) Has been cancelled
Docker / shell lint / Lint docker/ shell scripts (shellcheck) (push) Has been cancelled
Docker Build and Publish / build-amd64 (push) Has been cancelled
Docker Build and Publish / build-arm64 (push) Has been cancelled
Lint (ruff + ty) / ruff + ty diff (push) Has been cancelled
Lint (ruff + ty) / ruff enforcement (blocking) (push) Has been cancelled
Lint (ruff + ty) / Windows footguns (blocking) (push) Has been cancelled
Nix Lockfile Fix / auto-fix-main (push) Has been cancelled
Nix Lockfile Fix / fix (push) Has been cancelled
Nix / nix (macos-latest) (push) Has been cancelled
Nix / nix (ubuntu-latest) (push) Has been cancelled
OSV-Scanner / Scan lockfiles (push) Has been cancelled
Build Skills Index / build-index (push) Has been cancelled
Tests / test (1) (push) Has been cancelled
Tests / test (2) (push) Has been cancelled
Tests / test (3) (push) Has been cancelled
Tests / test (4) (push) Has been cancelled
Tests / test (5) (push) Has been cancelled
Tests / test (6) (push) Has been cancelled
Tests / e2e (push) Has been cancelled
uv.lock check / uv lock --check (push) Has been cancelled
Docker Build and Publish / merge (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
Tests / save-durations (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Dashboard Plugin SDK + Registry
|
||||
*
|
||||
* Exposes React, UI components, hooks, and utilities on the window so
|
||||
* that plugin bundles can use them without bundling their own copies.
|
||||
*
|
||||
* Plugins call window.__HERMES_PLUGINS__.register(name, Component)
|
||||
* to register their tab component.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
useContext,
|
||||
createContext,
|
||||
} from "react";
|
||||
import { api, fetchJSON } from "@/lib/api";
|
||||
import { cn, timeAgo, isoTimeAgo } from "@/lib/utils";
|
||||
import { Badge } from "@nous-research/ui/ui/components/badge";
|
||||
import { Button } from "@nous-research/ui/ui/components/button";
|
||||
import { Checkbox } from "@nous-research/ui/ui/components/checkbox";
|
||||
import { Select, SelectOption } from "@nous-research/ui/ui/components/select";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@nous-research/ui/ui/components/card";
|
||||
import { Input } from "@nous-research/ui/ui/components/input";
|
||||
import { Label } from "@nous-research/ui/ui/components/label";
|
||||
import { Separator } from "@nous-research/ui/ui/components/separator";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@nous-research/ui/ui/components/tabs";
|
||||
import { useI18n } from "@/i18n";
|
||||
import { registerSlot, PluginSlot } from "./slots";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Plugin registry — plugins call register() to add their component.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type RegistryListener = () => void;
|
||||
|
||||
const _registered: Map<string, React.ComponentType> = new Map();
|
||||
const _loadErrors: Map<string, string> = new Map();
|
||||
const _listeners: Set<RegistryListener> = new Set();
|
||||
|
||||
function _notify() {
|
||||
for (const fn of _listeners) {
|
||||
try { fn(); } catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
/** Re-run registry subscribers (e.g. after a plugin script onload, or dev HMR re-inject). */
|
||||
export function notifyPluginRegistry() {
|
||||
_notify();
|
||||
}
|
||||
|
||||
/** Register a plugin component. Called by plugin JS bundles. */
|
||||
function registerPlugin(name: string, component: React.ComponentType) {
|
||||
_loadErrors.delete(name);
|
||||
_registered.set(name, component);
|
||||
_notify();
|
||||
}
|
||||
|
||||
/** Get a registered component by plugin name. */
|
||||
export function getPluginComponent(name: string): React.ComponentType | undefined {
|
||||
return _registered.get(name);
|
||||
}
|
||||
|
||||
export function getPluginLoadError(name: string): string | undefined {
|
||||
return _loadErrors.get(name);
|
||||
}
|
||||
|
||||
export function setPluginLoadError(name: string, message: string) {
|
||||
_loadErrors.set(name, message);
|
||||
_notify();
|
||||
}
|
||||
|
||||
/** Subscribe to registry changes (returns unsubscribe fn). */
|
||||
export function onPluginRegistered(fn: RegistryListener): () => void {
|
||||
_listeners.add(fn);
|
||||
return () => _listeners.delete(fn);
|
||||
}
|
||||
|
||||
/** Get current count of registered plugins. */
|
||||
export function getRegisteredCount(): number {
|
||||
return _registered.size;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Expose SDK + registry on window
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__HERMES_PLUGIN_SDK__: unknown;
|
||||
__HERMES_PLUGINS__: {
|
||||
register: typeof registerPlugin;
|
||||
registerSlot: typeof registerSlot;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function exposePluginSDK() {
|
||||
window.__HERMES_PLUGINS__ = {
|
||||
register: registerPlugin,
|
||||
registerSlot,
|
||||
};
|
||||
|
||||
window.__HERMES_PLUGIN_SDK__ = {
|
||||
// React core — plugins use these instead of importing react
|
||||
React,
|
||||
hooks: {
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
useContext,
|
||||
createContext,
|
||||
},
|
||||
|
||||
// Hermes API client
|
||||
api,
|
||||
// Raw fetchJSON for plugin-specific endpoints
|
||||
fetchJSON,
|
||||
|
||||
// UI components — Nous DS where available, shadcn/ui primitives elsewhere.
|
||||
components: {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardContent,
|
||||
Badge,
|
||||
Button,
|
||||
Checkbox,
|
||||
Input,
|
||||
Label,
|
||||
Select,
|
||||
SelectOption,
|
||||
Separator,
|
||||
Tabs,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
PluginSlot,
|
||||
},
|
||||
|
||||
// Utilities
|
||||
utils: { cn, timeAgo, isoTimeAgo },
|
||||
|
||||
// Hooks
|
||||
useI18n,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user