feat(FN-3396): bundle Cursor CLI as a plugin provider with dashboard auth w
Merges FN-3396's full Cursor CLI provider integration (Steps 1–4): defines a CLI-backed provider contract, adds the `fusion-plugin-cursor-runtime` plugin package with process management and runtime probes, wires dashboard auth flows and UI (ProviderCard, onboarding modal, settings), and bundles the Fusion-Task-Id: FN-3396
This commit is contained in:
@@ -24,6 +24,7 @@ vi.mock("@fusion/core", () => ({
|
||||
// Import SUT after mocks are in place
|
||||
import {
|
||||
ensureBundledDependencyGraphPluginInstalled,
|
||||
ensureBundledCursorRuntimePluginInstalled,
|
||||
ensureBundledPluginInstalled,
|
||||
resolvePluginEntryPath,
|
||||
} from "../bundled-plugin-install.js";
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
|
||||
const BUNDLED_PLUGIN_ID = "fusion-plugin-dependency-graph";
|
||||
const HERMES_PLUGIN_ID = "fusion-plugin-hermes-runtime";
|
||||
const CURSOR_PLUGIN_ID = "fusion-plugin-cursor-runtime";
|
||||
|
||||
function makeManifest(overrides?: Partial<{ id: string; version: string; name: string }>) {
|
||||
return {
|
||||
@@ -356,6 +358,30 @@ describe("ensureBundledDependencyGraphPluginInstalled", () => {
|
||||
).rejects.toThrow("Invalid plugin manifest");
|
||||
});
|
||||
|
||||
it("registers Cursor runtime through the dedicated helper", async () => {
|
||||
const manifest = makeManifest({ id: CURSOR_PLUGIN_ID, name: "Cursor Runtime" });
|
||||
mockExistsSync.mockImplementation((p: string) => {
|
||||
if (p.endsWith("manifest.json") && p.includes(CURSOR_PLUGIN_ID)) return true;
|
||||
if (p.endsWith("/src/index.ts") && p.includes(CURSOR_PLUGIN_ID)) return true;
|
||||
return false;
|
||||
});
|
||||
mockReadFile.mockResolvedValue(JSON.stringify(manifest));
|
||||
mockValidatePluginManifest.mockReturnValue({ valid: true, errors: [] });
|
||||
|
||||
const store = makePluginStore();
|
||||
const loader = makePluginLoader();
|
||||
|
||||
const result = await ensureBundledCursorRuntimePluginInstalled(
|
||||
store as unknown as import("@fusion/core").PluginStore,
|
||||
loader as unknown as import("@fusion/core").PluginLoader,
|
||||
);
|
||||
|
||||
expect(result).toBe("installed");
|
||||
expect(store.registerPlugin).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ manifest: expect.objectContaining({ id: CURSOR_PLUGIN_ID }) }),
|
||||
);
|
||||
});
|
||||
|
||||
it("registers Hermes from source entry when both src and dist entries exist", async () => {
|
||||
const manifest = makeManifest({ id: HERMES_PLUGIN_ID, name: "Hermes Runtime" });
|
||||
mockExistsSync.mockImplementation((p: string) => {
|
||||
|
||||
@@ -5,12 +5,14 @@ import { fileURLToPath } from "node:url";
|
||||
import { validatePluginManifest, type PluginInstallation, type PluginLoader, type PluginManifest, type PluginStore } from "@fusion/core";
|
||||
|
||||
const DEPENDENCY_GRAPH_PLUGIN_ID = "fusion-plugin-dependency-graph";
|
||||
const CURSOR_RUNTIME_PLUGIN_ID = "fusion-plugin-cursor-runtime";
|
||||
|
||||
export const BUNDLED_PLUGIN_IDS = [
|
||||
"fusion-plugin-dependency-graph",
|
||||
"fusion-plugin-hermes-runtime",
|
||||
"fusion-plugin-openclaw-runtime",
|
||||
"fusion-plugin-paperclip-runtime",
|
||||
"fusion-plugin-cursor-runtime",
|
||||
] as const;
|
||||
|
||||
export type BundledPluginId = (typeof BUNDLED_PLUGIN_IDS)[number];
|
||||
@@ -156,3 +158,10 @@ export async function ensureBundledDependencyGraphPluginInstalled(
|
||||
): Promise<EnsureBundledResult> {
|
||||
return ensureBundledPluginInstalled(pluginStore, pluginLoader, DEPENDENCY_GRAPH_PLUGIN_ID);
|
||||
}
|
||||
|
||||
export async function ensureBundledCursorRuntimePluginInstalled(
|
||||
pluginStore: PluginStore,
|
||||
pluginLoader: PluginLoader,
|
||||
): Promise<EnsureBundledResult> {
|
||||
return ensureBundledPluginInstalled(pluginStore, pluginLoader, CURSOR_RUNTIME_PLUGIN_ID);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user