import { officialAcpRegistryIconUrlForAgentId, ProviderDriverKind, resolveOfficialAcpRegistryIconUrl, TextGenerationError, type AcpRegistryOperationError, type ProviderInstanceId, type ServerProvider, type ServerProviderModel, } from "@t3tools/contracts"; import { AcpRegistrySettings } from "../settings.ts"; import * as HostProcess from "@t3tools/shared/HostProcess"; import { createModelCapabilities } from "@t3tools/shared/model"; import * as Clock from "effect/Clock"; import * as Digest from "effect/crypto/Digest"; import * as SecureRandom from "effect/crypto/SecureRandom"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import * as Ref from "effect/Ref"; import * as Result from "effect/Result"; import * as Schema from "effect/Schema"; import * as Semaphore from "effect/Semaphore"; import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"; import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost"; import { AcpRegistryAdapterV2Driver, type AcpRegistryAdapterV2DriverEnv } from "./adapter.ts"; import type { ProviderTextGeneration } from "@t3tools/provider-core/server/textGeneration"; import { ProviderDriverError } from "@t3tools/provider-core/server/errors"; import { makeManagedServerProvider } from "@t3tools/provider-core/server/managedProvider"; import { mergeProviderInstanceEnvironment } from "@t3tools/provider-core/server/instanceEnvironment"; import { defaultProviderContinuationIdentity, type ProviderDriver, type ProviderInstance, type ProviderWorkspaceSnapshot, } from "@t3tools/provider-core/server/driver"; import { providerModelsFromSettings, providerProbeEnvironment, } from "@t3tools/provider-core/server/snapshotProbe"; import { makeManualOnlyProviderMaintenanceCapabilities } from "@t3tools/provider-core/server/maintenanceResolver"; import { haveProviderSnapshotSettingsChanged, makeProviderSnapshotSettingsSource, type ProviderSnapshotSettings, } from "@t3tools/provider-core/server/snapshotSettings"; import { type AcpRegistryAvailableCommands, type AcpRegistryConfigurationProbe, type AcpRegistryConfigurationProbeResult, type AcpRegistryLiveConfiguration, deleteAcpRegistrySession, disableAcpRegistryProvider, listAcpRegistrySessions, listAcpRegistryProviders, logoutAcpRegistry, probeAcpRegistryConfiguration, setAcpRegistryProvider, } from "./probe.ts"; import * as AcpRegistrySupport from "./AcpRegistrySupport.ts"; import * as AcpRegistryRuntimeCoordinator from "./AcpRegistryRuntimeCoordinator.ts"; import * as AcpRegistryAuth from "./auth.ts"; import * as AcpRegistryAuthenticationState from "./authenticationState.ts"; const DRIVER_KIND = ProviderDriverKind.make("acpRegistry"); const decodeSettings = Schema.decodeSync(AcpRegistrySettings); // Cache only successful authenticated probes so sign-in changes remain visible. const PROBE_SUCCESS_TTL_MS = 15 * 60 * 1_000; const EMPTY_CAPABILITIES = createModelCapabilities({ optionDescriptors: [] }); const MAINTENANCE = makeManualOnlyProviderMaintenanceCapabilities({ provider: DRIVER_KIND, packageName: null, }); const makeUnsupportedTextGeneration = (): ProviderTextGeneration => { const unsupported = (operation: string) => Effect.fail( new TextGenerationError({ operation, detail: "ACP Registry instances do not provide application text generation.", }), ); return { generateCommitMessage: () => unsupported("generateCommitMessage"), generatePrContent: () => unsupported("generatePrContent"), generateBranchName: () => unsupported("generateBranchName"), generateThreadTitle: () => unsupported("generateThreadTitle"), generateReviewGuide: () => unsupported("generateReviewGuide"), generateTranscriptionPostProcessing: () => unsupported("generateTranscriptionPostProcessing"), }; }; function modelsFromDiscovery( discovery: | Pick | undefined, customModels: ReadonlyArray, ): ReadonlyArray { const discovered = discovery?.models ?? []; const capabilities = discovery === undefined || discovery.configOptions.length === 0 ? EMPTY_CAPABILITIES : createModelCapabilities({ optionDescriptors: discovery.configOptions }); const builtInModels: ReadonlyArray = discovered.length === 0 ? [ { slug: "default", name: "Default", isCustom: false, isDefault: true, capabilities, }, ] : discovered.map((model) => ({ slug: model.id, name: model.name, isCustom: false, ...(model.id === discovery?.currentModelId ? { isDefault: true } : {}), capabilities, })); return providerModelsFromSettings(builtInModels, customModels, capabilities); } function acpRegistrySnapshotReadiness( inspection: | AcpRegistrySupport.AcpRegistryInspection | { readonly status: "failed"; readonly message: string }, ): Pick { switch (inspection.status) { case "ready": return { installed: true, version: inspection.version, status: "ready" }; case "unconfigured": return { installed: false, version: null, status: "warning", message: "Select an ACP Registry agent or configure a local ACP executable before starting a thread.", }; case "not_found": return { installed: false, version: null, status: "error", message: `ACP Registry does not contain agent '${inspection.agentId}'.`, }; case "unsupported": return { installed: false, version: inspection.version, status: "error", message: `ACP Registry agent '${inspection.agentId}' has no compatible distribution for this environment.`, }; case "missing_runner": return { installed: false, version: inspection.version, status: "error", message: inspection.distribution === "local" ? "Local ACP executable is not available on this environment's PATH." : `ACP executable '${inspection.runner}' is not available on this environment's PATH.`, }; case "unprepared": return { installed: false, version: inspection.version, status: "warning", message: `ACP Registry agent '${inspection.agentId}' has not been prepared on this environment.`, }; case "failed": return { installed: false, version: null, status: "error", message: inspection.message, }; } } interface SnapshotIdentity { readonly instanceId: ProviderInstance["instanceId"]; readonly displayName: string | undefined; readonly accentColor: string | undefined; readonly continuationKey: string; } function baseSnapshot( input: SnapshotIdentity & { readonly settings: AcpRegistrySettings; readonly checkedAt: string; readonly installed: boolean; readonly version: string | null; readonly status: ServerProvider["status"]; readonly auth: ServerProvider["auth"]; readonly documentationUrl?: string; readonly message?: string; readonly probe?: AcpRegistryConfigurationProbeResult; readonly probeError?: AcpRegistryOperationError; }, ): ServerProvider { const iconUrl = input.settings.source === "local" ? null : (resolveOfficialAcpRegistryIconUrl(input.probe?.probe.icon) ?? officialAcpRegistryIconUrlForAgentId(input.settings.agentId)); return { instanceId: input.instanceId, driver: DRIVER_KIND, ...(input.displayName ? { displayName: input.displayName } : {}), ...(input.accentColor ? { accentColor: input.accentColor } : {}), ...(iconUrl ? { iconUrl } : {}), continuation: { groupKey: input.continuationKey }, supportsTextGeneration: false, enabled: input.settings.enabled, installed: input.installed, version: input.version, status: input.settings.enabled ? input.status : "disabled", auth: { ...input.auth, canLogout: input.auth.canLogout ?? false }, checkedAt: input.checkedAt, setup: { canInstall: false, ...(input.documentationUrl ? { documentationUrl: input.documentationUrl } : {}), canAuthenticate: input.installed && (input.probe ? input.probe.probe.authMethods.length > 0 : input.settings.source === "local" ? (input.probeError?.authMethods?.length ?? 0) > 0 : input.settings.agentId.length > 0), }, ...(input.message ? { message: input.message } : {}), models: modelsFromDiscovery(input.probe?.probe, input.settings.customModels), ...(input.probe === undefined ? {} : { nativeSessions: { canList: input.probe.probe.sessionManagement.canList, canLoad: input.probe.probe.sessionManagement.canLoad, canResume: input.probe.probe.sessionManagement.canResume, canDelete: input.probe.probe.sessionManagement.canDelete, }, configurableProviders: input.probe.probe.sessionManagement.canConfigureProviders, }), slashCommands: input.probe?.slashCommands ?? [], skills: input.probe?.skills ?? [], }; } export function applyAcpRegistryAvailableCommands( provider: ServerProvider, commands: Option.Option, ): ServerProvider { return Option.match(commands, { onNone: () => provider, onSome: ({ slashCommands, skills }) => ({ ...provider, slashCommands, skills }), }); } export function applyAcpRegistryLiveConfiguration( provider: ServerProvider, configuration: AcpRegistryLiveConfiguration, customModels: ReadonlyArray, ): ServerProvider { const { message: _staleProbeMessage, ...snapshot } = provider; // session/load may omit models (Kimi returns `{}`); keep the probed list // and apply any live option descriptors to it. const probedModels = provider.models.filter((model) => !model.isCustom); const discovery = configuration.models.length > 0 ? configuration : { ...configuration, models: probedModels.map((model) => ({ id: model.slug, name: model.name, description: null, })), currentModelId: probedModels.find((model) => model.isDefault)?.slug ?? null, }; return { ...snapshot, status: provider.enabled ? "ready" : provider.status, models: configuration.models.length === 0 && configuration.configOptions.length === 0 ? provider.models : modelsFromDiscovery(discovery, customModels), }; } function applyAcpRegistryUrlAuthAction( provider: ServerProvider, action: Option.Option>, ): ServerProvider { const { action: _previousAction, ...auth } = provider.auth; return { ...provider, auth: Option.match(action, { onNone: () => auth, onSome: (nextAction) => ({ ...auth, action: nextAction }), }), }; } const buildInitialAcpRegistrySnapshot = Effect.fn("AcpRegistryDriver.buildInitialSnapshot")( function* (input: SnapshotIdentity & { readonly settings: AcpRegistrySettings }) { const checkedAt = DateTime.formatIso(yield* DateTime.now); return baseSnapshot({ ...input, checkedAt, installed: false, version: null, status: "warning", auth: { status: "unknown" }, message: input.settings.enabled ? "Checking ACP Registry agent readiness..." : "ACP Registry is disabled in T3 Code settings.", }); }, ); export function buildCheckedAcpRegistrySnapshot( input: SnapshotIdentity & { readonly settings: AcpRegistrySettings; readonly checkedAt: string; readonly inspection: | AcpRegistrySupport.AcpRegistryInspection | { readonly status: "failed"; readonly message: string }; readonly probe?: AcpRegistryConfigurationProbeResult; readonly probeError?: AcpRegistryOperationError; }, ): ServerProvider { const readiness = acpRegistrySnapshotReadiness(input.inspection); const probeFailed = input.probeError !== undefined; const advertisedAuthMethod = input.probeError?.reason === "authentication_failed" ? (input.probeError.authMethods?.find( (method) => method.id === input.settings.authMethodId, ) ?? input.probeError.authMethods?.[0]) : undefined; const authenticationMessage = advertisedAuthMethod ? advertisedAuthMethod.type === "terminal" && advertisedAuthMethod.command ? `Sign in in provider settings using "${advertisedAuthMethod.name}". The login terminal runs on this environment.` : advertisedAuthMethod.type === "env_var" && (advertisedAuthMethod.envVarNames?.length ?? 0) > 0 ? `Set ${advertisedAuthMethod.envVarNames!.join(", ")} under this instance's environment variables in provider settings. T3 Code will detect it on the next provider refresh.` : `Sign in in provider settings using "${advertisedAuthMethod.name}".` : undefined; return baseSnapshot({ ...input, ...(input.inspection.status === "ready" && input.inspection.documentationUrl ? { documentationUrl: input.inspection.documentationUrl } : {}), installed: readiness.installed, version: readiness.version, // Failed discovery is a warning: an installed agent may still run real turns. status: probeFailed ? "warning" : readiness.status, auth: input.probe ? { // Discovery sessions and an empty auth-method list do not prove sign-in. status: "unknown", canLogout: input.probe.probe.sessionManagement.canLogout, } : input.probeError?.reason === "authentication_failed" ? { status: "unauthenticated", ...(advertisedAuthMethod ? { type: advertisedAuthMethod.type, label: advertisedAuthMethod.name } : {}), ...(input.probeError.authAction === undefined ? {} : { action: input.probeError.authAction }), } : { status: "unknown" }, ...(input.probeError ? { message: authenticationMessage ?? input.probeError.message } : readiness.message ? { message: readiness.message } : {}), }); } export const checkAcpRegistryProviderStatus = Effect.fn("AcpRegistryDriver.checkProviderStatus")( function* ( input: SnapshotIdentity & { readonly settings: AcpRegistrySettings; readonly cwd: string; readonly environment: NodeJS.ProcessEnv; }, probeConfiguration: AcpRegistryConfigurationProbe, ): Effect.fn.Return { const checkedAt = DateTime.formatIso(yield* DateTime.now); if (!input.settings.enabled) { return yield* buildInitialAcpRegistrySnapshot(input); } const catalog = yield* AcpRegistrySupport.AcpRegistryCatalog; const inspected = yield* Effect.result(catalog.inspect(input.settings, input.environment)); if (Result.isFailure(inspected)) { return buildCheckedAcpRegistrySnapshot({ ...input, checkedAt, inspection: { status: "failed", message: `Could not inspect ACP Registry agent: ${inspected.failure.message}`, }, }); } if (inspected.success.status !== "ready") { return buildCheckedAcpRegistrySnapshot({ ...input, checkedAt, inspection: inspected.success, }); } const probed = yield* Effect.result( probeConfiguration({ instanceId: input.instanceId, settings: input.settings, cwd: input.cwd, environment: providerProbeEnvironment(input.environment), }), ); return Result.isFailure(probed) ? buildCheckedAcpRegistrySnapshot({ ...input, checkedAt, inspection: inspected.success, probeError: probed.failure, }) : buildCheckedAcpRegistrySnapshot({ ...input, checkedAt, inspection: inspected.success, probe: probed.success, }); }, ); export const probeAcpRegistryWorkspaceForCwd = Effect.fn("AcpRegistryDriver.probeWorkspaceForCwd")( function* ( input: { readonly instanceId: ProviderInstanceId; readonly settings: AcpRegistrySettings; readonly cwd: string; readonly environment: NodeJS.ProcessEnv; readonly machineSnapshot: ServerProvider; }, probeConfiguration: AcpRegistryConfigurationProbe, ): Effect.fn.Return { const { machineSnapshot } = input; if (!machineSnapshot.installed) { return { ...machineSnapshot, slashCommandsPending: false }; } const probed = yield* Effect.result( probeConfiguration({ instanceId: input.instanceId, settings: input.settings, cwd: input.cwd, environment: input.environment, }), ); if (Result.isFailure(probed)) return { ...machineSnapshot, slashCommandsPending: true }; const { slashCommands, skills } = probed.success; // Agents may advertise only after the probe's grace period; keep the machine // snapshot's commands, which carry what live sessions have advertised. if (slashCommands.length === 0 && skills.length === 0) return machineSnapshot; return { ...machineSnapshot, slashCommands, skills, slashCommandsPending: false }; }, ); export const checkAcpRegistryProviderReadiness = Effect.fn( "AcpRegistryDriver.checkProviderReadiness", )(function* ( input: SnapshotIdentity & { readonly settings: AcpRegistrySettings; readonly environment: NodeJS.ProcessEnv; }, ): Effect.fn.Return { const checkedAt = DateTime.formatIso(yield* DateTime.now); if (!input.settings.enabled) { return yield* buildInitialAcpRegistrySnapshot(input); } const catalog = yield* AcpRegistrySupport.AcpRegistryCatalog; const inspected = yield* Effect.result(catalog.inspect(input.settings, input.environment)); const snapshot = buildCheckedAcpRegistrySnapshot({ ...input, checkedAt, inspection: Result.isFailure(inspected) ? { status: "failed", message: `Could not inspect ACP Registry agent: ${inspected.failure.message}`, } : inspected.success, }); return inspected._tag === "Success" && inspected.success.status === "ready" ? { ...snapshot, message: "Checking ACP authentication, models, and commands in the background...", } : snapshot; }); export type AcpRegistryDriverEnv = | AcpRegistryAdapterV2DriverEnv | Digest.Digest | ProviderHost.ProviderHost; export const AcpRegistryDriver: ProviderDriver = { driverKind: DRIVER_KIND, metadata: { displayName: "ACP Registry", supportsMultipleInstances: true, hasDefaultInstance: false, }, configSchema: AcpRegistrySettings, defaultConfig: () => decodeSettings({}), create: Effect.fn("AcpRegistryDriver.create")(function* ({ instanceId, displayName, accentColor, environment, enabled, config, }) { const catalog = yield* AcpRegistrySupport.AcpRegistryCatalog; const runtimeCoordinator = yield* Effect.serviceOption( AcpRegistryRuntimeCoordinator.AcpRegistryRuntimeCoordinator, ); if (Option.isSome(runtimeCoordinator)) { yield* runtimeCoordinator.value.clearAvailableCommands(instanceId); yield* runtimeCoordinator.value.clearLiveConfiguration(instanceId); yield* Effect.addFinalizer(() => runtimeCoordinator.value .clearAvailableCommands(instanceId) .pipe(Effect.andThen(runtimeCoordinator.value.clearLiveConfiguration(instanceId))), ); } const random = yield* SecureRandom.SecureRandom; const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const hostEnvironment = yield* HostProcess.Environment; const host = yield* ProviderHost.ProviderHost; const continuationIdentity = defaultProviderContinuationIdentity({ driverKind: DRIVER_KIND, instanceId, }); const identity = { instanceId, displayName, accentColor, continuationKey: continuationIdentity.continuationKey, }; const effectiveConfig = { ...config, enabled } satisfies AcpRegistrySettings; const processEnvironment = yield* mergeProviderInstanceEnvironment( environment, hostEnvironment, ); const orchestrationAdapter = yield* AcpRegistryAdapterV2Driver.create({ instanceId, displayName, accentColor, environment, enabled, config, }).pipe( Effect.mapError( (cause) => new ProviderDriverError({ driver: DRIVER_KIND, instanceId, detail: "Failed to build ACP Registry orchestration adapter.", cause, }), ), ); const readinessInput = { ...identity, settings: effectiveConfig, environment: processEnvironment, }; const confirmedAuthentication = yield* AcpRegistryAuthenticationState.makeAcpRegistryAuthenticationState({ cacheDir: host.paths.providerStatusCacheDir, instanceId, settings: effectiveConfig, environment, processEnvironment, }); const withLiveRuntimeState = Effect.fn("AcpRegistryDriver.withLiveRuntimeState")(function* ( input: ServerProvider, ) { if (input.auth.status === "unauthenticated") yield* confirmedAuthentication.set(false); const provider = input.enabled && input.installed && input.auth.status === "unknown" && (yield* confirmedAuthentication.get) ? { ...input, auth: { ...input.auth, status: "authenticated" as const } } : input; return yield* Option.isNone(runtimeCoordinator) ? Effect.succeed(provider) : Effect.all({ commands: runtimeCoordinator.value.getAvailableCommands(instanceId), configuration: runtimeCoordinator.value.getLiveConfiguration(instanceId), authAction: runtimeCoordinator.value.getUrlAuthAction(instanceId), }).pipe( Effect.map(({ commands, configuration, authAction }) => { const withCommands = applyAcpRegistryAvailableCommands(provider, commands); const withConfiguration = Option.match(configuration, { onNone: () => withCommands, onSome: (liveConfiguration) => applyAcpRegistryLiveConfiguration( withCommands, liveConfiguration, effectiveConfig.customModels, ), }); return applyAcpRegistryUrlAuthAction(withConfiguration, authAction); }), ); }); const checkProvider = checkAcpRegistryProviderReadiness(readinessInput).pipe( Effect.provideService(AcpRegistrySupport.AcpRegistryCatalog, catalog), Effect.flatMap(withLiveRuntimeState), ); const enrichProvider = checkAcpRegistryProviderStatus( { ...readinessInput, cwd: host.paths.cwd, }, probeAcpRegistryConfiguration, ).pipe( Effect.provideService(AcpRegistrySupport.AcpRegistryCatalog, catalog), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(SecureRandom.SecureRandom, random), ); const enrichmentCache = yield* Ref.make<{ readonly generation: number; readonly entry: { readonly provider: ServerProvider; readonly expiresAt: number; } | null; }>({ generation: 0, entry: null }); const liveSnapshotSemaphore = yield* Semaphore.make(1); // Each probe spawns the agent; ProviderRegistry caches the result per cwd. const workspaceProbePermits = yield* Semaphore.make(2); const snapshotForCwd = Effect.fn("AcpRegistryDriver.snapshotForCwd")(function* (cwd: string) { const machineSnapshot = yield* snapshot.getSnapshot; if (!effectiveConfig.enabled) return machineSnapshot; return yield* workspaceProbePermits.withPermit( probeAcpRegistryWorkspaceForCwd( { instanceId, settings: effectiveConfig, cwd, environment: processEnvironment, machineSnapshot, }, probeAcpRegistryConfiguration, ).pipe( Effect.provideService(AcpRegistrySupport.AcpRegistryCatalog, catalog), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(SecureRandom.SecureRandom, random), ), ); }); const invalidateEnrichmentCache = Ref.update(enrichmentCache, (current) => ({ generation: current.generation + 1, entry: null, })); const enrichProviderCached = Effect.fn("AcpRegistryDriver.enrichProviderCached")(function* ( baseSnapshot: ServerProvider, ) { const now = yield* Clock.currentTimeMillis; const cacheState = yield* Ref.get(enrichmentCache); const cached = cacheState.entry; if ( cached !== null && cached.expiresAt > now && cached.provider.version === baseSnapshot.version ) { return { provider: { ...cached.provider, checkedAt: baseSnapshot.checkedAt }, generation: cacheState.generation, }; } const enriched = yield* enrichProvider; if (enriched.status === "ready") { yield* Ref.update(enrichmentCache, (current) => current.generation === cacheState.generation ? { ...current, entry: { provider: enriched, expiresAt: now + PROBE_SUCCESS_TTL_MS, }, } : current, ); } return { provider: enriched, generation: cacheState.generation }; }); const snapshotSettings = yield* makeProviderSnapshotSettingsSource(effectiveConfig); const snapshot = yield* makeManagedServerProvider< ProviderSnapshotSettings >({ resolveMaintenance: () => Effect.succeed(MAINTENANCE), getSettings: snapshotSettings.getSettings, streamSettings: snapshotSettings.streamSettings, haveSettingsChanged: haveProviderSnapshotSettingsChanged, initialSnapshot: () => checkProvider, checkProvider, enrichSnapshot: Effect.fn("enrichSnapshot")(function ({ snapshot, getSnapshot, publishSnapshot, }) { if (!snapshot.installed) return Effect.void; const publishEnrichment = ( Option.isSome(runtimeCoordinator) ? runtimeCoordinator.value.runBackgroundProbe( effectiveConfig.source === "local" ? `local:${instanceId}` : effectiveConfig.agentId, enrichProviderCached(snapshot), ) : enrichProviderCached(snapshot).pipe(Effect.asSome) ).pipe( Effect.flatMap( Option.match({ onNone: () => Effect.void, onSome: ({ provider, generation }) => liveSnapshotSemaphore.withPermit( Ref.get(enrichmentCache).pipe( Effect.flatMap((current) => current.generation === generation ? withLiveRuntimeState(provider).pipe(Effect.flatMap(publishSnapshot)) : Effect.void, ), ), ), }), ), ); if (Option.isNone(runtimeCoordinator)) return publishEnrichment; const publishLiveCommands = runtimeCoordinator.value.watchAvailableCommands( instanceId, ({ slashCommands, skills }) => liveSnapshotSemaphore.withPermit( getSnapshot.pipe( Effect.flatMap((current) => publishSnapshot({ ...current, slashCommands, skills, }), ), ), ), ); const publishLiveConfiguration = runtimeCoordinator.value.watchLiveConfiguration( instanceId, (configuration) => liveSnapshotSemaphore.withPermit( getSnapshot.pipe( Effect.flatMap((current) => publishSnapshot( applyAcpRegistryLiveConfiguration( current, configuration, effectiveConfig.customModels, ), ), ), ), ), ); const publishUrlAuthAction = runtimeCoordinator.value.watchUrlAuthAction( instanceId, (action) => liveSnapshotSemaphore.withPermit( getSnapshot.pipe( Effect.flatMap((current) => publishSnapshot( applyAcpRegistryUrlAuthAction(current, Option.fromNullishOr(action)), ), ), ), ), ); return Effect.all( [publishEnrichment, publishLiveCommands, publishLiveConfiguration, publishUrlAuthAction], { concurrency: "unbounded", discard: true, }, ); }), }).pipe( Effect.mapError( (cause) => new ProviderDriverError({ driver: DRIVER_KIND, instanceId, detail: "Failed to build the ACP Registry provider snapshot.", cause, }), ), ); const provideAcpManagementServices = ( effect: Effect.Effect< A, E, | AcpRegistrySupport.AcpRegistryCatalog | ChildProcessSpawner.ChildProcessSpawner | SecureRandom.SecureRandom >, ): Effect.Effect => { const provided = effect.pipe( Effect.provideService(AcpRegistrySupport.AcpRegistryCatalog, catalog), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(SecureRandom.SecureRandom, random), ); return Option.isSome(runtimeCoordinator) ? provided.pipe( Effect.provideService( AcpRegistryRuntimeCoordinator.AcpRegistryRuntimeCoordinator, runtimeCoordinator.value, ), ) : provided; }; const clearLiveState = Option.isSome(runtimeCoordinator) ? runtimeCoordinator.value .clearLiveConfiguration(instanceId) .pipe(Effect.andThen(runtimeCoordinator.value.clearAvailableCommands(instanceId))) : Effect.void; const controller = yield* AcpRegistryAuth.makeAcpRegistryAuth({ instanceId, settings: effectiveConfig, cwd: host.paths.cwd, environment: processEnvironment, onChanged: (authenticated) => confirmedAuthentication .set(authenticated) .pipe( Effect.andThen(authenticated ? Effect.void : clearLiveState), Effect.andThen(liveSnapshotSemaphore.withPermit(invalidateEnrichmentCache)), Effect.andThen(snapshot.refresh), Effect.asVoid, ), }).pipe( Effect.provideService(AcpRegistrySupport.AcpRegistryCatalog, catalog), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(SecureRandom.SecureRandom, random), ); const auth = { ...controller, invalidate: (controller.invalidate ?? Effect.void).pipe( Effect.andThen(confirmedAuthentication.set(false)), Effect.andThen(clearLiveState), Effect.andThen(liveSnapshotSemaphore.withPermit(invalidateEnrichmentCache)), Effect.andThen(snapshot.refresh), Effect.asVoid, ), }; return { instanceId, driverKind: DRIVER_KIND, continuationIdentity, displayName, accentColor, enabled, auth, snapshot: { ...snapshot, refresh: snapshot.refresh.pipe(Effect.tap(() => controller.refreshMethods ?? Effect.void)), }, snapshotForCwd, orchestrationAdapter, textGeneration: makeUnsupportedTextGeneration(), acpSessionManagement: { listSessions: ({ cwd, cursor }) => provideAcpManagementServices( listAcpRegistrySessions({ instanceId, settings: effectiveConfig, cwd, environment: processEnvironment, ...(cursor === undefined ? {} : { cursor }), }), ), deleteSession: ({ cwd, sessionId }) => provideAcpManagementServices( deleteAcpRegistrySession({ instanceId, settings: effectiveConfig, cwd, environment: processEnvironment, sessionId, }), ), listProviders: (cwd) => provideAcpManagementServices( listAcpRegistryProviders({ instanceId, settings: effectiveConfig, cwd, environment: processEnvironment, }), ), setProvider: ({ cwd, providerId, apiType, baseUrl, headers }) => provideAcpManagementServices( setAcpRegistryProvider({ instanceId, settings: effectiveConfig, cwd, environment: processEnvironment, providerId, apiType, baseUrl, ...(headers === undefined ? {} : { headers }), }), ).pipe(Effect.tap(() => liveSnapshotSemaphore.withPermit(invalidateEnrichmentCache))), disableProvider: ({ cwd, providerId }) => provideAcpManagementServices( disableAcpRegistryProvider({ instanceId, settings: effectiveConfig, cwd, environment: processEnvironment, providerId, }), ).pipe(Effect.tap(() => liveSnapshotSemaphore.withPermit(invalidateEnrichmentCache))), logout: (cwd) => { const logout = logoutAcpRegistry({ instanceId, settings: effectiveConfig, cwd, environment: processEnvironment, }).pipe( Effect.provideService(AcpRegistrySupport.AcpRegistryCatalog, catalog), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(SecureRandom.SecureRandom, random), Effect.tap(() => confirmedAuthentication.set(false)), Effect.tap(() => liveSnapshotSemaphore.withPermit( invalidateEnrichmentCache.pipe( Effect.andThen( Option.isSome(runtimeCoordinator) ? Effect.all( [ runtimeCoordinator.value.clearAvailableCommands(instanceId), runtimeCoordinator.value.clearLiveConfiguration(instanceId), ], { concurrency: "unbounded", discard: true }, ) : Effect.void, ), ), ), ), ); return Option.isSome(runtimeCoordinator) ? logout.pipe( Effect.provideService( AcpRegistryRuntimeCoordinator.AcpRegistryRuntimeCoordinator, runtimeCoordinator.value, ), ) : logout; }, }, } satisfies ProviderInstance; }), };