165 lines · 6.0 KB · TypeScript
RawDownload
/** * CursorDriver — `ProviderDriver` for the Cursor Agent SDK runtime. * * Provider status, model discovery, orchestration, and text generation use the * official Cursor SDK and require CURSOR_API_KEY in the provider instance * environment. * * @module provider/Drivers/CursorDriver */import { CursorSettings, ProviderDriverKind } from "@t3tools/contracts";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Path from "effect/Path";import * as Schema from "effect/Schema"; import * as BackgroundPolicy from "../../background/BackgroundPolicy.ts";import { ServerConfig } from "../../config.ts";import { ServerSettingsService } from "../../serverSettings.ts";import { makeCursorTextGeneration } from "../../textGeneration/CursorTextGeneration.ts";import {  CursorAdapterV2Driver,  type CursorAdapterV2DriverEnv,} from "../../orchestration-v2/Adapters/CursorAdapterV2.ts";import { ProviderDriverError } from "../Errors.ts";import {  buildInitialCursorProviderSnapshot,  checkCursorProviderStatus,} from "../Layers/CursorProvider.ts";import { CursorSdkCatalogLive } from "../Layers/CursorSdkCatalog.ts";import { makeManagedServerProvider } from "../makeManagedServerProvider.ts";import {  defaultProviderContinuationIdentity,  type ProviderDriver,  type ProviderInstance,} from "../ProviderDriver.ts";import { withInstanceIdentity } from "./instanceIdentity.ts";import { mergeProviderInstanceEnvironment } from "../ProviderInstanceEnvironment.ts";import { makeManualOnlyProviderMaintenanceCapabilities } from "../providerMaintenance.ts";import {  haveProviderSnapshotSettingsChanged,  makeProviderSnapshotSettingsSource,  type ProviderSnapshotSettings,} from "../providerUpdateSettings.ts";import { probeCursorSkills } from "./CursorSkills.ts";const decodeCursorSettings = Schema.decodeSync(CursorSettings); const DRIVER_KIND = ProviderDriverKind.make("cursor");const MAINTENANCE_CAPABILITIES = makeManualOnlyProviderMaintenanceCapabilities({  provider: DRIVER_KIND,  packageName: null,}); export type CursorDriverEnv =  | CursorAdapterV2DriverEnv  | FileSystem.FileSystem  | Path.Path  | BackgroundPolicy.BackgroundPolicy  | ServerConfig  | ServerSettingsService; export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {  driverKind: DRIVER_KIND,  metadata: {    displayName: "Cursor",    supportsMultipleInstances: true,  },  configSchema: CursorSettings,  defaultConfig: (): CursorSettings => decodeCursorSettings({}),  create: ({ instanceId, displayName, accentColor, environment, enabled, config }) =>    Effect.gen(function* () {      const serverSettings = yield* ServerSettingsService;      const fileSystem = yield* FileSystem.FileSystem;      const path = yield* Path.Path;      const processEnv = mergeProviderInstanceEnvironment(environment);      const continuationIdentity = defaultProviderContinuationIdentity({        driverKind: DRIVER_KIND,        instanceId,      });      const stampIdentity = withInstanceIdentity({        instanceId,        driverKind: DRIVER_KIND,        displayName,        accentColor,        continuationGroupKey: continuationIdentity.continuationKey,      });      const effectiveConfig = { ...config, enabled } satisfies CursorSettings;       const orchestrationAdapter = yield* CursorAdapterV2Driver.create({        instanceId,        displayName,        accentColor,        environment,        enabled,        config,      }).pipe(        Effect.mapError(          (cause) =>            new ProviderDriverError({              driver: DRIVER_KIND,              instanceId,              detail: "Failed to build Cursor orchestration adapter.",              cause,            }),        ),      );      const textGeneration = yield* makeCursorTextGeneration(effectiveConfig, processEnv);       const checkProvider = checkCursorProviderStatus(effectiveConfig, processEnv).pipe(        Effect.map(stampIdentity),        Effect.provide(CursorSdkCatalogLive),      );       const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);      const snapshot = yield* makeManagedServerProvider<ProviderSnapshotSettings<CursorSettings>>({        resolveMaintenance: () => Effect.succeed(MAINTENANCE_CAPABILITIES),        getSettings: snapshotSettings.getSettings,        streamSettings: snapshotSettings.streamSettings,        haveSettingsChanged: haveProviderSnapshotSettingsChanged,        initialSnapshot: (settings) =>          buildInitialCursorProviderSnapshot(settings.provider).pipe(Effect.map(stampIdentity)),        checkProvider,      }).pipe(        Effect.mapError(          (cause) =>            new ProviderDriverError({              driver: DRIVER_KIND,              instanceId,              detail: `Failed to build Cursor snapshot: ${cause.message ?? String(cause)}`,              cause,            }),        ),      );       return {        instanceId,        driverKind: DRIVER_KIND,        continuationIdentity,        displayName,        accentColor,        enabled,        snapshot,        snapshotForCwd: (cwd) =>          !effectiveConfig.enabled            ? snapshot.getSnapshot            : Effect.all([                snapshot.getSnapshot,                probeCursorSkills(cwd, processEnv).pipe(                  Effect.provideService(FileSystem.FileSystem, fileSystem),                  Effect.provideService(Path.Path, path),                  Effect.mapError(                    (cause) =>                      new ProviderDriverError({                        driver: DRIVER_KIND,                        instanceId,                        detail: `Failed to discover Cursor skills for '${cwd}'`,                        cause,                      }),                  ),                ),              ]).pipe(Effect.map(([machineSnapshot, skills]) => ({ ...machineSnapshot, skills }))),        orchestrationAdapter,        textGeneration,      } satisfies ProviderInstance;    }),};