import { Schema, Struct } from "effect"; import { IsoDateTime, TrimmedNonEmptyString } from "./baseSchemas"; import { KeybindingRule, ResolvedKeybindingsConfig } from "./keybindings"; import { EditorId } from "./editor"; import { DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER } from "./model"; import { ModelSelection, ProviderKind } from "./orchestration"; // ── Server Settings (server-authoritative) ─────────────────────────── export const ThreadEnvMode = Schema.Literals(["local", "worktree"]); export type ThreadEnvMode = typeof ThreadEnvMode.Type; export const CodexSettings = Schema.Struct({ binaryPath: Schema.String.pipe(Schema.withDecodingDefault(() => "")), homePath: Schema.String.pipe(Schema.withDecodingDefault(() => "")), }); export type CodexSettings = typeof CodexSettings.Type; export const ClaudeSettings = Schema.Struct({ binaryPath: Schema.String.pipe(Schema.withDecodingDefault(() => "")), }); export type ClaudeSettings = typeof ClaudeSettings.Type; export const ServerSettings = Schema.Struct({ codex: CodexSettings.pipe(Schema.withDecodingDefault(() => ({}))), claude: ClaudeSettings.pipe(Schema.withDecodingDefault(() => ({}))), enableAssistantStreaming: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)), defaultThreadEnvMode: ThreadEnvMode.pipe( Schema.withDecodingDefault(() => "local" as const satisfies ThreadEnvMode), ), customCodexModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])), customClaudeModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])), textGenerationModelSelection: ModelSelection.pipe( Schema.withDecodingDefault(() => ({ provider: "codex" as const, model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER.codex, })), ), }); export type ServerSettings = typeof ServerSettings.Type; export const DEFAULT_SERVER_SETTINGS: ServerSettings = Schema.decodeUnknownSync(ServerSettings)({}); export const ServerSettingsPatch = ServerSettings.mapFields(Struct.map(Schema.optionalKey)); export type ServerSettingsPatch = typeof ServerSettingsPatch.Type; const KeybindingsMalformedConfigIssue = Schema.Struct({ kind: Schema.Literal("keybindings.malformed-config"), message: TrimmedNonEmptyString, }); const KeybindingsInvalidEntryIssue = Schema.Struct({ kind: Schema.Literal("keybindings.invalid-entry"), message: TrimmedNonEmptyString, index: Schema.Number, }); export const ServerConfigIssue = Schema.Union([ KeybindingsMalformedConfigIssue, KeybindingsInvalidEntryIssue, ]); export type ServerConfigIssue = typeof ServerConfigIssue.Type; const ServerConfigIssues = Schema.Array(ServerConfigIssue); export const ServerProviderStatusState = Schema.Literals(["ready", "warning", "error"]); export type ServerProviderStatusState = typeof ServerProviderStatusState.Type; export const ServerProviderAuthStatus = Schema.Literals([ "authenticated", "unauthenticated", "unknown", ]); export type ServerProviderAuthStatus = typeof ServerProviderAuthStatus.Type; export const ServerProviderStatus = Schema.Struct({ provider: ProviderKind, status: ServerProviderStatusState, available: Schema.Boolean, authStatus: ServerProviderAuthStatus, checkedAt: IsoDateTime, message: Schema.optional(TrimmedNonEmptyString), }); export type ServerProviderStatus = typeof ServerProviderStatus.Type; const ServerProviderStatuses = Schema.Array(ServerProviderStatus); export const ServerConfig = Schema.Struct({ cwd: TrimmedNonEmptyString, keybindingsConfigPath: TrimmedNonEmptyString, keybindings: ResolvedKeybindingsConfig, issues: ServerConfigIssues, providers: ServerProviderStatuses, availableEditors: Schema.Array(EditorId), settings: ServerSettings, }); export type ServerConfig = typeof ServerConfig.Type; export const ServerUpsertKeybindingInput = KeybindingRule; export type ServerUpsertKeybindingInput = typeof ServerUpsertKeybindingInput.Type; export const ServerUpsertKeybindingResult = Schema.Struct({ keybindings: ResolvedKeybindingsConfig, issues: ServerConfigIssues, }); export type ServerUpsertKeybindingResult = typeof ServerUpsertKeybindingResult.Type; export const ServerConfigUpdatedPayload = Schema.Struct({ issues: ServerConfigIssues, providers: ServerProviderStatuses, settings: Schema.optional(ServerSettings), }); export type ServerConfigUpdatedPayload = typeof ServerConfigUpdatedPayload.Type;