import { Schema } from "effect";import { IsoDateTime, TrimmedNonEmptyString } from "./baseSchemas";import { KeybindingRule, ResolvedKeybindingsConfig } from "./keybindings";import { EditorId } from "./editor";import { ClaudeModelOptions, CodexModelOptions, 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(() => "")), customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])),});export type CodexSettings = typeof CodexSettings.Type; export const ClaudeSettings = Schema.Struct({ binaryPath: Schema.String.pipe(Schema.withDecodingDefault(() => "")), customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])),});export type ClaudeSettings = typeof ClaudeSettings.Type; export const ServerSettings = Schema.Struct({ enableAssistantStreaming: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)), defaultThreadEnvMode: ThreadEnvMode.pipe( Schema.withDecodingDefault(() => "local" as const satisfies ThreadEnvMode), ), textGenerationModelSelection: ModelSelection.pipe( Schema.withDecodingDefault(() => ({ provider: "codex" as const, model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER.codex, })), ), // Provider specific settings providers: Schema.Struct({ codex: CodexSettings.pipe(Schema.withDecodingDefault(() => ({}))), claudeAgent: ClaudeSettings.pipe(Schema.withDecodingDefault(() => ({}))), }).pipe(Schema.withDecodingDefault(() => ({}))),});export type ServerSettings = typeof ServerSettings.Type; export const DEFAULT_SERVER_SETTINGS: ServerSettings = Schema.decodeUnknownSync(ServerSettings)({}); const CodexModelOptionsPatch = Schema.Struct({ reasoningEffort: Schema.optionalKey(CodexModelOptions.fields.reasoningEffort), fastMode: Schema.optionalKey(CodexModelOptions.fields.fastMode),}); const ClaudeModelOptionsPatch = Schema.Struct({ thinking: Schema.optionalKey(ClaudeModelOptions.fields.thinking), effort: Schema.optionalKey(ClaudeModelOptions.fields.effort), fastMode: Schema.optionalKey(ClaudeModelOptions.fields.fastMode),}); const ModelSelectionPatch = Schema.Union([ Schema.Struct({ provider: Schema.optionalKey(Schema.Literal("codex")), model: Schema.optionalKey(TrimmedNonEmptyString), options: Schema.optionalKey(CodexModelOptionsPatch), }), Schema.Struct({ provider: Schema.optionalKey(Schema.Literal("claudeAgent")), model: Schema.optionalKey(TrimmedNonEmptyString), options: Schema.optionalKey(ClaudeModelOptionsPatch), }),]); const CodexSettingsPatch = Schema.Struct({ binaryPath: Schema.optionalKey(Schema.String), homePath: Schema.optionalKey(Schema.String), customModels: Schema.optionalKey(Schema.Array(Schema.String)),}); const ClaudeSettingsPatch = Schema.Struct({ binaryPath: Schema.optionalKey(Schema.String), customModels: Schema.optionalKey(Schema.Array(Schema.String)),}); export const ServerSettingsPatch = Schema.Struct({ enableAssistantStreaming: Schema.optionalKey(Schema.Boolean), defaultThreadEnvMode: Schema.optionalKey(ThreadEnvMode), textGenerationModelSelection: Schema.optionalKey(ModelSelectionPatch), providers: Schema.optionalKey( Schema.Struct({ codex: Schema.optionalKey(CodexSettingsPatch), claudeAgent: Schema.optionalKey(ClaudeSettingsPatch), }), ),});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;
import { Schema } from "effect";
import { IsoDateTime, TrimmedNonEmptyString } from "./baseSchemas";
import { KeybindingRule, ResolvedKeybindingsConfig } from "./keybindings";
import { EditorId } from "./editor";
import {
ClaudeModelOptions,
CodexModelOptions,
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(() => "")),
customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])),
});
export type CodexSettings = typeof CodexSettings.Type;
export const ClaudeSettings = Schema.Struct({
binaryPath: Schema.String.pipe(Schema.withDecodingDefault(() => "")),
customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])),
});
export type ClaudeSettings = typeof ClaudeSettings.Type;
export const ServerSettings = Schema.Struct({
enableAssistantStreaming: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)),
defaultThreadEnvMode: ThreadEnvMode.pipe(
Schema.withDecodingDefault(() => "local" as const satisfies ThreadEnvMode),
),
textGenerationModelSelection: ModelSelection.pipe(
Schema.withDecodingDefault(() => ({
provider: "codex" as const,
model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER.codex,
})),
),
// Provider specific settings
providers: Schema.Struct({
codex: CodexSettings.pipe(Schema.withDecodingDefault(() => ({}))),
claudeAgent: ClaudeSettings.pipe(Schema.withDecodingDefault(() => ({}))),
}).pipe(Schema.withDecodingDefault(() => ({}))),
});
export type ServerSettings = typeof ServerSettings.Type;
export const DEFAULT_SERVER_SETTINGS: ServerSettings = Schema.decodeUnknownSync(ServerSettings)({});
const CodexModelOptionsPatch = Schema.Struct({
reasoningEffort: Schema.optionalKey(CodexModelOptions.fields.reasoningEffort),
fastMode: Schema.optionalKey(CodexModelOptions.fields.fastMode),
});
const ClaudeModelOptionsPatch = Schema.Struct({
thinking: Schema.optionalKey(ClaudeModelOptions.fields.thinking),
effort: Schema.optionalKey(ClaudeModelOptions.fields.effort),
fastMode: Schema.optionalKey(ClaudeModelOptions.fields.fastMode),
});
const ModelSelectionPatch = Schema.Union([
Schema.Struct({
provider: Schema.optionalKey(Schema.Literal("codex")),
model: Schema.optionalKey(TrimmedNonEmptyString),
options: Schema.optionalKey(CodexModelOptionsPatch),
}),
Schema.Struct({
provider: Schema.optionalKey(Schema.Literal("claudeAgent")),
model: Schema.optionalKey(TrimmedNonEmptyString),
options: Schema.optionalKey(ClaudeModelOptionsPatch),
}),
]);
const CodexSettingsPatch = Schema.Struct({
binaryPath: Schema.optionalKey(Schema.String),
homePath: Schema.optionalKey(Schema.String),
customModels: Schema.optionalKey(Schema.Array(Schema.String)),
});
const ClaudeSettingsPatch = Schema.Struct({
binaryPath: Schema.optionalKey(Schema.String),
customModels: Schema.optionalKey(Schema.Array(Schema.String)),
});
export const ServerSettingsPatch = Schema.Struct({
enableAssistantStreaming: Schema.optionalKey(Schema.Boolean),
defaultThreadEnvMode: Schema.optionalKey(ThreadEnvMode),
textGenerationModelSelection: Schema.optionalKey(ModelSelectionPatch),
providers: Schema.optionalKey(
Schema.Struct({
codex: Schema.optionalKey(CodexSettingsPatch),
claudeAgent: Schema.optionalKey(ClaudeSettingsPatch),
}),
),
});
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;