fix(FN-9093): eagerly install bundled Cursor runtime plugin at host boot

The Cursor provider card's Enable action only flips useCursorCli in
settings and never registers fusion-plugin-cursor-runtime, so
getRuntimeById("cursor") missed and every cursor-cli selection hit the
runtime-routed fail-fast error even with an authenticated cursor-agent.
Mirror the FN-7761 Grok eager bootstrap in serve, dashboard, and daemon,
guarded by the same source-scan regression test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-08-15 21:07:02 -07:00
parent 0935e27902
commit 0ec3c76faf
5 changed files with 90 additions and 3 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Fix Cursor CLI models failing with "install and enable the Cursor runtime plugin" after enabling the provider.
category: fix
dev: serve/dashboard/daemon now eagerly run `ensureBundledCursorRuntimePluginInstalled` at boot, mirroring the FN-7761 Grok bootstrap, so `getRuntimeById("cursor")` resolves for cursor-cli selections.

View File

@@ -30,6 +30,29 @@ describe("Grok CLI runtime packaged bootstrap", () => {
}
});
/*
* FNXC:CursorCli 2026-08-16-04:05:
* FN-9093 regression guard: the Cursor provider card's Enable action only flips `useCursorCli` in settings,
* so without this eager bootstrap nothing ever registers fusion-plugin-cursor-runtime and every cursor-cli
* selection fails the runtime-routed fail-fast with "install and enable the Cursor runtime plugin".
* Mirrors the FN-7761 Grok guard above: the helper must run before loadAllPlugins() in each long-lived host.
*/
describe("Cursor CLI runtime packaged bootstrap", () => {
for (const command of ["serve", "daemon", "dashboard"] as const) {
it(`${command} eagerly ensures the bundled Cursor runtime before loading enabled plugins`, () => {
const source = readCommand(command);
const importIndex = source.indexOf("ensureBundledCursorRuntimePluginInstalled");
const ensureIndex = source.indexOf("ensureBundledCursorRuntimePluginInstalled(pluginStore, pluginLoader)");
const loadIndex = source.indexOf("pluginLoader.loadAllPlugins()");
expect(importIndex).toBeGreaterThanOrEqual(0);
expect(ensureIndex).toBeGreaterThanOrEqual(0);
expect(loadIndex).toBeGreaterThanOrEqual(0);
expect(ensureIndex).toBeLessThan(loadIndex);
});
}
});
/*
FNXC:GrokCliRouting 2026-07-15-10:17:
Hosts must pass a real engine PluginRunner (getRuntimeById) into createServer — never the bare PluginLoader. Engine-mode merge omits onMerge so server.ts derives engine.onMerge. UI-only / bare CLI leave pluginRunner undefined (dual-remediation).

View File

@@ -80,7 +80,7 @@ import { wrapAuthStorageWithApiKeyProviders } from "./provider-auth.js";
import { getPackageManagerAgentDir } from "./auth-paths.js";
import { resolveProject } from "../project-context.js";
import { startMigrationHoldingServer } from "./migration-holding-server.js";
import { ensureBundledDependencyGraphPluginInstalled, ensureBundledGrokRuntimePluginInstalled } from "../plugins/bundled-plugin-install.js";
import { ensureBundledCursorRuntimePluginInstalled, ensureBundledDependencyGraphPluginInstalled, ensureBundledGrokRuntimePluginInstalled } from "../plugins/bundled-plugin-install.js";
import { handleOpencodeGoApiKeySaved, syncStartupModels } from "./startup-model-sync.js";
import { registerCustomProviders, reregisterCustomProviders } from "./custom-provider-registry.js";
import { ensureCwdProjectRegistered } from "./ensure-project-registered.js";
@@ -572,6 +572,24 @@ export async function runDaemon(opts: DaemonOptions = {}) {
console.warn(`[plugins] Failed to auto-install bundled Grok CLI runtime plugin: ${err instanceof Error ? err.message : err}`);
}
/*
* FNXC:CursorCli 2026-08-16-04:05:
* FN-9093: daemon executors/reviewers/mergers resolve `cursor-cli` through the fail-fast runtime route,
* but nothing registered fusion-plugin-cursor-runtime (the provider Enable action only sets `useCursorCli`),
* so Cursor sessions failed with the missing-runtime error. Mirror the FN-7761 Grok eager bootstrap so the
* Cursor runtime is loaded before agent sessions are created.
*/
try {
const installStatus = await ensureBundledCursorRuntimePluginInstalled(pluginStore, pluginLoader);
if (installStatus === "installed") {
console.log("[plugins] Installed bundled Cursor CLI runtime plugin");
} else if (installStatus === "missing-bundle") {
console.warn("[plugins] Bundled Cursor CLI runtime plugin was not found in this build");
}
} catch (err) {
console.warn(`[plugins] Failed to auto-install bundled Cursor CLI runtime plugin: ${err instanceof Error ? err.message : err}`);
}
// Auto-load all enabled plugins so runtime UI (NewAgentDialog, AgentDetailView)
// can discover installed runtimes like Hermes and OpenClaw.
try {

View File

@@ -140,7 +140,7 @@ import {
} from "./llama-cpp-extension.js";
import { getCachedUpdateStatus, isUpdateCheckEnabled } from "../update-cache.js";
import { resolveSelfExtension } from "./self-extension.js";
import { ensureBundledDependencyGraphPluginInstalled, ensureBundledGrokRuntimePluginInstalled, ensureBundledPluginInstalled, isBundledPluginId } from "../plugins/bundled-plugin-install.js";
import { ensureBundledCursorRuntimePluginInstalled, ensureBundledDependencyGraphPluginInstalled, ensureBundledGrokRuntimePluginInstalled, ensureBundledPluginInstalled, isBundledPluginId } from "../plugins/bundled-plugin-install.js";
import { registerCustomProviders, reregisterCustomProviders } from "./custom-provider-registry.js";
import { handleOpencodeGoApiKeySaved, syncStartupModels } from "./startup-model-sync.js";
import { DashboardTUI, DashboardLogSink, isTTYAvailable, type SystemInfo, type GitStatus, type GitCommit, type GitCommitDetail, type GitBranch, type GitWorktree, type FileEntry, type FileReadResult, type TaskStep as TUITaskStep, type TaskLogEntry as TUITaskLogEntry, type TaskDetailData, type TaskEvent } from "./dashboard-tui/index.js";
@@ -1572,6 +1572,27 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?:
);
}
/*
* FNXC:CursorCli 2026-08-16-04:05:
* FN-9093: the Cursor provider card's Enable action only flips `useCursorCli` in settings and never
* registers fusion-plugin-cursor-runtime, so `getRuntimeById("cursor")` missed and every cursor-cli
* selection hit the fail-fast "install and enable the Cursor runtime plugin" error after enabling.
* Mirror the FN-7761 Grok eager bootstrap so the Cursor runtime is loadable before chat sends.
*/
try {
const installStatus = await ensureBundledCursorRuntimePluginInstalled(pluginStore, pluginLoader);
if (installStatus === "installed") {
logSink.log("Installed bundled Cursor CLI runtime plugin", "plugins");
} else if (installStatus === "missing-bundle") {
logSink.log("Bundled Cursor CLI runtime plugin was not found in this build", "plugins");
}
} catch (err) {
logSink.log(
`Failed to auto-install bundled Cursor CLI runtime plugin: ${err instanceof Error ? err.message : err}`,
"plugins",
);
}
try {
const { loaded, errors } = await pluginLoader.loadAllPlugins();
logSink.log(`Loaded ${loaded} plugins (${errors} errors)`, "plugins");

View File

@@ -80,7 +80,7 @@ import {
import { resolveSelfExtension } from "./self-extension.js";
import { registerCustomProviders, reregisterCustomProviders } from "./custom-provider-registry.js";
import { handleOpencodeGoApiKeySaved, syncStartupModels } from "./startup-model-sync.js";
import { ensureBundledDependencyGraphPluginInstalled, ensureBundledGrokRuntimePluginInstalled, ensureBundledPluginInstalled, isBundledPluginId } from "../plugins/bundled-plugin-install.js";
import { ensureBundledCursorRuntimePluginInstalled, ensureBundledDependencyGraphPluginInstalled, ensureBundledGrokRuntimePluginInstalled, ensureBundledPluginInstalled, isBundledPluginId } from "../plugins/bundled-plugin-install.js";
import { ensureCwdProjectRegistered } from "./ensure-project-registered.js";
import { phaseTime } from "../startup-phase.js";
@@ -657,6 +657,24 @@ export async function runServe(
console.warn(`[plugins] Failed to auto-install bundled Grok CLI runtime plugin: ${err instanceof Error ? err.message : err}`);
}
/*
* FNXC:CursorCli 2026-08-16-04:05:
* FN-9093: `cursor-cli` is runtime-routed with a fail-fast missing-runtime error, but the provider card's
* Enable action only flips `useCursorCli` in settings — nothing registered fusion-plugin-cursor-runtime,
* so every Cursor selection failed with "install and enable the Cursor runtime plugin" even after enabling.
* Mirror the FN-7761 Grok eager bootstrap so the Cursor runtime is discoverable before any session lane starts.
*/
try {
const installStatus = await ensureBundledCursorRuntimePluginInstalled(pluginStore, pluginLoader);
if (installStatus === "installed") {
console.log("[plugins] Installed bundled Cursor CLI runtime plugin");
} else if (installStatus === "missing-bundle") {
console.warn("[plugins] Bundled Cursor CLI runtime plugin was not found in this build");
}
} catch (err) {
console.warn(`[plugins] Failed to auto-install bundled Cursor CLI runtime plugin: ${err instanceof Error ? err.message : err}`);
}
// Lazy-install hook for bundled runtime plugins (Hermes/OpenClaw/Paperclip/Grok).
const ensureBundledPluginInstalledCallback = async (pluginId: string): Promise<boolean> => {
if (!isBundledPluginId(pluginId)) {