diff --git a/packages/types/src/__tests__/index.test.ts b/packages/types/src/__tests__/index.test.ts index c3df37fa97..fd1e9e1c88 100644 --- a/packages/types/src/__tests__/index.test.ts +++ b/packages/types/src/__tests__/index.test.ts @@ -1,4 +1,4 @@ -// npx vitest run src/__tests__/index.test.ts +// npx vitest run --globals src/__tests__/index.test.ts import { GLOBAL_STATE_KEYS } from "../index.js" diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index d69a77fa53..10b7d6ab18 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -1,6 +1,6 @@ import { z } from "zod" -import type { Keys } from "./type-fu.js" +import { type Keys, keysOf } from "./type-fu.js" import { type ProviderSettings, PROVIDER_SETTINGS_KEYS, @@ -34,8 +34,6 @@ export const globalSettingsSchema = z.object({ autoApprovalEnabled: z.boolean().optional(), alwaysAllowReadOnly: z.boolean().optional(), alwaysAllowReadOnlyOutsideWorkspace: z.boolean().optional(), - codebaseIndexModels: codebaseIndexModelsSchema.optional(), - codebaseIndexConfig: codebaseIndexConfigSchema.optional(), alwaysAllowWrite: z.boolean().optional(), alwaysAllowWriteOutsideWorkspace: z.boolean().optional(), writeDelayMs: z.number().optional(), @@ -85,6 +83,9 @@ export const globalSettingsSchema = z.object({ fuzzyMatchThreshold: z.number().optional(), experiments: experimentsSchema.optional(), + codebaseIndexModels: codebaseIndexModelsSchema.optional(), + codebaseIndexConfig: codebaseIndexConfigSchema.optional(), + language: languagesSchema.optional(), telemetrySetting: telemetrySettingsSchema.optional(), @@ -103,91 +104,87 @@ export const globalSettingsSchema = z.object({ export type GlobalSettings = z.infer -type GlobalSettingsRecord = Record, undefined> - -const globalSettingsRecord: GlobalSettingsRecord = { - codebaseIndexModels: undefined, - codebaseIndexConfig: undefined, - currentApiConfigName: undefined, - listApiConfigMeta: undefined, - pinnedApiConfigs: undefined, - - lastShownAnnouncementId: undefined, - customInstructions: undefined, - taskHistory: undefined, - - condensingApiConfigId: undefined, - customCondensingPrompt: undefined, - - autoApprovalEnabled: undefined, - alwaysAllowReadOnly: undefined, - alwaysAllowReadOnlyOutsideWorkspace: undefined, - alwaysAllowWrite: undefined, - alwaysAllowWriteOutsideWorkspace: undefined, - writeDelayMs: undefined, - alwaysAllowBrowser: undefined, - alwaysApproveResubmit: undefined, - requestDelaySeconds: undefined, - alwaysAllowMcp: undefined, - alwaysAllowModeSwitch: undefined, - alwaysAllowSubtasks: undefined, - alwaysAllowExecute: undefined, - allowedCommands: undefined, - allowedMaxRequests: undefined, - autoCondenseContextPercent: undefined, - - browserToolEnabled: undefined, - browserViewportSize: undefined, - screenshotQuality: undefined, - remoteBrowserEnabled: undefined, - remoteBrowserHost: undefined, - - enableCheckpoints: undefined, - - ttsEnabled: undefined, - ttsSpeed: undefined, - soundEnabled: undefined, - soundVolume: undefined, - - maxOpenTabsContext: undefined, - maxWorkspaceFiles: undefined, - showRooIgnoredFiles: undefined, - maxReadFileLine: undefined, - - terminalOutputLineLimit: undefined, - terminalShellIntegrationTimeout: undefined, - terminalShellIntegrationDisabled: undefined, - terminalCommandDelay: undefined, - terminalPowershellCounter: undefined, - terminalZshClearEolMark: undefined, - terminalZshOhMy: undefined, - terminalZshP10k: undefined, - terminalZdotdir: undefined, - terminalCompressProgressBar: undefined, - - rateLimitSeconds: undefined, - diffEnabled: undefined, - fuzzyMatchThreshold: undefined, - experiments: undefined, - - language: undefined, - - telemetrySetting: undefined, - - mcpEnabled: undefined, - enableMcpServerCreation: undefined, - - mode: undefined, - modeApiConfigs: undefined, - customModes: undefined, - customModePrompts: undefined, - customSupportPrompts: undefined, - enhancementApiConfigId: undefined, - cachedChromeHostUrl: undefined, - historyPreviewCollapsed: undefined, -} - -export const GLOBAL_SETTINGS_KEYS = Object.keys(globalSettingsRecord) as Keys[] +export const GLOBAL_SETTINGS_KEYS = keysOf()([ + "currentApiConfigName", + "listApiConfigMeta", + "pinnedApiConfigs", + + "lastShownAnnouncementId", + "customInstructions", + "taskHistory", + + "condensingApiConfigId", + "customCondensingPrompt", + + "autoApprovalEnabled", + "alwaysAllowReadOnly", + "alwaysAllowReadOnlyOutsideWorkspace", + "alwaysAllowWrite", + "alwaysAllowWriteOutsideWorkspace", + "writeDelayMs", + "alwaysAllowBrowser", + "alwaysApproveResubmit", + "requestDelaySeconds", + "alwaysAllowMcp", + "alwaysAllowModeSwitch", + "alwaysAllowSubtasks", + "alwaysAllowExecute", + "allowedCommands", + "allowedMaxRequests", + "autoCondenseContextPercent", + + "browserToolEnabled", + "browserViewportSize", + "screenshotQuality", + "remoteBrowserEnabled", + "remoteBrowserHost", + + "enableCheckpoints", + + "ttsEnabled", + "ttsSpeed", + "soundEnabled", + "soundVolume", + + "maxOpenTabsContext", + "maxWorkspaceFiles", + "showRooIgnoredFiles", + "maxReadFileLine", + + "terminalOutputLineLimit", + "terminalShellIntegrationTimeout", + "terminalShellIntegrationDisabled", + "terminalCommandDelay", + "terminalPowershellCounter", + "terminalZshClearEolMark", + "terminalZshOhMy", + "terminalZshP10k", + "terminalZdotdir", + "terminalCompressProgressBar", + + "rateLimitSeconds", + "diffEnabled", + "fuzzyMatchThreshold", + "experiments", + + "codebaseIndexModels", + "codebaseIndexConfig", + + "language", + + "telemetrySetting", + "mcpEnabled", + "enableMcpServerCreation", + + "mode", + "modeApiConfigs", + "customModes", + "customModePrompts", + "customSupportPrompts", + "enhancementApiConfigId", + "cachedChromeHostUrl", + "historyPreviewCollapsed", +]) /** * RooCodeSettings @@ -224,33 +221,27 @@ export type SecretState = Pick< | "codeIndexQdrantApiKey" > -export type CodeIndexSecrets = "codeIndexOpenAiKey" | "codeIndexQdrantApiKey" - -type SecretStateRecord = Record, undefined> - -const secretStateRecord: SecretStateRecord = { - apiKey: undefined, - glamaApiKey: undefined, - openRouterApiKey: undefined, - awsAccessKey: undefined, - awsSecretKey: undefined, - awsSessionToken: undefined, - openAiApiKey: undefined, - geminiApiKey: undefined, - openAiNativeApiKey: undefined, - deepSeekApiKey: undefined, - mistralApiKey: undefined, - unboundApiKey: undefined, - requestyApiKey: undefined, - xaiApiKey: undefined, - groqApiKey: undefined, - chutesApiKey: undefined, - litellmApiKey: undefined, - codeIndexOpenAiKey: undefined, - codeIndexQdrantApiKey: undefined, -} - -export const SECRET_STATE_KEYS = Object.keys(secretStateRecord) as Keys[] +export const SECRET_STATE_KEYS = keysOf()([ + "apiKey", + "glamaApiKey", + "openRouterApiKey", + "awsAccessKey", + "awsSecretKey", + "awsSessionToken", + "openAiApiKey", + "geminiApiKey", + "openAiNativeApiKey", + "deepSeekApiKey", + "mistralApiKey", + "unboundApiKey", + "requestyApiKey", + "xaiApiKey", + "groqApiKey", + "chutesApiKey", + "litellmApiKey", + "codeIndexOpenAiKey", + "codeIndexQdrantApiKey", +]) export const isSecretStateKey = (key: string): key is Keys => SECRET_STATE_KEYS.includes(key as Keys) diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 6803cebc11..7076361ea5 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -1,6 +1,6 @@ import { z } from "zod" -import type { Keys } from "./type-fu.js" +import { keysOf } from "./type-fu.js" import { reasoningEffortsSchema, modelInfoSchema } from "./model.js" import { codebaseIndexProviderSchema } from "./codebase-index.js" @@ -257,104 +257,100 @@ export const providerSettingsSchema = z.object({ export type ProviderSettings = z.infer -type ProviderSettingsRecord = Record, undefined> - -const providerSettingsRecord: ProviderSettingsRecord = { - apiProvider: undefined, +export const PROVIDER_SETTINGS_KEYS = keysOf()([ + "apiProvider", // Anthropic - apiModelId: undefined, - apiKey: undefined, - anthropicBaseUrl: undefined, - anthropicUseAuthToken: undefined, + "apiModelId", + "apiKey", + "anthropicBaseUrl", + "anthropicUseAuthToken", // Glama - glamaModelId: undefined, - glamaApiKey: undefined, + "glamaModelId", + "glamaApiKey", // OpenRouter - openRouterApiKey: undefined, - openRouterModelId: undefined, - openRouterBaseUrl: undefined, - openRouterSpecificProvider: undefined, - openRouterUseMiddleOutTransform: undefined, + "openRouterApiKey", + "openRouterModelId", + "openRouterBaseUrl", + "openRouterSpecificProvider", + "openRouterUseMiddleOutTransform", // Amazon Bedrock - awsAccessKey: undefined, - awsSecretKey: undefined, - awsSessionToken: undefined, - awsRegion: undefined, - awsUseCrossRegionInference: undefined, - awsUsePromptCache: undefined, - awsProfile: undefined, - awsUseProfile: undefined, - awsCustomArn: undefined, + "awsAccessKey", + "awsSecretKey", + "awsSessionToken", + "awsRegion", + "awsUseCrossRegionInference", + "awsUsePromptCache", + "awsProfile", + "awsUseProfile", + "awsCustomArn", // Google Vertex - vertexKeyFile: undefined, - vertexJsonCredentials: undefined, - vertexProjectId: undefined, - vertexRegion: undefined, + "vertexKeyFile", + "vertexJsonCredentials", + "vertexProjectId", + "vertexRegion", // OpenAI - openAiBaseUrl: undefined, - openAiApiKey: undefined, - openAiLegacyFormat: undefined, - openAiR1FormatEnabled: undefined, - openAiModelId: undefined, - openAiCustomModelInfo: undefined, - openAiUseAzure: undefined, - azureApiVersion: undefined, - openAiStreamingEnabled: undefined, - openAiHostHeader: undefined, // Keep temporarily for backward compatibility during migration - openAiHeaders: undefined, + "openAiBaseUrl", + "openAiApiKey", + "openAiLegacyFormat", + "openAiR1FormatEnabled", + "openAiModelId", + "openAiCustomModelInfo", + "openAiUseAzure", + "azureApiVersion", + "openAiStreamingEnabled", + "openAiHostHeader", // Keep temporarily for backward compatibility during migration. + "openAiHeaders", // Ollama - ollamaModelId: undefined, - ollamaBaseUrl: undefined, + "ollamaModelId", + "ollamaBaseUrl", // VS Code LM - vsCodeLmModelSelector: undefined, - lmStudioModelId: undefined, - lmStudioBaseUrl: undefined, - lmStudioDraftModelId: undefined, - lmStudioSpeculativeDecodingEnabled: undefined, + "vsCodeLmModelSelector", + "lmStudioModelId", + "lmStudioBaseUrl", + "lmStudioDraftModelId", + "lmStudioSpeculativeDecodingEnabled", // Gemini - geminiApiKey: undefined, - googleGeminiBaseUrl: undefined, + "geminiApiKey", + "googleGeminiBaseUrl", // OpenAI Native - openAiNativeApiKey: undefined, - openAiNativeBaseUrl: undefined, + "openAiNativeApiKey", + "openAiNativeBaseUrl", // Mistral - mistralApiKey: undefined, - mistralCodestralUrl: undefined, + "mistralApiKey", + "mistralCodestralUrl", // DeepSeek - deepSeekBaseUrl: undefined, - deepSeekApiKey: undefined, + "deepSeekBaseUrl", + "deepSeekApiKey", // Unbound - unboundApiKey: undefined, - unboundModelId: undefined, + "unboundApiKey", + "unboundModelId", // Requesty - requestyApiKey: undefined, - requestyModelId: undefined, + "requestyApiKey", + "requestyModelId", // Code Index - codeIndexOpenAiKey: undefined, - codeIndexQdrantApiKey: undefined, + "codeIndexOpenAiKey", + "codeIndexQdrantApiKey", // Reasoning - enableReasoningEffort: undefined, - reasoningEffort: undefined, - modelMaxTokens: undefined, - modelMaxThinkingTokens: undefined, + "enableReasoningEffort", + "reasoningEffort", + "modelMaxTokens", + "modelMaxThinkingTokens", // Generic - includeMaxTokens: undefined, - diffEnabled: undefined, - fuzzyMatchThreshold: undefined, - modelTemperature: undefined, - rateLimitSeconds: undefined, + "includeMaxTokens", + "diffEnabled", + "fuzzyMatchThreshold", + "modelTemperature", + "rateLimitSeconds", // Fake AI - fakeAi: undefined, + "fakeAi", // X.AI (Grok) - xaiApiKey: undefined, + "xaiApiKey", // Groq - groqApiKey: undefined, + "groqApiKey", // Chutes AI - chutesApiKey: undefined, + "chutesApiKey", // LiteLLM - litellmBaseUrl: undefined, - litellmApiKey: undefined, - litellmModelId: undefined, -} - -export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Keys[] + "litellmBaseUrl", + "litellmApiKey", + "litellmModelId", +]) diff --git a/packages/types/src/type-fu.ts b/packages/types/src/type-fu.ts index 0014e9b187..f5962de6f0 100644 --- a/packages/types/src/type-fu.ts +++ b/packages/types/src/type-fu.ts @@ -9,3 +9,13 @@ export type Values = T[keyof T] export type Equals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? true : false export type AssertEqual = T + +/** + * Creates a type-safe keys array that enforces ALL keys from type T are present. + * Returns a compile-time error if any keys are missing or extra keys are provided. + */ +export function keysOf() { + return ( + keys: keyof T extends U[number] ? (U[number] extends keyof T ? U : never) : never, + ): U => keys +}