@desktalk/miniapp-preference 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend.js +10 -3
- package/dist/backend.js.map +2 -2
- package/dist/frontend.js +22 -22
- package/dist/frontend.js.map +3 -3
- package/dist/schema.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/backend.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
// src/schema.ts
|
|
2
2
|
var DEFAULT_AI_PROVIDER_ID = "openai";
|
|
3
|
+
var LEGACY_AI_PROVIDER_IDS = {
|
|
4
|
+
copilot: "github-copilot"
|
|
5
|
+
};
|
|
6
|
+
function normalizeAiProviderId(providerId) {
|
|
7
|
+
return LEGACY_AI_PROVIDER_IDS[providerId] ?? providerId;
|
|
8
|
+
}
|
|
3
9
|
var AI_PROVIDER_DEFINITIONS = [
|
|
4
10
|
// ─── Subscription (OAuth) providers ────────────────────────────────────
|
|
5
11
|
{
|
|
6
|
-
id: "copilot",
|
|
12
|
+
id: "github-copilot",
|
|
7
13
|
label: "GitHub Copilot",
|
|
8
14
|
authType: "subscription",
|
|
9
15
|
supportsApiKey: false,
|
|
@@ -171,7 +177,8 @@ var VOICE_PROVIDER_DEFINITIONS = [
|
|
|
171
177
|
var AI_PROVIDER_IDS = new Set(AI_PROVIDER_DEFINITIONS.map((provider) => provider.id));
|
|
172
178
|
var VOICE_PROVIDER_IDS = new Set(VOICE_PROVIDER_DEFINITIONS.map((provider) => provider.id));
|
|
173
179
|
function getAiProviderDefinition(providerId) {
|
|
174
|
-
|
|
180
|
+
const normalizedProviderId = normalizeAiProviderId(providerId);
|
|
181
|
+
return AI_PROVIDER_DEFINITIONS.find((provider) => provider.id === normalizedProviderId);
|
|
175
182
|
}
|
|
176
183
|
function getAiProviderConfigKeys(providerId) {
|
|
177
184
|
const definition = getAiProviderDefinition(providerId);
|
|
@@ -191,7 +198,7 @@ function parseAiEnabledProviders(value) {
|
|
|
191
198
|
if (typeof value !== "string") {
|
|
192
199
|
return [DEFAULT_AI_PROVIDER_ID];
|
|
193
200
|
}
|
|
194
|
-
const providers = value.split(",").map((item) => item.trim()).filter(
|
|
201
|
+
const providers = value.split(",").map((item) => normalizeAiProviderId(item.trim())).filter(
|
|
195
202
|
(item, index, items) => item && items.indexOf(item) === index && AI_PROVIDER_IDS.has(item)
|
|
196
203
|
);
|
|
197
204
|
return providers.length > 0 ? providers : [DEFAULT_AI_PROVIDER_ID];
|
package/dist/backend.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/schema.ts", "../src/backend.ts"],
|
|
4
|
-
"sourcesContent": ["// \u2500\u2500\u2500 Preference Schema \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Shared between backend and frontend. Defines every configurable setting,\n// its type, default value, category, and UI constraints.\n\nexport interface PreferenceSchema {\n key: string;\n label: string;\n description: string;\n type: 'string' | 'number' | 'boolean';\n default: string | number | boolean;\n options?: string[]; // For enum-like string settings (renders a dropdown)\n min?: number; // For number settings\n max?: number; // For number settings\n category: string;\n requiresRestart?: boolean;\n sensitive?: boolean; // e.g. API keys \u2014 masked in UI\n}\n\nexport type Config = Record<string, string | number | boolean>;\n\nexport const CATEGORIES = ['General', 'Server', 'AI', 'Voice'] as const;\nexport type Category = (typeof CATEGORIES)[number];\n\nexport type AiProviderAuthType = 'api-key' | 'subscription';\n\nexport interface AiProviderDefinition {\n id: string;\n label: string;\n authType: AiProviderAuthType;\n supportsApiKey: boolean;\n supportsBaseUrl: boolean;\n}\n\nexport interface VoiceProviderDefinition {\n id: string;\n label: string;\n supportsApiKey: boolean;\n supportsBaseUrl: boolean;\n supportsModel: boolean;\n supportsAzureDeployment: boolean;\n supportsAzureApiVersion: boolean;\n}\n\nexport const DEFAULT_AI_PROVIDER_ID = 'openai';\n\nexport const AI_PROVIDER_DEFINITIONS: AiProviderDefinition[] = [\n // \u2500\u2500\u2500 Subscription (OAuth) providers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n id: 'copilot',\n label: 'GitHub Copilot',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'openai-codex',\n label: 'OpenAI Codex',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'claude-pro',\n label: 'Claude Pro/Max',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'gemini-cli',\n label: 'Google Gemini CLI',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'google-antigravity',\n label: 'Google Antigravity',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n // \u2500\u2500\u2500 API-key providers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n id: 'anthropic',\n label: 'Anthropic',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'azure-openai-responses',\n label: 'Azure OpenAI',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: DEFAULT_AI_PROVIDER_ID,\n label: 'OpenAI',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: 'google',\n label: 'Google Gemini',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'mistral',\n label: 'Mistral',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n { id: 'groq', label: 'Groq', authType: 'api-key', supportsApiKey: true, supportsBaseUrl: true },\n {\n id: 'cerebras',\n label: 'Cerebras',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n { id: 'xai', label: 'xAI', authType: 'api-key', supportsApiKey: true, supportsBaseUrl: true },\n {\n id: 'openrouter',\n label: 'OpenRouter',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: 'vercel-ai-gateway',\n label: 'Vercel AI Gateway',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n { id: 'zai', label: 'ZAI', authType: 'api-key', supportsApiKey: true, supportsBaseUrl: false },\n {\n id: 'opencode',\n label: 'OpenCode Zen',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'opencode-go',\n label: 'OpenCode Go',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'huggingface',\n label: 'Hugging Face',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: 'kimi-coding',\n label: 'Kimi For Coding',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'minimax',\n label: 'MiniMax',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'minimax-cn',\n label: 'MiniMax China',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'ollama',\n label: 'Ollama',\n authType: 'api-key',\n supportsApiKey: false,\n supportsBaseUrl: true,\n },\n];\n\nexport const DEFAULT_VOICE_PROVIDER_ID = 'openai-whisper';\n\nexport const VOICE_PROVIDER_DEFINITIONS: VoiceProviderDefinition[] = [\n {\n id: DEFAULT_VOICE_PROVIDER_ID,\n label: 'OpenAI Whisper',\n supportsApiKey: true,\n supportsBaseUrl: true,\n supportsModel: true,\n supportsAzureDeployment: false,\n supportsAzureApiVersion: false,\n },\n {\n id: 'azure-openai-whisper',\n label: 'Azure OpenAI Whisper',\n supportsApiKey: true,\n supportsBaseUrl: true,\n supportsModel: false,\n supportsAzureDeployment: true,\n supportsAzureApiVersion: true,\n },\n];\n\nconst AI_PROVIDER_IDS = new Set(AI_PROVIDER_DEFINITIONS.map((provider) => provider.id));\nconst VOICE_PROVIDER_IDS = new Set(VOICE_PROVIDER_DEFINITIONS.map((provider) => provider.id));\n\nexport function getAiProviderDefinition(providerId: string): AiProviderDefinition | undefined {\n return AI_PROVIDER_DEFINITIONS.find((provider) => provider.id === providerId);\n}\n\nexport function getAiProviderConfigKeys(providerId: string): string[] {\n const definition = getAiProviderDefinition(providerId);\n if (!definition) {\n return [];\n }\n\n const keys = [`ai.providers.${providerId}.model`];\n if (definition.supportsApiKey) {\n keys.push(`ai.providers.${providerId}.apiKey`);\n }\n if (definition.supportsBaseUrl) {\n keys.push(`ai.providers.${providerId}.baseUrl`);\n }\n return keys;\n}\n\nexport function parseAiEnabledProviders(value: unknown): string[] {\n if (typeof value !== 'string') {\n return [DEFAULT_AI_PROVIDER_ID];\n }\n\n const providers = value\n .split(',')\n .map((item) => item.trim())\n .filter(\n (item, index, items) => item && items.indexOf(item) === index && AI_PROVIDER_IDS.has(item),\n );\n\n return providers.length > 0 ? providers : [DEFAULT_AI_PROVIDER_ID];\n}\n\nexport function serializeAiEnabledProviders(providerIds: string[]): string {\n return parseAiEnabledProviders(providerIds.join(',')).join(',');\n}\n\nexport function hasAiProviderConfig(config: Config, providerId: string): boolean {\n return getAiProviderConfigKeys(providerId).some((key) => {\n const value = config[key];\n return typeof value === 'string' && value.trim().length > 0;\n });\n}\n\nexport function getVoiceProviderDefinition(\n providerId: string,\n): VoiceProviderDefinition | undefined {\n return VOICE_PROVIDER_DEFINITIONS.find((provider) => provider.id === providerId);\n}\n\nexport function getVoiceProviderConfigKeys(providerId: string): string[] {\n const definition = getVoiceProviderDefinition(providerId);\n if (!definition) {\n return [];\n }\n\n const keys: string[] = [];\n if (definition.supportsApiKey) {\n keys.push(`voice.providers.${providerId}.apiKey`);\n }\n if (definition.supportsModel) {\n keys.push(`voice.providers.${providerId}.model`);\n }\n if (definition.supportsBaseUrl) {\n keys.push(`voice.providers.${providerId}.baseUrl`);\n }\n if (definition.supportsAzureDeployment) {\n keys.push(`voice.providers.${providerId}.azureDeployment`);\n }\n if (definition.supportsAzureApiVersion) {\n keys.push(`voice.providers.${providerId}.azureApiVersion`);\n }\n return keys;\n}\n\nexport function parseVoiceEnabledProviders(value: unknown): string[] {\n if (typeof value !== 'string') {\n return [DEFAULT_VOICE_PROVIDER_ID];\n }\n\n const providers = value\n .split(',')\n .map((item) => item.trim())\n .filter(\n (item, index, items) => item && items.indexOf(item) === index && VOICE_PROVIDER_IDS.has(item),\n );\n\n return providers.length > 0 ? providers : [DEFAULT_VOICE_PROVIDER_ID];\n}\n\nexport function serializeVoiceEnabledProviders(providerIds: string[]): string {\n return parseVoiceEnabledProviders(providerIds.join(',')).join(',');\n}\n\nexport function hasVoiceProviderConfig(config: Config, providerId: string): boolean {\n return getVoiceProviderConfigKeys(providerId).some((key) => {\n const value = config[key];\n return typeof value === 'string' && value.trim().length > 0;\n });\n}\n\nfunction getAiProviderPreferenceSchemas(): PreferenceSchema[] {\n const schemas: PreferenceSchema[] = [\n {\n key: 'ai.enabledProviders',\n label: 'Enabled Providers',\n description: 'Ordered list of configured AI providers.',\n type: 'string',\n default: DEFAULT_AI_PROVIDER_ID,\n category: 'AI',\n },\n {\n key: 'ai.defaultProvider',\n label: 'Default Provider',\n description: 'Provider selected by default for chat and tool execution.',\n type: 'string',\n default: DEFAULT_AI_PROVIDER_ID,\n options: AI_PROVIDER_DEFINITIONS.map((provider) => provider.id),\n category: 'AI',\n },\n ];\n\n for (const provider of AI_PROVIDER_DEFINITIONS) {\n schemas.push({\n key: `ai.providers.${provider.id}.model`,\n label: `${provider.label} Model`,\n description: `Model identifier to use when ${provider.label} is selected.`,\n type: 'string',\n default: '',\n category: 'AI',\n });\n\n if (provider.supportsApiKey) {\n schemas.push({\n key: `ai.providers.${provider.id}.apiKey`,\n label: `${provider.label} API Key`,\n description: `API key for ${provider.label}.`,\n type: 'string',\n default: '',\n category: 'AI',\n sensitive: true,\n });\n }\n\n if (provider.supportsBaseUrl) {\n schemas.push({\n key: `ai.providers.${provider.id}.baseUrl`,\n label: `${provider.label} Base URL`,\n description: `Optional custom API base URL for ${provider.label}.`,\n type: 'string',\n default: '',\n category: 'AI',\n });\n }\n }\n\n schemas.push({\n key: 'ai.maxTokens',\n label: 'Max Tokens',\n description: 'Maximum tokens per AI response.',\n type: 'number',\n default: 4096,\n min: 256,\n max: 128000,\n category: 'AI',\n });\n\n return schemas;\n}\n\nconst AI_PREFERENCE_SCHEMAS = getAiProviderPreferenceSchemas();\n\nfunction getVoiceProviderPreferenceSchemas(): PreferenceSchema[] {\n const schemas: PreferenceSchema[] = [\n {\n key: 'voice.enabledProviders',\n label: 'Enabled Providers',\n description: 'Ordered list of configured STT providers.',\n type: 'string',\n default: DEFAULT_VOICE_PROVIDER_ID,\n category: 'Voice',\n },\n {\n key: 'voice.defaultProvider',\n label: 'Default Provider',\n description: 'Provider selected by default for voice transcription.',\n type: 'string',\n default: DEFAULT_VOICE_PROVIDER_ID,\n options: VOICE_PROVIDER_DEFINITIONS.map((provider) => provider.id),\n category: 'Voice',\n },\n ];\n\n for (const provider of VOICE_PROVIDER_DEFINITIONS) {\n if (provider.supportsApiKey) {\n schemas.push({\n key: `voice.providers.${provider.id}.apiKey`,\n label: `${provider.label} API Key`,\n description: `API key for ${provider.label}.`,\n type: 'string',\n default: '',\n category: 'Voice',\n sensitive: true,\n });\n }\n\n if (provider.supportsModel) {\n schemas.push({\n key: `voice.providers.${provider.id}.model`,\n label: `${provider.label} Model`,\n description: `Model identifier to use when ${provider.label} is selected.`,\n type: 'string',\n default: 'whisper-1',\n category: 'Voice',\n });\n }\n\n if (provider.supportsBaseUrl) {\n schemas.push({\n key: `voice.providers.${provider.id}.baseUrl`,\n label: `${provider.label} Base URL`,\n description:\n provider.id === 'azure-openai-whisper'\n ? 'Base URL for Azure OpenAI Whisper requests.'\n : `Optional custom API base URL for ${provider.label}.`,\n type: 'string',\n default: provider.id === DEFAULT_VOICE_PROVIDER_ID ? 'https://api.openai.com/v1' : '',\n category: 'Voice',\n });\n }\n\n if (provider.supportsAzureDeployment) {\n schemas.push({\n key: `voice.providers.${provider.id}.azureDeployment`,\n label: `${provider.label} Deployment`,\n description: 'Azure OpenAI deployment name for Whisper transcription.',\n type: 'string',\n default: '',\n category: 'Voice',\n });\n }\n\n if (provider.supportsAzureApiVersion) {\n schemas.push({\n key: `voice.providers.${provider.id}.azureApiVersion`,\n label: `${provider.label} API Version`,\n description: 'Azure OpenAI API version used for transcription requests.',\n type: 'string',\n default: '2024-06-01',\n category: 'Voice',\n });\n }\n }\n\n return schemas;\n}\n\nconst VOICE_PREFERENCE_SCHEMAS = getVoiceProviderPreferenceSchemas();\n\nexport const PREFERENCE_SCHEMAS: PreferenceSchema[] = [\n // \u2500\u2500\u2500 General \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n key: 'general.theme',\n label: 'Theme',\n description: 'UI theme: light or dark.',\n type: 'string',\n default: 'light',\n options: ['light', 'dark'],\n category: 'General',\n },\n {\n key: 'general.accentColor',\n label: 'Accent Color',\n description: 'Primary theme color. Accepts hex values or any CSS color string.',\n type: 'string',\n default: '#7c6ff7',\n category: 'General',\n },\n {\n key: 'general.language',\n label: 'Language',\n description: 'UI language/locale.',\n type: 'string',\n default: 'en',\n options: ['en', 'zh'],\n category: 'General',\n },\n {\n key: 'general.dataDirectory',\n label: 'Data Directory',\n description:\n 'Override the base data directory. Leave empty for platform default (resolved via env-paths).',\n type: 'string',\n default: '',\n category: 'General',\n requiresRestart: true,\n },\n\n // \u2500\u2500\u2500 Server \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n key: 'server.host',\n label: 'Host',\n description: 'Server bind address.',\n type: 'string',\n default: 'localhost',\n category: 'Server',\n requiresRestart: true,\n },\n {\n key: 'server.port',\n label: 'Port',\n description: 'Server listen port.',\n type: 'number',\n default: 3000,\n min: 1,\n max: 65535,\n category: 'Server',\n requiresRestart: true,\n },\n\n // \u2500\u2500\u2500 AI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n ...AI_PREFERENCE_SCHEMAS,\n\n // \u2500\u2500\u2500 Voice \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n ...VOICE_PREFERENCE_SCHEMAS,\n {\n key: 'voice.silenceTimeoutMs',\n label: 'Silence Timeout',\n description: 'Silence duration (ms) before finalizing an utterance.',\n type: 'number',\n default: 800,\n min: 200,\n max: 5000,\n category: 'Voice',\n },\n {\n key: 'voice.energyThreshold',\n label: 'Energy Threshold',\n description: 'RMS energy threshold for voice activity detection (0\u201332767).',\n type: 'number',\n default: 500,\n min: 50,\n max: 10000,\n category: 'Voice',\n },\n];\n\n/** Build the default config from schemas */\nexport function getDefaultConfig(): Config {\n const config: Config = {};\n for (const schema of PREFERENCE_SCHEMAS) {\n config[schema.key] = schema.default;\n }\n return config;\n}\n\n/** Find schema by key */\nexport function getSchema(key: string): PreferenceSchema | undefined {\n return PREFERENCE_SCHEMAS.find((s) => s.key === key);\n}\n\n/** Get all schemas for a category */\nexport function getSchemasByCategory(category: string): PreferenceSchema[] {\n return PREFERENCE_SCHEMAS.filter((s) => s.category === category);\n}\n\n/** Mask a sensitive value \u2014 show only last 4 characters */\nexport function maskSensitive(value: string): string {\n if (value.length <= 4) return '****';\n return '*'.repeat(value.length - 4) + value.slice(-4);\n}\n", "import type { MiniAppManifest, MiniAppContext, MiniAppBackendActivation } from '@desktalk/sdk';\nimport type { Config } from './schema';\nimport {\n PREFERENCE_SCHEMAS,\n DEFAULT_AI_PROVIDER_ID,\n DEFAULT_VOICE_PROVIDER_ID,\n getDefaultConfig,\n getSchema,\n hasAiProviderConfig,\n hasVoiceProviderConfig,\n maskSensitive,\n parseAiEnabledProviders,\n parseVoiceEnabledProviders,\n serializeAiEnabledProviders,\n serializeVoiceEnabledProviders,\n} from './schema';\n\n// \u2500\u2500\u2500 Manifest \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const manifest: MiniAppManifest = {\n id: 'preference',\n name: 'Preferences',\n icon: '\\u2699\\uFE0F',\n version: '0.1.0',\n description: 'Application settings and configuration',\n};\n\n// \u2500\u2500\u2500 Activate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * The Preference MiniApp uses ctx.storage as the persistence layer for settings.\n * In production, the core would provide a privileged ctx.config hook that writes\n * to <config>/config.toml. For now, ctx.storage serves as the backing store.\n *\n * All settings are stored under the key \"config\" as a flat Config object.\n */\nexport function activate(ctx: MiniAppContext): MiniAppBackendActivation {\n ctx.logger.info('Preference MiniApp activated');\n\n const defaults = getDefaultConfig();\n\n /** Load the persisted config, merging with defaults for any missing keys. */\n async function loadConfig(): Promise<Config> {\n const stored = await ctx.storage.get<Config>('config');\n const config = { ...defaults, ...(stored ?? {}) };\n\n const legacyProvider =\n typeof stored?.['ai.provider'] === 'string' ? stored['ai.provider'] : undefined;\n if (legacyProvider && typeof stored?.['ai.defaultProvider'] !== 'string') {\n config['ai.defaultProvider'] = legacyProvider;\n }\n\n if (legacyProvider) {\n const legacyModel = typeof stored?.['ai.model'] === 'string' ? stored['ai.model'] : undefined;\n const legacyApiKey =\n typeof stored?.['ai.apiKey'] === 'string' ? stored['ai.apiKey'] : undefined;\n const legacyBaseUrl =\n typeof stored?.['ai.baseUrl'] === 'string' ? stored['ai.baseUrl'] : undefined;\n\n const providerModelKey = `ai.providers.${legacyProvider}.model`;\n const providerApiKeyKey = `ai.providers.${legacyProvider}.apiKey`;\n const providerBaseUrlKey = `ai.providers.${legacyProvider}.baseUrl`;\n\n if (legacyModel && !config[providerModelKey]) {\n config[providerModelKey] = legacyModel;\n }\n if (legacyApiKey && !config[providerApiKeyKey]) {\n config[providerApiKeyKey] = legacyApiKey;\n }\n if (legacyBaseUrl && !config[providerBaseUrlKey]) {\n config[providerBaseUrlKey] = legacyBaseUrl;\n }\n }\n\n const enabledProviders = parseAiEnabledProviders(stored?.['ai.enabledProviders']);\n const derivedProviders = enabledProviders.filter((providerId) =>\n hasAiProviderConfig(config, providerId),\n );\n for (const schema of PREFERENCE_SCHEMAS) {\n if (!schema.key.startsWith('ai.providers.')) {\n continue;\n }\n\n const match = /^ai\\.providers\\.([^.]+)\\./.exec(schema.key);\n const providerId = match?.[1];\n if (\n providerId &&\n hasAiProviderConfig(config, providerId) &&\n !derivedProviders.includes(providerId)\n ) {\n derivedProviders.push(providerId);\n }\n }\n\n const defaultProvider =\n typeof config['ai.defaultProvider'] === 'string' && config['ai.defaultProvider']\n ? String(config['ai.defaultProvider'])\n : DEFAULT_AI_PROVIDER_ID;\n\n if (!derivedProviders.includes(defaultProvider)) {\n derivedProviders.unshift(defaultProvider);\n }\n\n for (const providerId of enabledProviders) {\n if (!derivedProviders.includes(providerId)) {\n derivedProviders.push(providerId);\n }\n }\n\n config['ai.enabledProviders'] = serializeAiEnabledProviders(derivedProviders);\n config['ai.defaultProvider'] = derivedProviders[0] ?? DEFAULT_AI_PROVIDER_ID;\n\n const legacyVoiceProvider =\n typeof stored?.['voice.provider'] === 'string' ? stored['voice.provider'] : undefined;\n if (legacyVoiceProvider && typeof stored?.['voice.defaultProvider'] !== 'string') {\n config['voice.defaultProvider'] = legacyVoiceProvider;\n }\n\n if (legacyVoiceProvider) {\n const legacyVoiceApiKey =\n typeof stored?.['voice.apiKey'] === 'string' ? stored['voice.apiKey'] : undefined;\n const legacyVoiceModel =\n typeof stored?.['voice.model'] === 'string' ? stored['voice.model'] : undefined;\n const legacyVoiceBaseUrl =\n typeof stored?.['voice.baseUrl'] === 'string' ? stored['voice.baseUrl'] : undefined;\n const legacyVoiceDeployment =\n typeof stored?.['voice.azureDeployment'] === 'string'\n ? stored['voice.azureDeployment']\n : undefined;\n const legacyVoiceApiVersion =\n typeof stored?.['voice.azureApiVersion'] === 'string'\n ? stored['voice.azureApiVersion']\n : undefined;\n\n if (legacyVoiceApiKey && !config[`voice.providers.${legacyVoiceProvider}.apiKey`]) {\n config[`voice.providers.${legacyVoiceProvider}.apiKey`] = legacyVoiceApiKey;\n }\n if (legacyVoiceModel && !config[`voice.providers.${legacyVoiceProvider}.model`]) {\n config[`voice.providers.${legacyVoiceProvider}.model`] = legacyVoiceModel;\n }\n if (legacyVoiceBaseUrl && !config[`voice.providers.${legacyVoiceProvider}.baseUrl`]) {\n config[`voice.providers.${legacyVoiceProvider}.baseUrl`] = legacyVoiceBaseUrl;\n }\n if (\n legacyVoiceDeployment &&\n !config[`voice.providers.${legacyVoiceProvider}.azureDeployment`]\n ) {\n config[`voice.providers.${legacyVoiceProvider}.azureDeployment`] = legacyVoiceDeployment;\n }\n if (\n legacyVoiceApiVersion &&\n !config[`voice.providers.${legacyVoiceProvider}.azureApiVersion`]\n ) {\n config[`voice.providers.${legacyVoiceProvider}.azureApiVersion`] = legacyVoiceApiVersion;\n }\n }\n\n const enabledVoiceProviders = parseVoiceEnabledProviders(stored?.['voice.enabledProviders']);\n const derivedVoiceProviders = enabledVoiceProviders.filter((providerId) =>\n hasVoiceProviderConfig(config, providerId),\n );\n for (const schema of PREFERENCE_SCHEMAS) {\n if (!schema.key.startsWith('voice.providers.')) {\n continue;\n }\n\n const match = /^voice\\.providers\\.([^.]+)\\./.exec(schema.key);\n const providerId = match?.[1];\n if (\n providerId &&\n hasVoiceProviderConfig(config, providerId) &&\n !derivedVoiceProviders.includes(providerId)\n ) {\n derivedVoiceProviders.push(providerId);\n }\n }\n\n const defaultVoiceProvider =\n typeof config['voice.defaultProvider'] === 'string' && config['voice.defaultProvider']\n ? String(config['voice.defaultProvider'])\n : DEFAULT_VOICE_PROVIDER_ID;\n\n if (!derivedVoiceProviders.includes(defaultVoiceProvider)) {\n derivedVoiceProviders.unshift(defaultVoiceProvider);\n }\n\n for (const providerId of enabledVoiceProviders) {\n if (!derivedVoiceProviders.includes(providerId)) {\n derivedVoiceProviders.push(providerId);\n }\n }\n\n config['voice.enabledProviders'] = serializeVoiceEnabledProviders(derivedVoiceProviders);\n config['voice.defaultProvider'] = derivedVoiceProviders[0] ?? DEFAULT_VOICE_PROVIDER_ID;\n\n return config;\n }\n\n /** Persist the config to storage. */\n async function saveConfig(config: Config): Promise<void> {\n await ctx.storage.set('config', config);\n }\n\n /**\n * Mask sensitive values in the config for API responses.\n * The raw value is stored internally; only the masked version is returned.\n */\n function maskConfig(config: Config): Config {\n const masked = { ...config };\n for (const schema of PREFERENCE_SCHEMAS) {\n if (schema.sensitive && typeof masked[schema.key] === 'string') {\n const raw = masked[schema.key] as string;\n masked[schema.key] = raw ? maskSensitive(raw) : '';\n }\n }\n return masked;\n }\n\n // \u2500\u2500\u2500 preferences.getAll \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<void, Config>('preferences.getAll', async () => {\n const config = await loadConfig();\n return maskConfig(config);\n });\n\n // \u2500\u2500\u2500 preferences.get \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<{ key: string }, { value: string | number | boolean }>(\n 'preferences.get',\n async (req) => {\n const config = await loadConfig();\n const schema = getSchema(req.key);\n let value = config[req.key] ?? defaults[req.key];\n\n if (value === undefined) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n // Mask sensitive values\n if (schema?.sensitive && typeof value === 'string' && value) {\n value = maskSensitive(value);\n }\n\n return { value };\n },\n );\n\n // \u2500\u2500\u2500 preferences.getRaw (internal \u2014 returns unmasked values for backend use)\n\n ctx.messaging.onCommand<{ key: string }, { value: string | number | boolean }>(\n 'preferences.getRaw',\n async (req) => {\n const config = await loadConfig();\n const value = config[req.key] ?? defaults[req.key];\n\n if (value === undefined) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n return { value };\n },\n );\n\n // \u2500\u2500\u2500 preferences.set \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<{ key: string; value: string | number | boolean }, void>(\n 'preferences.set',\n async (req) => {\n const schema = getSchema(req.key);\n if (!schema) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n // Type validation\n if (typeof req.value !== schema.type) {\n throw new Error(`Expected ${schema.type} for ${req.key}, got ${typeof req.value}`);\n }\n\n // Range validation for numbers\n if (schema.type === 'number' && typeof req.value === 'number') {\n if (schema.min !== undefined && req.value < schema.min) {\n throw new Error(`${req.key} must be >= ${schema.min}`);\n }\n if (schema.max !== undefined && req.value > schema.max) {\n throw new Error(`${req.key} must be <= ${schema.max}`);\n }\n }\n\n // Enum validation for string options\n if (schema.options && typeof req.value === 'string') {\n if (!schema.options.includes(req.value)) {\n throw new Error(`${req.key} must be one of: ${schema.options.join(', ')}`);\n }\n }\n\n const config = await loadConfig();\n config[req.key] = req.value;\n await saveConfig(config);\n\n ctx.logger.info(`Setting updated: ${req.key}`);\n\n // Emit change event so frontend can react\n ctx.messaging.emit('preferences:changed', {\n key: req.key,\n value: schema.sensitive ? maskSensitive(String(req.value)) : req.value,\n requiresRestart: schema.requiresRestart ?? false,\n });\n },\n );\n\n // \u2500\u2500\u2500 preferences.reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<{ key: string }, void>('preferences.reset', async (req) => {\n const schema = getSchema(req.key);\n if (!schema) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n const config = await loadConfig();\n config[req.key] = schema.default;\n await saveConfig(config);\n\n ctx.logger.info(`Setting reset: ${req.key}`);\n\n ctx.messaging.emit('preferences:changed', {\n key: req.key,\n value: schema.default,\n requiresRestart: schema.requiresRestart ?? false,\n });\n });\n\n // \u2500\u2500\u2500 preferences.resetAll \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<void, void>('preferences.resetAll', async () => {\n await saveConfig({ ...defaults });\n ctx.logger.info('All settings reset to defaults');\n\n ctx.messaging.emit('preferences:resetAll', {});\n });\n\n return {};\n}\n\n// \u2500\u2500\u2500 Deactivate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function deactivate(): void {\n // cleanup\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["// \u2500\u2500\u2500 Preference Schema \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Shared between backend and frontend. Defines every configurable setting,\n// its type, default value, category, and UI constraints.\n\nexport interface PreferenceSchema {\n key: string;\n label: string;\n description: string;\n type: 'string' | 'number' | 'boolean';\n default: string | number | boolean;\n options?: string[]; // For enum-like string settings (renders a dropdown)\n min?: number; // For number settings\n max?: number; // For number settings\n category: string;\n requiresRestart?: boolean;\n sensitive?: boolean; // e.g. API keys \u2014 masked in UI\n}\n\nexport type Config = Record<string, string | number | boolean>;\n\nexport const CATEGORIES = ['General', 'Server', 'AI', 'Voice'] as const;\nexport type Category = (typeof CATEGORIES)[number];\n\nexport type AiProviderAuthType = 'api-key' | 'subscription';\n\nexport interface AiProviderDefinition {\n id: string;\n label: string;\n authType: AiProviderAuthType;\n supportsApiKey: boolean;\n supportsBaseUrl: boolean;\n}\n\nexport interface VoiceProviderDefinition {\n id: string;\n label: string;\n supportsApiKey: boolean;\n supportsBaseUrl: boolean;\n supportsModel: boolean;\n supportsAzureDeployment: boolean;\n supportsAzureApiVersion: boolean;\n}\n\nexport const DEFAULT_AI_PROVIDER_ID = 'openai';\nconst LEGACY_AI_PROVIDER_IDS: Record<string, string> = {\n copilot: 'github-copilot',\n};\n\nfunction normalizeAiProviderId(providerId: string): string {\n return LEGACY_AI_PROVIDER_IDS[providerId] ?? providerId;\n}\n\nexport const AI_PROVIDER_DEFINITIONS: AiProviderDefinition[] = [\n // \u2500\u2500\u2500 Subscription (OAuth) providers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n id: 'github-copilot',\n label: 'GitHub Copilot',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'openai-codex',\n label: 'OpenAI Codex',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'claude-pro',\n label: 'Claude Pro/Max',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'gemini-cli',\n label: 'Google Gemini CLI',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n {\n id: 'google-antigravity',\n label: 'Google Antigravity',\n authType: 'subscription',\n supportsApiKey: false,\n supportsBaseUrl: false,\n },\n // \u2500\u2500\u2500 API-key providers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n id: 'anthropic',\n label: 'Anthropic',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'azure-openai-responses',\n label: 'Azure OpenAI',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: DEFAULT_AI_PROVIDER_ID,\n label: 'OpenAI',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: 'google',\n label: 'Google Gemini',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'mistral',\n label: 'Mistral',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n { id: 'groq', label: 'Groq', authType: 'api-key', supportsApiKey: true, supportsBaseUrl: true },\n {\n id: 'cerebras',\n label: 'Cerebras',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n { id: 'xai', label: 'xAI', authType: 'api-key', supportsApiKey: true, supportsBaseUrl: true },\n {\n id: 'openrouter',\n label: 'OpenRouter',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: 'vercel-ai-gateway',\n label: 'Vercel AI Gateway',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n { id: 'zai', label: 'ZAI', authType: 'api-key', supportsApiKey: true, supportsBaseUrl: false },\n {\n id: 'opencode',\n label: 'OpenCode Zen',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'opencode-go',\n label: 'OpenCode Go',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'huggingface',\n label: 'Hugging Face',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: true,\n },\n {\n id: 'kimi-coding',\n label: 'Kimi For Coding',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'minimax',\n label: 'MiniMax',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'minimax-cn',\n label: 'MiniMax China',\n authType: 'api-key',\n supportsApiKey: true,\n supportsBaseUrl: false,\n },\n {\n id: 'ollama',\n label: 'Ollama',\n authType: 'api-key',\n supportsApiKey: false,\n supportsBaseUrl: true,\n },\n];\n\nexport const DEFAULT_VOICE_PROVIDER_ID = 'openai-whisper';\n\nexport const VOICE_PROVIDER_DEFINITIONS: VoiceProviderDefinition[] = [\n {\n id: DEFAULT_VOICE_PROVIDER_ID,\n label: 'OpenAI Whisper',\n supportsApiKey: true,\n supportsBaseUrl: true,\n supportsModel: true,\n supportsAzureDeployment: false,\n supportsAzureApiVersion: false,\n },\n {\n id: 'azure-openai-whisper',\n label: 'Azure OpenAI Whisper',\n supportsApiKey: true,\n supportsBaseUrl: true,\n supportsModel: false,\n supportsAzureDeployment: true,\n supportsAzureApiVersion: true,\n },\n];\n\nconst AI_PROVIDER_IDS = new Set(AI_PROVIDER_DEFINITIONS.map((provider) => provider.id));\nconst VOICE_PROVIDER_IDS = new Set(VOICE_PROVIDER_DEFINITIONS.map((provider) => provider.id));\n\nexport function getAiProviderDefinition(providerId: string): AiProviderDefinition | undefined {\n const normalizedProviderId = normalizeAiProviderId(providerId);\n return AI_PROVIDER_DEFINITIONS.find((provider) => provider.id === normalizedProviderId);\n}\n\nexport function getAiProviderConfigKeys(providerId: string): string[] {\n const definition = getAiProviderDefinition(providerId);\n if (!definition) {\n return [];\n }\n\n const keys = [`ai.providers.${providerId}.model`];\n if (definition.supportsApiKey) {\n keys.push(`ai.providers.${providerId}.apiKey`);\n }\n if (definition.supportsBaseUrl) {\n keys.push(`ai.providers.${providerId}.baseUrl`);\n }\n return keys;\n}\n\nexport function parseAiEnabledProviders(value: unknown): string[] {\n if (typeof value !== 'string') {\n return [DEFAULT_AI_PROVIDER_ID];\n }\n\n const providers = value\n .split(',')\n .map((item) => normalizeAiProviderId(item.trim()))\n .filter(\n (item, index, items) => item && items.indexOf(item) === index && AI_PROVIDER_IDS.has(item),\n );\n\n return providers.length > 0 ? providers : [DEFAULT_AI_PROVIDER_ID];\n}\n\nexport function serializeAiEnabledProviders(providerIds: string[]): string {\n return parseAiEnabledProviders(providerIds.join(',')).join(',');\n}\n\nexport function hasAiProviderConfig(config: Config, providerId: string): boolean {\n return getAiProviderConfigKeys(providerId).some((key) => {\n const value = config[key];\n return typeof value === 'string' && value.trim().length > 0;\n });\n}\n\nexport function getVoiceProviderDefinition(\n providerId: string,\n): VoiceProviderDefinition | undefined {\n return VOICE_PROVIDER_DEFINITIONS.find((provider) => provider.id === providerId);\n}\n\nexport function getVoiceProviderConfigKeys(providerId: string): string[] {\n const definition = getVoiceProviderDefinition(providerId);\n if (!definition) {\n return [];\n }\n\n const keys: string[] = [];\n if (definition.supportsApiKey) {\n keys.push(`voice.providers.${providerId}.apiKey`);\n }\n if (definition.supportsModel) {\n keys.push(`voice.providers.${providerId}.model`);\n }\n if (definition.supportsBaseUrl) {\n keys.push(`voice.providers.${providerId}.baseUrl`);\n }\n if (definition.supportsAzureDeployment) {\n keys.push(`voice.providers.${providerId}.azureDeployment`);\n }\n if (definition.supportsAzureApiVersion) {\n keys.push(`voice.providers.${providerId}.azureApiVersion`);\n }\n return keys;\n}\n\nexport function parseVoiceEnabledProviders(value: unknown): string[] {\n if (typeof value !== 'string') {\n return [DEFAULT_VOICE_PROVIDER_ID];\n }\n\n const providers = value\n .split(',')\n .map((item) => item.trim())\n .filter(\n (item, index, items) => item && items.indexOf(item) === index && VOICE_PROVIDER_IDS.has(item),\n );\n\n return providers.length > 0 ? providers : [DEFAULT_VOICE_PROVIDER_ID];\n}\n\nexport function serializeVoiceEnabledProviders(providerIds: string[]): string {\n return parseVoiceEnabledProviders(providerIds.join(',')).join(',');\n}\n\nexport function hasVoiceProviderConfig(config: Config, providerId: string): boolean {\n return getVoiceProviderConfigKeys(providerId).some((key) => {\n const value = config[key];\n return typeof value === 'string' && value.trim().length > 0;\n });\n}\n\nfunction getAiProviderPreferenceSchemas(): PreferenceSchema[] {\n const schemas: PreferenceSchema[] = [\n {\n key: 'ai.enabledProviders',\n label: 'Enabled Providers',\n description: 'Ordered list of configured AI providers.',\n type: 'string',\n default: DEFAULT_AI_PROVIDER_ID,\n category: 'AI',\n },\n {\n key: 'ai.defaultProvider',\n label: 'Default Provider',\n description: 'Provider selected by default for chat and tool execution.',\n type: 'string',\n default: DEFAULT_AI_PROVIDER_ID,\n options: AI_PROVIDER_DEFINITIONS.map((provider) => provider.id),\n category: 'AI',\n },\n ];\n\n for (const provider of AI_PROVIDER_DEFINITIONS) {\n schemas.push({\n key: `ai.providers.${provider.id}.model`,\n label: `${provider.label} Model`,\n description: `Model identifier to use when ${provider.label} is selected.`,\n type: 'string',\n default: '',\n category: 'AI',\n });\n\n if (provider.supportsApiKey) {\n schemas.push({\n key: `ai.providers.${provider.id}.apiKey`,\n label: `${provider.label} API Key`,\n description: `API key for ${provider.label}.`,\n type: 'string',\n default: '',\n category: 'AI',\n sensitive: true,\n });\n }\n\n if (provider.supportsBaseUrl) {\n schemas.push({\n key: `ai.providers.${provider.id}.baseUrl`,\n label: `${provider.label} Base URL`,\n description: `Optional custom API base URL for ${provider.label}.`,\n type: 'string',\n default: '',\n category: 'AI',\n });\n }\n }\n\n schemas.push({\n key: 'ai.maxTokens',\n label: 'Max Tokens',\n description: 'Maximum tokens per AI response.',\n type: 'number',\n default: 4096,\n min: 256,\n max: 128000,\n category: 'AI',\n });\n\n return schemas;\n}\n\nconst AI_PREFERENCE_SCHEMAS = getAiProviderPreferenceSchemas();\n\nfunction getVoiceProviderPreferenceSchemas(): PreferenceSchema[] {\n const schemas: PreferenceSchema[] = [\n {\n key: 'voice.enabledProviders',\n label: 'Enabled Providers',\n description: 'Ordered list of configured STT providers.',\n type: 'string',\n default: DEFAULT_VOICE_PROVIDER_ID,\n category: 'Voice',\n },\n {\n key: 'voice.defaultProvider',\n label: 'Default Provider',\n description: 'Provider selected by default for voice transcription.',\n type: 'string',\n default: DEFAULT_VOICE_PROVIDER_ID,\n options: VOICE_PROVIDER_DEFINITIONS.map((provider) => provider.id),\n category: 'Voice',\n },\n ];\n\n for (const provider of VOICE_PROVIDER_DEFINITIONS) {\n if (provider.supportsApiKey) {\n schemas.push({\n key: `voice.providers.${provider.id}.apiKey`,\n label: `${provider.label} API Key`,\n description: `API key for ${provider.label}.`,\n type: 'string',\n default: '',\n category: 'Voice',\n sensitive: true,\n });\n }\n\n if (provider.supportsModel) {\n schemas.push({\n key: `voice.providers.${provider.id}.model`,\n label: `${provider.label} Model`,\n description: `Model identifier to use when ${provider.label} is selected.`,\n type: 'string',\n default: 'whisper-1',\n category: 'Voice',\n });\n }\n\n if (provider.supportsBaseUrl) {\n schemas.push({\n key: `voice.providers.${provider.id}.baseUrl`,\n label: `${provider.label} Base URL`,\n description:\n provider.id === 'azure-openai-whisper'\n ? 'Base URL for Azure OpenAI Whisper requests.'\n : `Optional custom API base URL for ${provider.label}.`,\n type: 'string',\n default: provider.id === DEFAULT_VOICE_PROVIDER_ID ? 'https://api.openai.com/v1' : '',\n category: 'Voice',\n });\n }\n\n if (provider.supportsAzureDeployment) {\n schemas.push({\n key: `voice.providers.${provider.id}.azureDeployment`,\n label: `${provider.label} Deployment`,\n description: 'Azure OpenAI deployment name for Whisper transcription.',\n type: 'string',\n default: '',\n category: 'Voice',\n });\n }\n\n if (provider.supportsAzureApiVersion) {\n schemas.push({\n key: `voice.providers.${provider.id}.azureApiVersion`,\n label: `${provider.label} API Version`,\n description: 'Azure OpenAI API version used for transcription requests.',\n type: 'string',\n default: '2024-06-01',\n category: 'Voice',\n });\n }\n }\n\n return schemas;\n}\n\nconst VOICE_PREFERENCE_SCHEMAS = getVoiceProviderPreferenceSchemas();\n\nexport const PREFERENCE_SCHEMAS: PreferenceSchema[] = [\n // \u2500\u2500\u2500 General \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n key: 'general.theme',\n label: 'Theme',\n description: 'UI theme: light or dark.',\n type: 'string',\n default: 'light',\n options: ['light', 'dark'],\n category: 'General',\n },\n {\n key: 'general.accentColor',\n label: 'Accent Color',\n description: 'Primary theme color. Accepts hex values or any CSS color string.',\n type: 'string',\n default: '#7c6ff7',\n category: 'General',\n },\n {\n key: 'general.language',\n label: 'Language',\n description: 'UI language/locale.',\n type: 'string',\n default: 'en',\n options: ['en', 'zh'],\n category: 'General',\n },\n {\n key: 'general.dataDirectory',\n label: 'Data Directory',\n description:\n 'Override the base data directory. Leave empty for platform default (resolved via env-paths).',\n type: 'string',\n default: '',\n category: 'General',\n requiresRestart: true,\n },\n\n // \u2500\u2500\u2500 Server \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n key: 'server.host',\n label: 'Host',\n description: 'Server bind address.',\n type: 'string',\n default: 'localhost',\n category: 'Server',\n requiresRestart: true,\n },\n {\n key: 'server.port',\n label: 'Port',\n description: 'Server listen port.',\n type: 'number',\n default: 3000,\n min: 1,\n max: 65535,\n category: 'Server',\n requiresRestart: true,\n },\n\n // \u2500\u2500\u2500 AI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n ...AI_PREFERENCE_SCHEMAS,\n\n // \u2500\u2500\u2500 Voice \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n ...VOICE_PREFERENCE_SCHEMAS,\n {\n key: 'voice.silenceTimeoutMs',\n label: 'Silence Timeout',\n description: 'Silence duration (ms) before finalizing an utterance.',\n type: 'number',\n default: 800,\n min: 200,\n max: 5000,\n category: 'Voice',\n },\n {\n key: 'voice.energyThreshold',\n label: 'Energy Threshold',\n description: 'RMS energy threshold for voice activity detection (0\u201332767).',\n type: 'number',\n default: 500,\n min: 50,\n max: 10000,\n category: 'Voice',\n },\n];\n\n/** Build the default config from schemas */\nexport function getDefaultConfig(): Config {\n const config: Config = {};\n for (const schema of PREFERENCE_SCHEMAS) {\n config[schema.key] = schema.default;\n }\n return config;\n}\n\n/** Find schema by key */\nexport function getSchema(key: string): PreferenceSchema | undefined {\n return PREFERENCE_SCHEMAS.find((s) => s.key === key);\n}\n\n/** Get all schemas for a category */\nexport function getSchemasByCategory(category: string): PreferenceSchema[] {\n return PREFERENCE_SCHEMAS.filter((s) => s.category === category);\n}\n\n/** Mask a sensitive value \u2014 show only last 4 characters */\nexport function maskSensitive(value: string): string {\n if (value.length <= 4) return '****';\n return '*'.repeat(value.length - 4) + value.slice(-4);\n}\n", "import type { MiniAppManifest, MiniAppContext, MiniAppBackendActivation } from '@desktalk/sdk';\nimport type { Config } from './schema';\nimport {\n PREFERENCE_SCHEMAS,\n DEFAULT_AI_PROVIDER_ID,\n DEFAULT_VOICE_PROVIDER_ID,\n getDefaultConfig,\n getSchema,\n hasAiProviderConfig,\n hasVoiceProviderConfig,\n maskSensitive,\n parseAiEnabledProviders,\n parseVoiceEnabledProviders,\n serializeAiEnabledProviders,\n serializeVoiceEnabledProviders,\n} from './schema';\n\n// \u2500\u2500\u2500 Manifest \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const manifest: MiniAppManifest = {\n id: 'preference',\n name: 'Preferences',\n icon: '\\u2699\\uFE0F',\n version: '0.1.0',\n description: 'Application settings and configuration',\n};\n\n// \u2500\u2500\u2500 Activate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * The Preference MiniApp uses ctx.storage as the persistence layer for settings.\n * In production, the core would provide a privileged ctx.config hook that writes\n * to <config>/config.toml. For now, ctx.storage serves as the backing store.\n *\n * All settings are stored under the key \"config\" as a flat Config object.\n */\nexport function activate(ctx: MiniAppContext): MiniAppBackendActivation {\n ctx.logger.info('Preference MiniApp activated');\n\n const defaults = getDefaultConfig();\n\n /** Load the persisted config, merging with defaults for any missing keys. */\n async function loadConfig(): Promise<Config> {\n const stored = await ctx.storage.get<Config>('config');\n const config = { ...defaults, ...(stored ?? {}) };\n\n const legacyProvider =\n typeof stored?.['ai.provider'] === 'string' ? stored['ai.provider'] : undefined;\n if (legacyProvider && typeof stored?.['ai.defaultProvider'] !== 'string') {\n config['ai.defaultProvider'] = legacyProvider;\n }\n\n if (legacyProvider) {\n const legacyModel = typeof stored?.['ai.model'] === 'string' ? stored['ai.model'] : undefined;\n const legacyApiKey =\n typeof stored?.['ai.apiKey'] === 'string' ? stored['ai.apiKey'] : undefined;\n const legacyBaseUrl =\n typeof stored?.['ai.baseUrl'] === 'string' ? stored['ai.baseUrl'] : undefined;\n\n const providerModelKey = `ai.providers.${legacyProvider}.model`;\n const providerApiKeyKey = `ai.providers.${legacyProvider}.apiKey`;\n const providerBaseUrlKey = `ai.providers.${legacyProvider}.baseUrl`;\n\n if (legacyModel && !config[providerModelKey]) {\n config[providerModelKey] = legacyModel;\n }\n if (legacyApiKey && !config[providerApiKeyKey]) {\n config[providerApiKeyKey] = legacyApiKey;\n }\n if (legacyBaseUrl && !config[providerBaseUrlKey]) {\n config[providerBaseUrlKey] = legacyBaseUrl;\n }\n }\n\n const enabledProviders = parseAiEnabledProviders(stored?.['ai.enabledProviders']);\n const derivedProviders = enabledProviders.filter((providerId) =>\n hasAiProviderConfig(config, providerId),\n );\n for (const schema of PREFERENCE_SCHEMAS) {\n if (!schema.key.startsWith('ai.providers.')) {\n continue;\n }\n\n const match = /^ai\\.providers\\.([^.]+)\\./.exec(schema.key);\n const providerId = match?.[1];\n if (\n providerId &&\n hasAiProviderConfig(config, providerId) &&\n !derivedProviders.includes(providerId)\n ) {\n derivedProviders.push(providerId);\n }\n }\n\n const defaultProvider =\n typeof config['ai.defaultProvider'] === 'string' && config['ai.defaultProvider']\n ? String(config['ai.defaultProvider'])\n : DEFAULT_AI_PROVIDER_ID;\n\n if (!derivedProviders.includes(defaultProvider)) {\n derivedProviders.unshift(defaultProvider);\n }\n\n for (const providerId of enabledProviders) {\n if (!derivedProviders.includes(providerId)) {\n derivedProviders.push(providerId);\n }\n }\n\n config['ai.enabledProviders'] = serializeAiEnabledProviders(derivedProviders);\n config['ai.defaultProvider'] = derivedProviders[0] ?? DEFAULT_AI_PROVIDER_ID;\n\n const legacyVoiceProvider =\n typeof stored?.['voice.provider'] === 'string' ? stored['voice.provider'] : undefined;\n if (legacyVoiceProvider && typeof stored?.['voice.defaultProvider'] !== 'string') {\n config['voice.defaultProvider'] = legacyVoiceProvider;\n }\n\n if (legacyVoiceProvider) {\n const legacyVoiceApiKey =\n typeof stored?.['voice.apiKey'] === 'string' ? stored['voice.apiKey'] : undefined;\n const legacyVoiceModel =\n typeof stored?.['voice.model'] === 'string' ? stored['voice.model'] : undefined;\n const legacyVoiceBaseUrl =\n typeof stored?.['voice.baseUrl'] === 'string' ? stored['voice.baseUrl'] : undefined;\n const legacyVoiceDeployment =\n typeof stored?.['voice.azureDeployment'] === 'string'\n ? stored['voice.azureDeployment']\n : undefined;\n const legacyVoiceApiVersion =\n typeof stored?.['voice.azureApiVersion'] === 'string'\n ? stored['voice.azureApiVersion']\n : undefined;\n\n if (legacyVoiceApiKey && !config[`voice.providers.${legacyVoiceProvider}.apiKey`]) {\n config[`voice.providers.${legacyVoiceProvider}.apiKey`] = legacyVoiceApiKey;\n }\n if (legacyVoiceModel && !config[`voice.providers.${legacyVoiceProvider}.model`]) {\n config[`voice.providers.${legacyVoiceProvider}.model`] = legacyVoiceModel;\n }\n if (legacyVoiceBaseUrl && !config[`voice.providers.${legacyVoiceProvider}.baseUrl`]) {\n config[`voice.providers.${legacyVoiceProvider}.baseUrl`] = legacyVoiceBaseUrl;\n }\n if (\n legacyVoiceDeployment &&\n !config[`voice.providers.${legacyVoiceProvider}.azureDeployment`]\n ) {\n config[`voice.providers.${legacyVoiceProvider}.azureDeployment`] = legacyVoiceDeployment;\n }\n if (\n legacyVoiceApiVersion &&\n !config[`voice.providers.${legacyVoiceProvider}.azureApiVersion`]\n ) {\n config[`voice.providers.${legacyVoiceProvider}.azureApiVersion`] = legacyVoiceApiVersion;\n }\n }\n\n const enabledVoiceProviders = parseVoiceEnabledProviders(stored?.['voice.enabledProviders']);\n const derivedVoiceProviders = enabledVoiceProviders.filter((providerId) =>\n hasVoiceProviderConfig(config, providerId),\n );\n for (const schema of PREFERENCE_SCHEMAS) {\n if (!schema.key.startsWith('voice.providers.')) {\n continue;\n }\n\n const match = /^voice\\.providers\\.([^.]+)\\./.exec(schema.key);\n const providerId = match?.[1];\n if (\n providerId &&\n hasVoiceProviderConfig(config, providerId) &&\n !derivedVoiceProviders.includes(providerId)\n ) {\n derivedVoiceProviders.push(providerId);\n }\n }\n\n const defaultVoiceProvider =\n typeof config['voice.defaultProvider'] === 'string' && config['voice.defaultProvider']\n ? String(config['voice.defaultProvider'])\n : DEFAULT_VOICE_PROVIDER_ID;\n\n if (!derivedVoiceProviders.includes(defaultVoiceProvider)) {\n derivedVoiceProviders.unshift(defaultVoiceProvider);\n }\n\n for (const providerId of enabledVoiceProviders) {\n if (!derivedVoiceProviders.includes(providerId)) {\n derivedVoiceProviders.push(providerId);\n }\n }\n\n config['voice.enabledProviders'] = serializeVoiceEnabledProviders(derivedVoiceProviders);\n config['voice.defaultProvider'] = derivedVoiceProviders[0] ?? DEFAULT_VOICE_PROVIDER_ID;\n\n return config;\n }\n\n /** Persist the config to storage. */\n async function saveConfig(config: Config): Promise<void> {\n await ctx.storage.set('config', config);\n }\n\n /**\n * Mask sensitive values in the config for API responses.\n * The raw value is stored internally; only the masked version is returned.\n */\n function maskConfig(config: Config): Config {\n const masked = { ...config };\n for (const schema of PREFERENCE_SCHEMAS) {\n if (schema.sensitive && typeof masked[schema.key] === 'string') {\n const raw = masked[schema.key] as string;\n masked[schema.key] = raw ? maskSensitive(raw) : '';\n }\n }\n return masked;\n }\n\n // \u2500\u2500\u2500 preferences.getAll \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<void, Config>('preferences.getAll', async () => {\n const config = await loadConfig();\n return maskConfig(config);\n });\n\n // \u2500\u2500\u2500 preferences.get \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<{ key: string }, { value: string | number | boolean }>(\n 'preferences.get',\n async (req) => {\n const config = await loadConfig();\n const schema = getSchema(req.key);\n let value = config[req.key] ?? defaults[req.key];\n\n if (value === undefined) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n // Mask sensitive values\n if (schema?.sensitive && typeof value === 'string' && value) {\n value = maskSensitive(value);\n }\n\n return { value };\n },\n );\n\n // \u2500\u2500\u2500 preferences.getRaw (internal \u2014 returns unmasked values for backend use)\n\n ctx.messaging.onCommand<{ key: string }, { value: string | number | boolean }>(\n 'preferences.getRaw',\n async (req) => {\n const config = await loadConfig();\n const value = config[req.key] ?? defaults[req.key];\n\n if (value === undefined) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n return { value };\n },\n );\n\n // \u2500\u2500\u2500 preferences.set \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<{ key: string; value: string | number | boolean }, void>(\n 'preferences.set',\n async (req) => {\n const schema = getSchema(req.key);\n if (!schema) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n // Type validation\n if (typeof req.value !== schema.type) {\n throw new Error(`Expected ${schema.type} for ${req.key}, got ${typeof req.value}`);\n }\n\n // Range validation for numbers\n if (schema.type === 'number' && typeof req.value === 'number') {\n if (schema.min !== undefined && req.value < schema.min) {\n throw new Error(`${req.key} must be >= ${schema.min}`);\n }\n if (schema.max !== undefined && req.value > schema.max) {\n throw new Error(`${req.key} must be <= ${schema.max}`);\n }\n }\n\n // Enum validation for string options\n if (schema.options && typeof req.value === 'string') {\n if (!schema.options.includes(req.value)) {\n throw new Error(`${req.key} must be one of: ${schema.options.join(', ')}`);\n }\n }\n\n const config = await loadConfig();\n config[req.key] = req.value;\n await saveConfig(config);\n\n ctx.logger.info(`Setting updated: ${req.key}`);\n\n // Emit change event so frontend can react\n ctx.messaging.emit('preferences:changed', {\n key: req.key,\n value: schema.sensitive ? maskSensitive(String(req.value)) : req.value,\n requiresRestart: schema.requiresRestart ?? false,\n });\n },\n );\n\n // \u2500\u2500\u2500 preferences.reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<{ key: string }, void>('preferences.reset', async (req) => {\n const schema = getSchema(req.key);\n if (!schema) {\n throw new Error(`Unknown preference key: ${req.key}`);\n }\n\n const config = await loadConfig();\n config[req.key] = schema.default;\n await saveConfig(config);\n\n ctx.logger.info(`Setting reset: ${req.key}`);\n\n ctx.messaging.emit('preferences:changed', {\n key: req.key,\n value: schema.default,\n requiresRestart: schema.requiresRestart ?? false,\n });\n });\n\n // \u2500\u2500\u2500 preferences.resetAll \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n ctx.messaging.onCommand<void, void>('preferences.resetAll', async () => {\n await saveConfig({ ...defaults });\n ctx.logger.info('All settings reset to defaults');\n\n ctx.messaging.emit('preferences:resetAll', {});\n });\n\n return {};\n}\n\n// \u2500\u2500\u2500 Deactivate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function deactivate(): void {\n // cleanup\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|