From 0ec3c76faf31353c0fa920ab05692ca419f3a4b8 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sat, 15 Aug 2026 21:07:02 -0700 Subject: [PATCH] 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 --- .../fn-9093-cursor-runtime-eager-install.md | 7 ++++++ .../__tests__/grok-runtime-bootstrap.test.ts | 23 +++++++++++++++++++ packages/cli/src/commands/daemon.ts | 20 +++++++++++++++- packages/cli/src/commands/dashboard.ts | 23 ++++++++++++++++++- packages/cli/src/commands/serve.ts | 20 +++++++++++++++- 5 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 .changeset/fn-9093-cursor-runtime-eager-install.md diff --git a/.changeset/fn-9093-cursor-runtime-eager-install.md b/.changeset/fn-9093-cursor-runtime-eager-install.md new file mode 100644 index 0000000000..259f263a8c --- /dev/null +++ b/.changeset/fn-9093-cursor-runtime-eager-install.md @@ -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. diff --git a/packages/cli/src/commands/__tests__/grok-runtime-bootstrap.test.ts b/packages/cli/src/commands/__tests__/grok-runtime-bootstrap.test.ts index 83d7ef33ee..f28a7fe32b 100644 --- a/packages/cli/src/commands/__tests__/grok-runtime-bootstrap.test.ts +++ b/packages/cli/src/commands/__tests__/grok-runtime-bootstrap.test.ts @@ -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). diff --git a/packages/cli/src/commands/daemon.ts b/packages/cli/src/commands/daemon.ts index c633b67e69..e5ec97419d 100644 --- a/packages/cli/src/commands/daemon.ts +++ b/packages/cli/src/commands/daemon.ts @@ -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 { diff --git a/packages/cli/src/commands/dashboard.ts b/packages/cli/src/commands/dashboard.ts index bb2216195f..01f9fdcdd4 100644 --- a/packages/cli/src/commands/dashboard.ts +++ b/packages/cli/src/commands/dashboard.ts @@ -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"); diff --git a/packages/cli/src/commands/serve.ts b/packages/cli/src/commands/serve.ts index 859c22e20b..d76ae8dbdb 100644 --- a/packages/cli/src/commands/serve.ts +++ b/packages/cli/src/commands/serve.ts @@ -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 => { if (!isBundledPluginId(pluginId)) {