fix(plugins): re-export probe symbols + declare plugin deps in dashboard

- Hermes / OpenClaw plugin index.ts now re-export `probeHermesBinary` /
  `probeOpenClawBinary` and their status types so the dashboard's
  `runtime-provider-probes.ts` façade can import them via the public
  package entry instead of deep paths.
- Dashboard `package.json` adds `@fusion-plugin-examples/hermes-runtime`,
  `…/openclaw-runtime`, `…/paperclip-runtime` as workspace deps so
  pnpm symlinks them into `packages/dashboard/node_modules/`. Without
  these, the new probe imports failed with "Cannot find module" during
  `pnpm typecheck`.

This clears 6 of the 9 outstanding typecheck errors. The remaining 3 are
in the in-flight Hermes plugin rewrite (runtime-adapter still imports
from a deleted `./pi-module.js`; the new `index.ts` calls a factory
with the wrong arg type) and should be resolved by the same change set
that landed the rewrite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Fusion
2026-04-27 20:22:18 -07:00
committed by gsxdsm
parent 5159cc2a68
commit 6e65786bc5
82 changed files with 8481 additions and 2833 deletions

View File

@@ -1,86 +1,79 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const { mockResolveModelConfig } = vi.hoisted(() => ({
mockResolveModelConfig: vi.fn().mockReturnValue({
provider: "anthropic",
modelId: "claude-sonnet-4-5",
apiKey: undefined,
thinkingLevel: undefined,
const { mockResolveCli } = vi.hoisted(() => ({
mockResolveCli: vi.fn().mockReturnValue({
binaryPath: "hermes",
model: undefined,
provider: undefined,
maxTurns: 12,
yolo: false,
cliTimeoutMs: 300_000,
}),
}));
vi.mock("../pi-module.js", () => ({
resolveModelConfig: mockResolveModelConfig,
}));
import plugin, { hermesRuntimeMetadata, hermesRuntimeFactory, HERMES_RUNTIME_ID } from "../index.js";
vi.mock("../cli-spawn.js", async () => {
const actual = await vi.importActual("../cli-spawn.js");
return {
...actual,
resolveCliSettings: mockResolveCli,
};
});
import plugin, { hermesRuntimeMetadata, hermesRuntimeFactory, HERMES_RUNTIME_ID, } from "../index.js";
import { HermesRuntimeAdapter } from "../runtime-adapter.js";
function createMockContext(settings = {}) {
return {
pluginId: "fusion-plugin-hermes-runtime",
settings,
logger: {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
},
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
emitEvent: vi.fn(),
taskStore: {
getTask: vi.fn(),
},
taskStore: { getTask: vi.fn() },
};
}
describe("hermes-runtime plugin", () => {
beforeEach(() => {
vi.clearAllMocks();
mockResolveCli.mockReturnValue({
binaryPath: "hermes",
model: undefined,
provider: undefined,
maxTurns: 12,
yolo: false,
cliTimeoutMs: 300_000,
});
});
it("has expected manifest identity", () => {
expect(plugin.manifest.id).toBe("fusion-plugin-hermes-runtime");
expect(plugin.manifest.name).toBe("Hermes Runtime Plugin");
expect(plugin.manifest.version).toBe("0.1.0");
expect(plugin.state).toBe("installed");
});
it("registers runtime metadata and exports matching constants", () => {
expect(HERMES_RUNTIME_ID).toBe("hermes");
expect(plugin.runtime?.metadata.runtimeId).toBe("hermes");
expect(plugin.runtime?.metadata.name).toBe("Hermes Runtime");
expect(plugin.runtime?.metadata.description).toContain("pi-ai direct streaming");
expect(plugin.runtime?.metadata.description).toContain("hermes");
expect(plugin.manifest.runtime).toEqual(hermesRuntimeMetadata);
});
it("onLoad resolves model config and logs selected provider/model without api key", async () => {
const ctx = createMockContext({ provider: "openai", modelId: "gpt-5", apiKey: "secret" });
mockResolveModelConfig.mockReturnValue({
provider: "openai",
modelId: "gpt-5",
apiKey: "secret",
thinkingLevel: "medium",
it("onLoad logs selected binary path & model and emits loaded event", async () => {
mockResolveCli.mockReturnValue({
binaryPath: "/opt/homebrew/bin/hermes",
model: "claude-sonnet-4-5",
provider: "anthropic",
maxTurns: 12,
yolo: false,
cliTimeoutMs: 300_000,
});
await plugin.hooks.onLoad?.(ctx);
expect(mockResolveModelConfig).toHaveBeenCalledWith(ctx.settings);
expect(ctx.logger.info).toHaveBeenCalledWith("Hermes Runtime Plugin loaded — using openai/gpt-5");
expect(ctx.logger.info.mock.calls[0][0]).not.toContain("secret");
const ctx = createMockContext({ binaryPath: "/opt/homebrew/bin/hermes" });
await plugin.hooks.onLoad(ctx);
expect(mockResolveCli).toHaveBeenCalledWith(ctx.settings);
expect(ctx.logger.info).toHaveBeenCalledWith(expect.stringContaining("/opt/homebrew/bin/hermes"));
expect(ctx.emitEvent).toHaveBeenCalledWith("hermes-runtime:loaded", {
runtimeId: "hermes",
version: "0.1.0",
version: plugin.manifest.version,
});
});
it("runtime factory resolves settings and returns HermesRuntimeAdapter", async () => {
const ctx = createMockContext({ provider: "openai", modelId: "gpt-5" });
mockResolveModelConfig.mockReturnValue({
provider: "openai",
modelId: "gpt-5",
apiKey: "api-key",
thinkingLevel: "high",
});
it("factory returns a HermesRuntimeAdapter", async () => {
const ctx = createMockContext({ binaryPath: "hermes" });
const runtime = (await hermesRuntimeFactory(ctx));
expect(mockResolveModelConfig).toHaveBeenCalledWith(ctx.settings);
expect(runtime).toBeInstanceOf(HermesRuntimeAdapter);
expect(runtime.id).toBe("hermes");
expect(runtime.name).toBe("Hermes Runtime");
expect(runtime.config).toEqual({
provider: "openai",
modelId: "gpt-5",
apiKey: "api-key",
thinkingLevel: "high",
});
});
});
//# sourceMappingURL=index.test.js.map