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:
@@ -36,6 +36,7 @@ describe("PluginRunner", () => {
|
||||
getPluginUiSlots: ReturnType<typeof vi.fn>;
|
||||
getPluginUiContributions: ReturnType<typeof vi.fn>;
|
||||
getPluginRuntimes: ReturnType<typeof vi.fn>;
|
||||
getCliProviderContributions: ReturnType<typeof vi.fn>;
|
||||
getPluginSkills: ReturnType<typeof vi.fn>;
|
||||
getPluginWorkflowSteps: ReturnType<typeof vi.fn>;
|
||||
getPluginWorkflowStepTemplates: ReturnType<typeof vi.fn>;
|
||||
@@ -100,6 +101,7 @@ describe("PluginRunner", () => {
|
||||
getPluginUiSlots: vi.fn().mockReturnValue([]),
|
||||
getPluginUiContributions: vi.fn().mockReturnValue([]),
|
||||
getPluginRuntimes: vi.fn().mockReturnValue([]),
|
||||
getCliProviderContributions: vi.fn().mockReturnValue([]),
|
||||
getPluginSkills: vi.fn().mockReturnValue([]),
|
||||
getPluginWorkflowSteps: vi.fn().mockReturnValue([]),
|
||||
getPluginWorkflowStepTemplates: vi.fn().mockReturnValue([]),
|
||||
@@ -832,6 +834,28 @@ describe("PluginRunner", () => {
|
||||
});
|
||||
|
||||
describe("new plugin contribution accessors", () => {
|
||||
it("getCliProviderContributions returns cached CLI-provider contributions", async () => {
|
||||
const contributions = [
|
||||
{
|
||||
pluginId: "cursor-plugin",
|
||||
contribution: {
|
||||
providerId: "cursor-cli",
|
||||
displayName: "Cursor CLI",
|
||||
binaryName: "cursor-agent",
|
||||
providerType: "cli",
|
||||
statusRoute: "/providers/cursor-cli/status",
|
||||
authRoute: "/auth/cursor-cli",
|
||||
},
|
||||
},
|
||||
];
|
||||
mockPluginLoader.getCliProviderContributions.mockReturnValue(contributions);
|
||||
await pluginRunner.init();
|
||||
const first = pluginRunner.getCliProviderContributions();
|
||||
const second = pluginRunner.getCliProviderContributions();
|
||||
expect(first).toEqual(contributions);
|
||||
expect(second).toBe(first);
|
||||
});
|
||||
|
||||
it("getPluginSkills returns empty array initially", async () => {
|
||||
await pluginRunner.init();
|
||||
expect(pluginRunner.getPluginSkills()).toEqual([]);
|
||||
@@ -887,6 +911,7 @@ describe("PluginRunner", () => {
|
||||
|
||||
it("invalidates new contribution caches on state change and loader events", async () => {
|
||||
await pluginRunner.init();
|
||||
pluginRunner.getCliProviderContributions();
|
||||
pluginRunner.getPluginSkills();
|
||||
pluginRunner.getPluginWorkflowSteps();
|
||||
pluginRunner.getPluginWorkflowStepTemplates();
|
||||
@@ -895,6 +920,7 @@ describe("PluginRunner", () => {
|
||||
|
||||
const stateChanged = mockPluginStore.on.mock.calls.find((call) => call[0] === "plugin:stateChanged")?.[1];
|
||||
stateChanged?.();
|
||||
pluginRunner.getCliProviderContributions();
|
||||
pluginRunner.getPluginSkills();
|
||||
pluginRunner.getPluginWorkflowSteps();
|
||||
pluginRunner.getPluginWorkflowStepTemplates();
|
||||
@@ -903,12 +929,14 @@ describe("PluginRunner", () => {
|
||||
|
||||
const loaded = mockPluginLoader.on.mock.calls.find((call) => call[0] === "plugin:loaded")?.[1];
|
||||
loaded?.({ pluginId: "test-plugin" });
|
||||
pluginRunner.getCliProviderContributions();
|
||||
pluginRunner.getPluginSkills();
|
||||
pluginRunner.getPluginWorkflowSteps();
|
||||
pluginRunner.getPluginWorkflowStepTemplates();
|
||||
pluginRunner.getPluginPromptContributions();
|
||||
pluginRunner.getPluginSetupInfo();
|
||||
|
||||
expect(mockPluginLoader.getCliProviderContributions).toHaveBeenCalledTimes(3);
|
||||
expect(mockPluginLoader.getPluginSkills).toHaveBeenCalledTimes(3);
|
||||
expect(mockPluginLoader.getPluginWorkflowSteps).toHaveBeenCalledTimes(3);
|
||||
expect(mockPluginLoader.getPluginWorkflowStepTemplates).toHaveBeenCalledTimes(3);
|
||||
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
PluginUiSlotDefinition,
|
||||
PluginUiContributionDefinition,
|
||||
PluginRuntimeRegistration,
|
||||
CliProviderContribution,
|
||||
PluginContext,
|
||||
PluginSkillContribution,
|
||||
PluginWorkflowStepContribution,
|
||||
@@ -83,6 +84,11 @@ interface CachedRuntimes {
|
||||
version: number;
|
||||
}
|
||||
|
||||
interface CachedCliProviderContributions {
|
||||
contributions: Array<{ pluginId: string; contribution: CliProviderContribution }>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
interface CachedSkills {
|
||||
skills: Array<{ pluginId: string; skill: PluginSkillContribution }>;
|
||||
version: number;
|
||||
@@ -121,6 +127,7 @@ export class PluginRunner {
|
||||
private cachedUiSlots: CachedUiSlots | null = null;
|
||||
private cachedUiContributions: CachedUiContributions | null = null;
|
||||
private cachedRuntimes: CachedRuntimes | null = null;
|
||||
private cachedCliProviderContributions: CachedCliProviderContributions | null = null;
|
||||
private cachedSkills: CachedSkills | null = null;
|
||||
private cachedWorkflowSteps: CachedWorkflowSteps | null = null;
|
||||
private cachedWorkflowStepTemplates: CachedWorkflowStepTemplates | null = null;
|
||||
@@ -131,6 +138,7 @@ export class PluginRunner {
|
||||
private uiSlotsCacheVersion = 0;
|
||||
private uiContributionsCacheVersion = 0;
|
||||
private runtimesCacheVersion = 0;
|
||||
private cliProviderContributionsCacheVersion = 0;
|
||||
private skillsCacheVersion = 0;
|
||||
private workflowStepsCacheVersion = 0;
|
||||
private workflowStepTemplatesCacheVersion = 0;
|
||||
@@ -207,6 +215,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -318,6 +327,16 @@ export class PluginRunner {
|
||||
return this.cachedRuntimes.runtimes;
|
||||
}
|
||||
|
||||
getCliProviderContributions(): Array<{ pluginId: string; contribution: CliProviderContribution }> {
|
||||
if (!this.cachedCliProviderContributions || this.cachedCliProviderContributions.version !== this.cliProviderContributionsCacheVersion) {
|
||||
this.cachedCliProviderContributions = {
|
||||
contributions: this.options.pluginLoader.getCliProviderContributions(),
|
||||
version: this.cliProviderContributionsCacheVersion,
|
||||
};
|
||||
}
|
||||
return this.cachedCliProviderContributions.contributions;
|
||||
}
|
||||
|
||||
getPluginSkills(): Array<{ pluginId: string; skill: PluginSkillContribution }> {
|
||||
if (!this.cachedSkills || this.cachedSkills.version !== this.skillsCacheVersion) {
|
||||
this.cachedSkills = {
|
||||
@@ -475,6 +494,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -495,6 +515,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -520,6 +541,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -545,6 +567,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -569,6 +592,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -585,6 +609,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -601,6 +626,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -617,6 +643,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -633,6 +660,7 @@ export class PluginRunner {
|
||||
this.invalidateUiSlotsCache();
|
||||
this.invalidateUiContributionsCache();
|
||||
this.invalidateRuntimesCache();
|
||||
this.invalidateCliProviderContributionsCache();
|
||||
this.invalidateSkillsCache();
|
||||
this.invalidateWorkflowStepsCache();
|
||||
this.invalidateWorkflowStepTemplatesCache();
|
||||
@@ -848,6 +876,11 @@ export class PluginRunner {
|
||||
this.log.log(`Runtimes cache invalidated (version: ${this.runtimesCacheVersion})`);
|
||||
}
|
||||
|
||||
private invalidateCliProviderContributionsCache(): void {
|
||||
this.cliProviderContributionsCacheVersion++;
|
||||
this.log.log(`CLI provider contributions cache invalidated (version: ${this.cliProviderContributionsCacheVersion})`);
|
||||
}
|
||||
|
||||
private invalidateSkillsCache(): void {
|
||||
this.skillsCacheVersion++;
|
||||
this.log.log(`Skills cache invalidated (version: ${this.skillsCacheVersion})`);
|
||||
|
||||
Reference in New Issue
Block a user