| @@ -3,41 +3,43 @@ import { Option, Schema } from "effect"; · 2 unmodified lines |
| 3 | 3 | import { TrimmedNonEmptyString, type ProviderKind } from "@t3tools/contracts"; |
| 4 | 4 | import { getDefaultModel, getModelOptions, normalizeModelSlug } from "@t3tools/shared/model"; |
| 5 | 5 | import { useLocalStorage } from "./hooks/useLocalStorage"; |
| 6 | +import { EnvMode } from "./components/BranchToolbar.logic"; |
| 6 | 7 | |
| 7 | 8 | const APP_SETTINGS_STORAGE_KEY = "t3code:app-settings:v1"; |
| 8 | 9 | const MAX_CUSTOM_MODEL_COUNT = 32; |
| 9 | 10 | export const MAX_CUSTOM_MODEL_LENGTH = 256; |
| 10 | | −export const TIMESTAMP_FORMAT_OPTIONS = ["locale", "12-hour", "24-hour"] as const; |
| 11 | | −export type TimestampFormat = (typeof TIMESTAMP_FORMAT_OPTIONS)[number]; |
| 11 | + |
| 12 | +export const TimestampFormat = Schema.Literals(["locale", "12-hour", "24-hour"]); |
| 13 | +export type TimestampFormat = typeof TimestampFormat.Type; |
| 12 | 14 | export const DEFAULT_TIMESTAMP_FORMAT: TimestampFormat = "locale"; |
| 15 | + |
| 13 | 16 | const BUILT_IN_MODEL_SLUGS_BY_PROVIDER: Record<ProviderKind, ReadonlySet<string>> = { |
| 14 | 17 | codex: new Set(getModelOptions("codex").map((option) => option.slug)), |
| 15 | 18 | claudeAgent: new Set(getModelOptions("claudeAgent").map((option) => option.slug)), |
| 16 | 19 | }; |
| 17 | 20 | |
| 18 | | −const AppSettingsSchema = Schema.Struct({ |
| 19 | | − codexBinaryPath: Schema.String.check(Schema.isMaxLength(4096)).pipe( |
| 20 | | − Schema.withConstructorDefault(() => Option.some("")), |
| 21 | | − ), |
| 22 | | − codexHomePath: Schema.String.check(Schema.isMaxLength(4096)).pipe( |
| 23 | | − Schema.withConstructorDefault(() => Option.some("")), |
| 24 | | − ), |
| 25 | | − defaultThreadEnvMode: Schema.Literals(["local", "worktree"]).pipe( |
| 26 | | − Schema.withConstructorDefault(() => Option.some("local")), |
| 27 | | − ), |
| 28 | | − confirmThreadDelete: Schema.Boolean.pipe(Schema.withConstructorDefault(() => Option.some(true))), |
| 29 | | − enableAssistantStreaming: Schema.Boolean.pipe( |
| 30 | | − Schema.withConstructorDefault(() => Option.some(false)), |
| 31 | | − ), |
| 32 | | − timestampFormat: Schema.Literals(["locale", "12-hour", "24-hour"]).pipe( |
| 33 | | − Schema.withConstructorDefault(() => Option.some(DEFAULT_TIMESTAMP_FORMAT)), |
| 34 | | − ), |
| 35 | | − customCodexModels: Schema.Array(Schema.String).pipe( |
| 36 | | − Schema.withConstructorDefault(() => Option.some([])), |
| 37 | | − ), |
| 38 | | − customClaudeModels: Schema.Array(Schema.String).pipe( |
| 39 | | − Schema.withConstructorDefault(() => Option.some([])), |
| 40 | | − ), |
| 21 | +const withDefaults = |
| 22 | + < |
| 23 | + S extends Schema.Top & Schema.WithoutConstructorDefault, |
| 24 | + D extends S["~type.make.in"] & S["Encoded"], |
| 25 | + >( |
| 26 | + fallback: () => D, |
| 27 | + ) => |
| 28 | + (schema: S) => |
| 29 | + schema.pipe( |
| 30 | + Schema.withConstructorDefault(() => Option.some(fallback())), |
| 31 | + Schema.withDecodingDefault(() => fallback()), |
| 32 | + ); |
| 33 | + |
| 34 | +export const AppSettingsSchema = Schema.Struct({ |
| 35 | + codexBinaryPath: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), |
| 36 | + codexHomePath: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), |
| 37 | + defaultThreadEnvMode: EnvMode.pipe(withDefaults(() => "local" as const satisfies EnvMode)), |
| 38 | + confirmThreadDelete: Schema.Boolean.pipe(withDefaults(() => true)), |
| 39 | + enableAssistantStreaming: Schema.Boolean.pipe(withDefaults(() => false)), |
| 40 | + timestampFormat: TimestampFormat.pipe(withDefaults(() => DEFAULT_TIMESTAMP_FORMAT)), |
| 41 | + customCodexModels: Schema.Array(Schema.String).pipe(withDefaults(() => [])), |
| 42 | + customClaudeModels: Schema.Array(Schema.String).pipe(withDefaults(() => [])), |
| 41 | 43 | textGenerationModel: Schema.optional(TrimmedNonEmptyString), |
| 42 | 44 | }); |
| 43 | 45 | export type AppSettings = typeof AppSettingsSchema.Type; |