@mastra/code-sdk 1.15.0-alpha.11 → 1.15.0-alpha.12
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/acp/agent.js +2 -1
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +0 -2
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp.js +1 -2
- package/dist/agent-connections/registry.js.map +1 -1
- package/dist/agent-connections/signal-provider.js.map +1 -1
- package/dist/agent-connections/state-processor.js.map +1 -1
- package/dist/agent-connections/tools.js +26 -24
- package/dist/agent-connections/tools.js.map +1 -1
- package/dist/agents/instructions.js +3 -2
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +35 -27
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.d.ts.map +1 -1
- package/dist/agents/memory.js +16 -2
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +1 -1
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/index.js +3 -2
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/plan.js +2 -1
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/sandbox-filesystem.d.ts +28 -0
- package/dist/agents/sandbox-filesystem.d.ts.map +1 -1
- package/dist/agents/sandbox-filesystem.js +81 -2
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/tools.d.ts.map +1 -1
- package/dist/agents/tools.js +18 -12
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +2 -1
- package/dist/agents/workspace.js.map +1 -1
- package/dist/auth/account-rotation-processor.js +2 -1
- package/dist/auth/account-rotation-processor.js.map +1 -1
- package/dist/auth/providers/anthropic.js +2 -2
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +1 -1
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +3 -2
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +1 -1
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/clipboard/index.js +5 -4
- package/dist/clipboard/index.js.map +1 -1
- package/dist/evals/context-builder.js +1 -3
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/scorers/outcome.js +2 -1
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/factory/remote-controller.js.map +1 -1
- package/dist/factory/remote-session.js +1 -3
- package/dist/factory/remote-session.js.map +1 -1
- package/dist/headless/cli.js +2 -1
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/run-mc.js +9 -9
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/hooks/executor.js +3 -1
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/manager.js +40 -26
- package/dist/hooks/manager.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -10
- package/dist/index.js.map +1 -1
- package/dist/knowledge-inspector.js +2 -2
- package/dist/knowledge-inspector.js.map +1 -1
- package/dist/lsp/server.js +4 -2
- package/dist/lsp/server.js.map +1 -1
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +14 -2
- package/dist/mcp/manager.js.map +1 -1
- package/dist/onboarding/settings.js +5 -2
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/platform/index.js +5 -3
- package/dist/platform/index.js.map +1 -1
- package/dist/plugins/loader.js +3 -1
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +2 -1
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/scaffold.js +4 -2
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/signal-lane.js.map +1 -1
- package/dist/process-memory-diagnostics.js +2 -1
- package/dist/process-memory-diagnostics.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +2 -1
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +2 -2
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +13 -9
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot-gateway.js.map +1 -1
- package/dist/providers/github-copilot.js +13 -12
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +14 -11
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/provider-thinking.js.map +1 -1
- package/dist/schedules/run-script.js +1 -1
- package/dist/schedules/run-script.js.map +1 -1
- package/dist/schedules/scheduler.js.map +1 -1
- package/dist/tools/request-sandbox-access.js +7 -5
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +3 -1
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.d.ts +13 -11
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +21 -15
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/debug-log.js +2 -2
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/gateway-sync.js +1 -1
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/local-observability.d.ts +1 -1
- package/dist/utils/local-observability.d.ts.map +1 -1
- package/dist/utils/local-observability.js +1 -1
- package/dist/utils/local-observability.js.map +1 -1
- package/dist/utils/prune-cli.js +10 -8
- package/dist/utils/prune-cli.js.map +1 -1
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-processor.js +1 -1
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +1 -1
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.d.ts.map +1 -1
- package/dist/utils/storage-factory.js +1 -1
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +1 -1
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/update-check.js +2 -1
- package/dist/utils/update-check.js.map +1 -1
- package/dist/workflows/register-primitives.js +1 -1
- package/dist/workflows/register-primitives.js.map +1 -1
- package/package.json +12 -12
|
@@ -488,7 +488,9 @@ function parseVoiceSettings(rawVoice) {
|
|
|
488
488
|
const raw = rawVoice && typeof rawVoice === "object" ? rawVoice : {};
|
|
489
489
|
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : DEFAULTS.voice.enabled;
|
|
490
490
|
const engine = raw.engine === "macos-native" || raw.engine === "cloud" ? raw.engine : defaultVoiceEngine();
|
|
491
|
-
const
|
|
491
|
+
const provider = typeof raw.provider === "string" ? raw.provider : DEFAULTS.voice.provider;
|
|
492
|
+
const model = typeof raw.model === "string" ? raw.model : void 0;
|
|
493
|
+
const resolved = resolveSTTModel(provider, model);
|
|
492
494
|
return {
|
|
493
495
|
enabled,
|
|
494
496
|
engine,
|
|
@@ -848,9 +850,10 @@ function getSignalSettingsForSave(settings, filePath) {
|
|
|
848
850
|
function writeFileAtomically(filePath, content) {
|
|
849
851
|
const tempPath = `${filePath}.${process.pid}.${globalThis.crypto.randomUUID()}.tmp`;
|
|
850
852
|
try {
|
|
853
|
+
const mode = existsSync(filePath) ? statSync(filePath).mode & 511 : 384;
|
|
851
854
|
writeFileSync(tempPath, content, {
|
|
852
855
|
encoding: "utf-8",
|
|
853
|
-
mode
|
|
856
|
+
mode
|
|
854
857
|
});
|
|
855
858
|
renameSync(tempPath, filePath);
|
|
856
859
|
} finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","names":["resolveThinkingDefault"],"sources":["../../src/onboarding/settings.ts"],"sourcesContent":["/**\n * Persistent global settings stored in the app data directory as settings.json.\n * This file persists onboarding state AND user preferences (model choices, yolo, etc.)\n * so they carry across threads and restarts.\n */\n\nimport { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { OMModel } from '@mastra/core/agent-controller';\nimport type { MastraBrowser } from '@mastra/core/browser';\nimport type { LSPConfig } from '@mastra/core/workspace';\nimport { AuthStorage, PROVIDER_DEFAULT_MODELS } from '../auth/storage.js';\nimport {\n ANTHROPIC_PREFIX,\n normalizeAnthropicModelId,\n OPENAI_PREFIX,\n remapOpenAIModelForCodexOAuth,\n stripMastraGatewayPrefix,\n} from '../providers/model-ids.js';\nimport { buildCodexStagehandFetch, createCodexMiddleware } from '../providers/openai-codex.js';\nimport {\n isThinkingLevelSetting,\n resolveDefaultThinkingLevel as resolveThinkingDefault,\n THINKING_LEVEL_VALUES,\n} from '../thinking.js';\nimport type { ThinkingLevelSetting, ThinkingLevelSource } from '../thinking.js';\nexport { isThinkingLevelSetting, THINKING_LEVEL_VALUES } from '../thinking.js';\nexport type { ThinkingLevelSetting, ThinkingLevelSource } from '../thinking.js';\nimport { getAppDataDir } from '../utils/project.js';\nimport { DEFAULT_STT_PROVIDER, resolveSTTModel } from '../voice/stt-registry.js';\nimport { pruneUnknownModePackFallbacks, pruneUnknownPackAccountPreferences } from './packs.js';\n\n/** A saved custom pack — user-defined model selections for each mode. */\nexport interface CustomPack {\n name: string;\n models: Record<string, string>;\n createdAt: string;\n}\n\n/** A saved custom provider for OpenAI-compatible endpoints. */\nexport interface CustomProviderSetting {\n name: string;\n url: string;\n apiKey?: string;\n models: string[];\n}\n\n/** Storage backend type. */\nexport type StorageBackend = 'libsql' | 'pg';\n\n/** Experimental agent implementation used by MastraCode. */\nexport type ExperimentalAgent = 'durable' | 'evented';\n\nexport class ExperimentalAgentSettingsError extends Error {\n readonly value: unknown;\n\n constructor(value: unknown, settingsPath?: string) {\n super(\n `Invalid \"experimentalAgent\" setting${settingsPath ? ` in ${settingsPath}` : ''}: ${JSON.stringify(value)}. ` +\n `Remove the \"experimentalAgent\" key or set it to \"durable\", \"evented\", or null.`,\n );\n this.name = 'ExperimentalAgentSettingsError';\n this.value = value;\n }\n}\n\n/** LibSQL-specific storage settings. */\nexport interface LibSQLStorageSettings {\n url?: string;\n authToken?: string;\n}\n\n/** PostgreSQL-specific storage settings. */\nexport interface PgStorageSettings {\n connectionString?: string;\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n password?: string;\n schemaName?: string;\n disableInit?: boolean;\n skipDefaultIndexes?: boolean;\n}\n\n/** Storage configuration persisted in global settings. */\nexport interface StorageSettings {\n /** Which backend to use. Default: 'libsql'. */\n backend: StorageBackend;\n /** LibSQL-specific config (used when backend is 'libsql'). */\n libsql: LibSQLStorageSettings;\n /** PostgreSQL-specific config (used when backend is 'pg'). */\n pg: PgStorageSettings;\n}\n\n/** Gateway provider key used in AuthStorage. */\nexport const MASTRA_GATEWAY_PROVIDER = 'mastra-gateway';\n\n/** Default gateway URL. */\nexport const MASTRA_GATEWAY_DEFAULT_URL = 'https://gateway-api.mastra.ai';\n\n/** @deprecated Renamed to {@link MASTRA_GATEWAY_PROVIDER}. */\nexport const MEMORY_GATEWAY_PROVIDER = MASTRA_GATEWAY_PROVIDER;\n\n/** @deprecated Renamed to {@link MASTRA_GATEWAY_DEFAULT_URL}. */\nexport const MEMORY_GATEWAY_DEFAULT_URL = MASTRA_GATEWAY_DEFAULT_URL;\n\n/** Preferred model-independent web search/extract provider. */\nexport type WebSearchProviderSetting = 'auto' | 'tavily' | 'parallel';\n\n/** Browser provider type. */\nexport type BrowserProvider = 'stagehand' | 'agent-browser';\n\n/** Direct TUI `!` shell passthrough mode. */\nexport type ShellPassthroughSettingsMode = 'default' | 'path' | 'login';\n\n/** Direct TUI `!` shell command language. */\nexport type ShellPassthroughSettingsFamily = 'posix' | 'cmd' | 'powershell';\n\n/** Direct TUI `!` shell passthrough configuration. */\nexport interface ShellPassthroughSettings {\n mode?: ShellPassthroughSettingsMode | string;\n executable?: string;\n family?: ShellPassthroughSettingsFamily | string;\n}\n\n/** STT engine: on-device macOS recognizer or a cloud provider. */\nexport type VoiceEngine = 'macos-native' | 'cloud';\n\n/** Voice (hold-space dictation) configuration persisted in global settings. */\nexport interface VoiceSettings {\n /** Whether hold-space voice input is enabled. */\n enabled: boolean;\n /** Which STT engine to use. Defaults to macOS native on darwin, else cloud. */\n engine: VoiceEngine;\n /** Cloud provider id (matches an STT registry entry). Cloud engine only. */\n provider: string;\n /** Cloud model id; defaults to the provider's first registry model. */\n model?: string;\n}\n\n/** Stagehand environment type. */\nexport type StagehandEnv = 'LOCAL' | 'BROWSERBASE';\n\n/**\n * Browser viewport: explicit dimensions, or `'window'` to follow the real\n * browser window instead of emulating a fixed size.\n */\nexport type BrowserViewport = { width: number; height: number } | 'window';\n\n/** Named viewport sizes offered by `/browser set viewport`. */\nexport const VIEWPORT_PRESETS = {\n desktop: { width: 1280, height: 720 },\n 'desktop-hd': { width: 1920, height: 1080 },\n laptop: { width: 1440, height: 900 },\n tablet: { width: 768, height: 1024 },\n mobile: { width: 390, height: 844 },\n} as const satisfies Record<string, { width: number; height: number }>;\n\nexport type ViewportPreset = keyof typeof VIEWPORT_PRESETS;\n\n/**\n * Largest viewport dimension accepted. Guards against typos that would launch a\n * browser far larger than any display.\n */\nconst MAX_VIEWPORT_DIMENSION = 10000;\n\nfunction isValidDimension(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 && value <= MAX_VIEWPORT_DIMENSION;\n}\n\n/**\n * Parse a `WIDTHxHEIGHT` string (e.g. `1280x720`), a preset name, or `window`.\n * Returns undefined when the input is not a usable viewport.\n */\nexport function parseViewportInput(input: string): BrowserViewport | undefined {\n const value = input.trim().toLowerCase();\n if (!value) return undefined;\n if (value === 'window') return 'window';\n if (value in VIEWPORT_PRESETS) return { ...VIEWPORT_PRESETS[value as ViewportPreset] };\n\n const match = /^(\\d+)\\s*[x×]\\s*(\\d+)$/.exec(value);\n if (!match) return undefined;\n const width = Number(match[1]);\n const height = Number(match[2]);\n if (!isValidDimension(width) || !isValidDimension(height)) return undefined;\n return { width, height };\n}\n\n/** Stagehand-specific browser settings. */\nexport interface StagehandSettings {\n env: StagehandEnv;\n apiKey?: string;\n projectId?: string;\n /**\n * Model Stagehand uses for its AI operations, as `provider/model`\n * (for example `anthropic/claude-sonnet-4-5`). Stagehand resolves the\n * provider's API key from the environment (`ANTHROPIC_API_KEY`,\n * `OPENAI_API_KEY`, and so on). Defaults to Stagehand's own default.\n */\n model?: string;\n /** Whether to preserve the user data directory after the browser closes. */\n preserveUserDataDir?: boolean;\n}\n\n/** AgentBrowser-specific browser settings. */\nexport interface AgentBrowserSettings {\n /** Path to a Playwright storage state file (JSON) containing cookies and localStorage. */\n storageState?: string;\n}\n\n/** Browser configuration persisted in global settings. */\nexport interface BrowserSettings {\n /** Whether browser automation is enabled. */\n enabled: boolean;\n /** Which browser provider to use. */\n provider: BrowserProvider;\n /** Whether to run headless (no visible browser window). */\n headless: boolean;\n /**\n * Browser viewport dimensions, or `'window'` to disable viewport emulation so\n * the page follows the real browser window.\n */\n viewport?: BrowserViewport;\n /** CDP URL for connecting to an existing browser. */\n cdpUrl?: string;\n /** Path to a Chrome/Chromium user data directory (profile). */\n profile?: string;\n /** Path to the browser executable to use. */\n executablePath?: string;\n /** Browser scope — 'shared' (all threads share one browser) or 'thread' (each thread gets its own). */\n scope?: 'shared' | 'thread';\n /** Stagehand-specific settings. */\n stagehand?: StagehandSettings;\n /** AgentBrowser-specific settings. */\n agentBrowser?: AgentBrowserSettings;\n}\n\nexport type PackAccountPreferences = Record<string, Record<string, string>>;\n\nexport interface GlobalSettings {\n // Onboarding tracking\n onboarding: {\n completedAt: string | null;\n skippedAt: string | null;\n version: number;\n modePackId: string | null;\n omPackId: string | null;\n };\n // Global model preferences (applied to new threads)\n models: {\n /**\n * Active model pack ID. Built-in packs use their id directly (\"anthropic\",\n * \"openai\"). Custom packs use \"custom:<name>\".\n * When set, models are resolved from the pack at startup so pack updates\n * (e.g. new model versions) apply automatically. Built-in packs may layer\n * explicit modePackOverrides over these defaults.\n */\n activeModelPackId: string | null;\n /** Per-mode overrides keyed by built-in pack ID. */\n modePackOverrides: Record<string, Record<string, string>>;\n /**\n * Fallback pack per pack ID (packId → packId; builtin ids and\n * \"custom:<name>\" both allowed). When every account serving a pack's\n * provider is exhausted — or the provider is persistently down — the turn\n * hops to the fallback pack's model. Chains are allowed; a cycle is\n * capped at one revisit per cascade, then the error surfaces.\n */\n packFallbacks: Record<string, string>;\n /** Preferred OAuth account by pack ID and resolved model ID. */\n packAccountPreferences: Record<string, Record<string, string>>;\n /** Explicit per-mode defaults — used when no activeModelPackId is set. */\n modeDefaults: Record<string, string>;\n /**\n * Per-mode reasoning-effort defaults (e.g. { build: \"high\", plan: \"xhigh\" }).\n * Resolved at request time; falls back to `preferences.thinkingLevel` for\n * modes without an entry. Overridden per-session via /think or the session\n * settings panel.\n */\n modeThinkingDefaults: Record<string, ThinkingLevelSetting>;\n /**\n * Active OM pack ID (e.g. \"gemini\", \"anthropic\", \"custom\").\n * When set, the OM model is resolved from the pack at startup so pack\n * updates (e.g. new model versions) apply automatically.\n * Cleared when the user manually overrides via /om (falls back to omModelOverride).\n */\n activeOmPackId: string | null;\n /**\n * Shared OM model override — used for both observer and reflector when a\n * role-specific override is not set. Kept for back-compat with older settings\n * files and set by onboarding when the user picks a custom OM pack.\n */\n omModelOverride: string | null;\n /**\n * Explicit Observer model override — takes precedence over `omModelOverride`\n * when set. Written by `/om` when the observer model is changed independently.\n */\n observerModelOverride: string | null;\n /** Persisted Observer model intent. Missing values use legacy-field compatibility. */\n observerModelSelection: OMModel | null;\n /**\n * Explicit Reflector model override — takes precedence over `omModelOverride`\n * when set. Written by `/om` when the reflector model is changed independently.\n */\n reflectorModelOverride: string | null;\n /** Persisted Reflector model intent. Missing values use legacy-field compatibility. */\n reflectorModelSelection: OMModel | null;\n /** Default OM observation threshold used for new threads unless overridden per-thread. */\n omObservationThreshold: number | null;\n /** Default OM reflection threshold used for new threads unless overridden per-thread. */\n omReflectionThreshold: number | null;\n /**\n * Whether observations and reflections use the terse caveman-style instruction.\n * `null` means inherit the built-in default (currently `false` — caveman is\n * opt-in via `/om` settings). Used as the default for new threads unless\n * overridden per-thread.\n */\n omCavemanObservations: boolean | null;\n /**\n * Whether Observational Memory forwards image/file attachment parts to the\n * Observer LLM. `null` ⇒ inherit built-in default ('auto'). 'auto' checks\n * model capabilities; true/false forces the setting.\n */\n omObserveAttachments: 'auto' | boolean | null;\n /** Per-agent-type subagent model overrides (e.g. { explore: \"openai/gpt-5.1-codex-mini\" }) */\n subagentModels: Record<string, string>;\n /** Default judge model for /goal. */\n goalJudgeModel: string | null;\n /** Default max attempts for /goal. */\n goalMaxTurns: number | null;\n };\n // Global behavior preferences\n preferences: {\n yolo: boolean | null;\n /** 'auto' | 'dark' | 'light', or the name of a custom theme file in ~/.mastracode/themes/<name>.json */\n theme: 'auto' | 'dark' | 'light' | (string & {});\n /** Default reasoning effort level used for all threads/models unless overridden in-session. */\n thinkingLevel: ThinkingLevelSetting;\n /** Whether native subagents are enabled for Mastra Code TUI sessions. */\n subagentsEnabled: boolean;\n /** Maximum detail preview lines shown under compact tool calls (0-8). Set to 0 to hide previews. */\n previewLines: number;\n /**\n * Default web search/extract provider. `auto` picks the first configured\n * provider key (Tavily, then Parallel). An explicit provider is only\n * honored while its API key is configured.\n */\n webSearchProvider: WebSearchProviderSetting;\n };\n // Storage backend configuration\n storage: StorageSettings;\n // User-created custom model packs\n customModelPacks: CustomPack[];\n // User-created custom providers with custom models\n customProviders: CustomProviderSetting[];\n // Model usage counts for ranking in the selector\n modelUseCounts: Record<string, number>;\n // Version the user dismissed the update prompt for (skip until they manually update past this)\n updateDismissedVersion: string | null;\n // Mastra gateway configuration\n memoryGateway: { baseUrl?: string };\n // LSP configuration forwarded to the workspace. Disabled unless the user\n // opts in with `true` or an LSPConfig object.\n lsp?: boolean | LSPConfig;\n // Browser automation configuration\n browser: BrowserSettings;\n // Direct TUI `!` shell passthrough configuration\n shellPassthrough: ShellPassthroughSettings;\n // Hold-space voice input configuration\n voice: VoiceSettings;\n // Raw persisted experimental agent value. Resolve through resolveExperimentalAgent() before use.\n experimentalAgent: unknown;\n // Internal load diagnostic retained on clones until the user repairs the setting.\n _experimentalAgentSettingsPath?: string;\n // Native background execution for eligible Mastra Code tools\n backgroundTools: BackgroundToolSettings;\n // Signal routing configuration\n signals: SignalSettings;\n // Read-only discovery of MCP servers configured by other coding agents\n mcp: McpDiscoverySettings;\n // Cloud observability configuration (per-resource project IDs; tokens stored in auth.json)\n observability: ObservabilitySettings;\n // Remote Factory connection selected via /factory (null = run locally)\n factory: FactoryConnectionSettings | null;\n}\n\nexport interface FactoryConnectionSettings {\n url: string;\n orgId: string;\n projectId: string;\n projectName: string;\n environmentId: string;\n environmentName: string;\n factoryProjectId: string;\n factoryProjectName: string;\n projectRepositoryId: string;\n repositorySlug: string;\n /** Factory user session ID; addresses the remote agent-controller session as its resourceId. */\n sessionId: string;\n branch: string;\n /** False keeps the connection saved but starts Mastra Code locally. */\n active?: boolean;\n}\n\nfunction parseFactoryConnectionSettings(raw: unknown): FactoryConnectionSettings | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const keys = [\n 'url',\n 'orgId',\n 'projectId',\n 'projectName',\n 'environmentId',\n 'environmentName',\n 'factoryProjectId',\n 'factoryProjectName',\n 'projectRepositoryId',\n 'repositorySlug',\n 'sessionId',\n 'branch',\n ] as const;\n if (!keys.every(key => typeof obj[key] === 'string' && obj[key])) return null;\n const parsed = Object.fromEntries(keys.map(key => [key, obj[key]])) as unknown as FactoryConnectionSettings;\n if (obj.active === false) parsed.active = false;\n return parsed;\n}\n\nexport interface McpDiscoverySettings {\n /** Reuse top-level MCP servers from ~/.claude.json. */\n claudeCodeGlobal: boolean;\n /** Reuse MCP servers from $CODEX_HOME/config.toml or ~/.codex/config.toml. */\n codexGlobal: boolean;\n}\n\nexport interface BackgroundToolSettings {\n /** Allow eligible Mastra Code tools to accept per-call background execution overrides. */\n enabled: boolean;\n}\n\nexport interface SignalSettings {\n /** Opt into local Unix socket PubSub for cross-process signal routing. */\n unixSocketPubSub: boolean;\n /** Experimental: enable GitHub PR subscription signals backed by gitcrawl. */\n experimentalGithubSignals: boolean;\n /** Experimental: enable cross-agent communication (thread ownership advertisement, peer discovery, and agent connection tools). */\n experimentalCrossAgentSignals: boolean;\n /** Experimental: give the agent tools to create and manage `/schedules` schedules on its thread. */\n experimentalScheduleTools: boolean;\n /** Poll interval for GitHub PR subscriptions. */\n githubPollIntervalMs: number;\n}\n\nexport interface ObservabilityResourceConfig {\n /** Cloud project ID for this resource */\n projectId: string;\n /** When this config was created */\n configuredAt: string;\n}\n\nexport interface ObservabilitySettings {\n /** Per-resource cloud project configs, keyed by resourceId */\n resources: Record<string, ObservabilityResourceConfig>;\n /** Whether to store traces locally in DuckDB. Off by default to avoid disk usage. */\n localTracing: boolean;\n}\n\n/** Auth key prefix for observability tokens stored per-resource in auth.json */\nexport const OBSERVABILITY_AUTH_PREFIX = 'observability:';\n\nexport const GITHUB_POLL_INTERVAL_DEFAULT_MS = 300_000;\nexport const GITHUB_POLL_INTERVAL_MIN_MS = 10_000;\nexport const GITHUB_POLL_INTERVAL_MAX_MS = 2_147_483_647;\n\nexport const STORAGE_DEFAULTS: StorageSettings = {\n backend: 'libsql',\n libsql: {},\n pg: {},\n};\n\n/** Default STT engine: on-device macOS recognizer where available, else cloud. */\nexport function defaultVoiceEngine(): VoiceEngine {\n return process.platform === 'darwin' ? 'macos-native' : 'cloud';\n}\n\nconst DEFAULTS: GlobalSettings = {\n onboarding: {\n completedAt: null,\n skippedAt: null,\n version: 0,\n modePackId: null,\n omPackId: null,\n },\n models: {\n activeModelPackId: null,\n modePackOverrides: {},\n packFallbacks: {},\n packAccountPreferences: {},\n modeDefaults: {},\n modeThinkingDefaults: {},\n activeOmPackId: null,\n omModelOverride: null,\n observerModelOverride: null,\n observerModelSelection: null,\n reflectorModelOverride: null,\n reflectorModelSelection: null,\n omObservationThreshold: null,\n omReflectionThreshold: null,\n omCavemanObservations: null,\n omObserveAttachments: null,\n subagentModels: {},\n goalJudgeModel: null,\n goalMaxTurns: null,\n },\n preferences: {\n yolo: null,\n theme: 'auto',\n thinkingLevel: 'off',\n subagentsEnabled: false,\n previewLines: 2,\n webSearchProvider: 'auto',\n },\n storage: { ...STORAGE_DEFAULTS },\n customModelPacks: [],\n customProviders: [],\n modelUseCounts: {},\n updateDismissedVersion: null,\n memoryGateway: {},\n lsp: false,\n browser: {\n enabled: false,\n provider: 'stagehand',\n headless: false,\n viewport: { ...VIEWPORT_PRESETS.desktop },\n stagehand: { env: 'LOCAL' },\n },\n shellPassthrough: { mode: 'default' },\n voice: { enabled: false, engine: defaultVoiceEngine(), provider: DEFAULT_STT_PROVIDER },\n experimentalAgent: null,\n backgroundTools: { enabled: false },\n signals: {\n unixSocketPubSub: false,\n experimentalGithubSignals: false,\n experimentalCrossAgentSignals: false,\n experimentalScheduleTools: false,\n githubPollIntervalMs: GITHUB_POLL_INTERVAL_DEFAULT_MS,\n },\n mcp: { claudeCodeGlobal: false, codexGlobal: false },\n observability: { resources: {}, localTracing: false },\n factory: null,\n};\n\nexport const WEB_SEARCH_PROVIDER_VALUES: WebSearchProviderSetting[] = ['auto', 'tavily', 'parallel'];\nconst PREVIEW_LINES_MAX = 8;\nconst loadedSignalSettings = new WeakMap<GlobalSettings, SignalSettings>();\n\nfunction cloneSignalSettings(signals: SignalSettings): SignalSettings {\n return { ...signals };\n}\n\nfunction rememberLoadedSettings(settings: GlobalSettings): GlobalSettings {\n loadedSignalSettings.set(settings, cloneSignalSettings(settings.signals));\n return settings;\n}\n\nfunction signalSettingsEqual(left: SignalSettings, right: SignalSettings): boolean {\n return (\n left.unixSocketPubSub === right.unixSocketPubSub &&\n left.experimentalGithubSignals === right.experimentalGithubSignals &&\n left.experimentalCrossAgentSignals === right.experimentalCrossAgentSignals &&\n left.experimentalScheduleTools === right.experimentalScheduleTools &&\n left.githubPollIntervalMs === right.githubPollIntervalMs\n );\n}\n\nfunction parseWebSearchProvider(value: unknown): WebSearchProviderSetting {\n return typeof value === 'string' && WEB_SEARCH_PROVIDER_VALUES.includes(value as WebSearchProviderSetting)\n ? (value as WebSearchProviderSetting)\n : DEFAULTS.preferences.webSearchProvider;\n}\n\nfunction parseThinkingLevel(value: unknown): ThinkingLevelSetting {\n return isThinkingLevelSetting(value) ? value : DEFAULTS.preferences.thinkingLevel;\n}\n\nfunction parseModeThinkingDefaults(value: unknown): Record<string, ThinkingLevelSetting> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, ThinkingLevelSetting> = {};\n for (const [mode, level] of Object.entries(value as Record<string, unknown>)) {\n if (isThinkingLevelSetting(level)) {\n result[mode] = level;\n }\n }\n return result;\n}\n\nfunction parseModePackOverrides(value: unknown): Record<string, Record<string, string>> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, Record<string, string>> = {};\n for (const [packId, overrides] of Object.entries(value as Record<string, unknown>)) {\n if (!overrides || typeof overrides !== 'object') continue;\n const parsedOverrides = Object.fromEntries(\n Object.entries(overrides as Record<string, unknown>).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1].length > 0,\n ),\n );\n if (Object.keys(parsedOverrides).length > 0) result[packId] = parsedOverrides;\n }\n return result;\n}\n\nfunction parsePackFallbacks(value: unknown): Record<string, string> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, string> = {};\n for (const [packId, fallbackId] of Object.entries(value as Record<string, unknown>)) {\n if (typeof fallbackId === 'string' && fallbackId.length > 0) result[packId] = fallbackId;\n }\n return result;\n}\n\n/** Shape-parse + drop entries whose source or target pack no longer exists. */\nfunction loadPackFallbacks(value: unknown, customModelPacks: Array<{ name: string }>): Record<string, string> {\n return pruneUnknownModePackFallbacks(parsePackFallbacks(value), customModelPacks);\n}\n\nfunction parsePackAccountPreferences(value: unknown): Record<string, Record<string, string>> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, Record<string, string>> = {};\n for (const [packId, modelPreferences] of Object.entries(value as Record<string, unknown>)) {\n if (!modelPreferences || typeof modelPreferences !== 'object') continue;\n const parsed = Object.fromEntries(\n Object.entries(modelPreferences as Record<string, unknown>).filter(\n (entry): entry is [string, string] =>\n entry[0].length > 0 && typeof entry[1] === 'string' && entry[1].length > 0,\n ),\n );\n if (Object.keys(parsed).length > 0) result[packId] = parsed;\n }\n return result;\n}\n\nfunction loadPackAccountPreferences(\n value: unknown,\n customModelPacks: CustomPack[],\n modePackOverrides: Record<string, Record<string, string>>,\n): PackAccountPreferences {\n return pruneUnknownPackAccountPreferences(parsePackAccountPreferences(value), customModelPacks, modePackOverrides);\n}\n\n/** Move persisted routing choices when re-authentication changes an account instance id. */\nexport function migrateAccountPreferences(\n settings: GlobalSettings,\n previousAccountId: string,\n nextAccountId: string,\n): void {\n if (previousAccountId === nextAccountId) return;\n for (const modelPreferences of Object.values(settings.models.packAccountPreferences ?? {})) {\n for (const [modelId, accountInstanceId] of Object.entries(modelPreferences)) {\n if (accountInstanceId === previousAccountId) modelPreferences[modelId] = nextAccountId;\n }\n }\n}\n\n/** Remove persisted routing choices that point at deleted OAuth account instances. */\nexport function pruneRemovedAccountPreferences(settings: GlobalSettings, removedAccountIds: Iterable<string>): void {\n const removed = new Set(removedAccountIds);\n if (removed.size === 0) return;\n\n const next: PackAccountPreferences = {};\n for (const [packId, modelPreferences] of Object.entries(settings.models.packAccountPreferences ?? {})) {\n const retained = Object.fromEntries(\n Object.entries(modelPreferences).filter(([, accountInstanceId]) => !removed.has(accountInstanceId)),\n );\n if (Object.keys(retained).length > 0) next[packId] = retained;\n }\n settings.models.packAccountPreferences = next;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/**\n * Resolves the preview line limit. `previewLines` wins when valid; otherwise the legacy\n * `quietModeMaxToolPreviewLines` key (still written by older Mastra Code versions) is used.\n */\nfunction parsePreviewLines(raw: Record<string, unknown>): number {\n const value = isFiniteNumber(raw.previewLines)\n ? raw.previewLines\n : isFiniteNumber(raw.quietModeMaxToolPreviewLines)\n ? raw.quietModeMaxToolPreviewLines\n : DEFAULTS.preferences.previewLines;\n return Math.min(PREVIEW_LINES_MAX, Math.max(0, Math.floor(value)));\n}\n\nfunction parsePreferences(rawPreferences: unknown): GlobalSettings['preferences'] {\n const raw = rawPreferences && typeof rawPreferences === 'object' ? (rawPreferences as Record<string, unknown>) : {};\n\n return {\n ...DEFAULTS.preferences,\n ...raw,\n thinkingLevel: parseThinkingLevel(raw.thinkingLevel),\n subagentsEnabled:\n typeof raw.subagentsEnabled === 'boolean' ? raw.subagentsEnabled : DEFAULTS.preferences.subagentsEnabled,\n previewLines: parsePreviewLines(raw),\n webSearchProvider: parseWebSearchProvider(raw.webSearchProvider),\n };\n}\n\nfunction parseGithubPollIntervalMs(value: unknown): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULTS.signals.githubPollIntervalMs;\n const intervalMs = Math.floor(value);\n if (intervalMs < GITHUB_POLL_INTERVAL_MIN_MS) return DEFAULTS.signals.githubPollIntervalMs;\n return Math.min(intervalMs, GITHUB_POLL_INTERVAL_MAX_MS);\n}\n\nexport function parseExperimentalAgentSetting(value: unknown, settingsPath?: string): ExperimentalAgent | null {\n if (value === undefined || value === null) return null;\n if (value === 'durable' || value === 'evented') return value;\n throw new ExperimentalAgentSettingsError(value, settingsPath);\n}\n\nfunction loadExperimentalAgentSetting(\n value: unknown,\n settingsPath: string,\n): { selection: unknown; settingsPath?: string } {\n try {\n return { selection: parseExperimentalAgentSetting(value, settingsPath) };\n } catch (error) {\n if (error instanceof ExperimentalAgentSettingsError) {\n return { selection: error.value, settingsPath };\n }\n throw error;\n }\n}\n\nfunction parseBackgroundToolSettings(rawBackgroundTools: unknown): BackgroundToolSettings {\n const raw =\n rawBackgroundTools && typeof rawBackgroundTools === 'object' ? (rawBackgroundTools as Record<string, unknown>) : {};\n return {\n enabled: typeof raw.enabled === 'boolean' ? raw.enabled : DEFAULTS.backgroundTools.enabled,\n };\n}\n\nfunction parseSignalSettings(rawSignals: unknown): SignalSettings {\n const raw = rawSignals && typeof rawSignals === 'object' ? (rawSignals as Record<string, unknown>) : {};\n return {\n unixSocketPubSub:\n typeof raw.unixSocketPubSub === 'boolean' ? raw.unixSocketPubSub : DEFAULTS.signals.unixSocketPubSub,\n experimentalGithubSignals:\n typeof raw.experimentalGithubSignals === 'boolean'\n ? raw.experimentalGithubSignals\n : DEFAULTS.signals.experimentalGithubSignals,\n experimentalCrossAgentSignals:\n typeof raw.experimentalCrossAgentSignals === 'boolean'\n ? raw.experimentalCrossAgentSignals\n : DEFAULTS.signals.experimentalCrossAgentSignals,\n experimentalScheduleTools:\n typeof raw.experimentalScheduleTools === 'boolean'\n ? raw.experimentalScheduleTools\n : DEFAULTS.signals.experimentalScheduleTools,\n githubPollIntervalMs: parseGithubPollIntervalMs(raw.githubPollIntervalMs),\n };\n}\n\nfunction parseMcpDiscoverySettings(rawMcp: unknown): McpDiscoverySettings {\n const raw = rawMcp && typeof rawMcp === 'object' ? (rawMcp as Record<string, unknown>) : {};\n return {\n claudeCodeGlobal: typeof raw.claudeCodeGlobal === 'boolean' ? raw.claudeCodeGlobal : DEFAULTS.mcp.claudeCodeGlobal,\n codexGlobal: typeof raw.codexGlobal === 'boolean' ? raw.codexGlobal : DEFAULTS.mcp.codexGlobal,\n };\n}\n\nexport function getSettingsPath(): string {\n return join(getAppDataDir(), 'settings.json');\n}\n\nexport function getCustomProviderId(name: string): string {\n const slug = name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return slug || 'provider';\n}\n\nexport function toCustomProviderModelId(providerName: string, modelName: string): string {\n const providerId = getCustomProviderId(providerName);\n const trimmedModelName = modelName.trim();\n const providerPrefix = `${providerId}/`;\n if (trimmedModelName.startsWith(providerPrefix)) {\n return trimmedModelName;\n }\n return `${providerId}/${trimmedModelName}`;\n}\n\n/**\n * The shared gateway catalog namespaces provider keys under their owning\n * gateway id, so a custom provider's models surface in the `/models` catalog\n * as `mastracode/<providerId>/<model>` instead of the canonical\n * `<providerId>/<model>` that model resolution expects. Persisting the\n * gateway-qualified id verbatim breaks lookup later (the provider is parsed\n * as `mastracode`). Strip the prefix before saving — but only when the\n * middle segment matches one of the user's configured custom providers, so\n * legitimate `mastracode/...` gateway-routed ids are left untouched.\n */\nexport function stripMastraCodeCustomProviderPrefix(\n modelId: string,\n customProviders: Array<Pick<CustomProviderSetting, 'name'>>,\n): string {\n const gatewayPrefix = 'mastracode/';\n if (!modelId.startsWith(gatewayPrefix)) return modelId;\n\n const rest = modelId.slice(gatewayPrefix.length);\n const [providerId, ...modelParts] = rest.split('/');\n if (!providerId || modelParts.length === 0 || modelParts.some(part => part.length === 0)) return modelId;\n\n const isCustomProvider = customProviders.some(provider => getCustomProviderId(provider.name) === providerId);\n return isCustomProvider ? rest : modelId;\n}\n\nexport function parseCustomProviders(rawProviders: unknown): CustomProviderSetting[] {\n if (!Array.isArray(rawProviders)) return [];\n\n const parsedProviders: CustomProviderSetting[] = [];\n for (const rawProvider of rawProviders) {\n if (!rawProvider || typeof rawProvider !== 'object') continue;\n\n const candidate = rawProvider as Record<string, unknown>;\n const name = typeof candidate.name === 'string' ? candidate.name.trim() : '';\n const url = typeof candidate.url === 'string' ? candidate.url.trim() : '';\n if (!name || !url) continue;\n\n const providerId = getCustomProviderId(name);\n const models = Array.isArray(candidate.models)\n ? [\n ...new Set(\n candidate.models\n .filter((model): model is string => typeof model === 'string')\n .map(model => model.trim())\n .map(model => {\n const providerPrefix = `${providerId}/`;\n if (model.startsWith(providerPrefix)) {\n return model.slice(providerPrefix.length);\n }\n return model;\n }),\n ),\n ].filter(model => model.length > 0)\n : [];\n\n const apiKey =\n typeof candidate.apiKey === 'string' && candidate.apiKey.trim().length > 0 ? candidate.apiKey.trim() : undefined;\n\n parsedProviders.push({\n name,\n url,\n ...(apiKey ? { apiKey } : {}),\n models,\n });\n }\n\n return parsedProviders;\n}\n\nconst BROWSER_PROVIDERS = new Set<BrowserProvider>(['stagehand', 'agent-browser']);\nconst STAGEHAND_ENVS = new Set<StagehandEnv>(['LOCAL', 'BROWSERBASE']);\n\n/**\n * Normalize a Stagehand model id, which must be provider-qualified.\n *\n * Stagehand reads the segment before the first slash as the provider, so a\n * bare id like `gpt-4.1` is rejected as an unknown provider and a trailing\n * slash leaves an empty model name that only fails once a request is made.\n * Neither is usable, so both are dropped here rather than persisted.\n *\n * The provider name itself is checked where the command is issued, which can\n * name the supported providers in an error; this module is on the startup path\n * and only imports Stagehand lazily.\n *\n * @returns the trimmed model id, or undefined when it is unusable.\n */\nfunction parseStagehandModel(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const model = value.trim();\n const separator = model.indexOf('/');\n if (separator <= 0) return undefined;\n return model.slice(separator + 1).trim() ? model : undefined;\n}\n\n/**\n * Validate a viewport read from settings.json, falling back to the default when\n * it is missing or malformed.\n */\nfunction parseStoredViewport(raw: unknown): BrowserViewport {\n if (raw === 'window') return 'window';\n if (raw && typeof raw === 'object') {\n const { width, height } = raw as Record<string, unknown>;\n if (isValidDimension(width) && isValidDimension(height)) return { width, height };\n }\n return { ...VIEWPORT_PRESETS.desktop };\n}\n\n/**\n * Validate the `lsp` setting from JSON. Accepts both the boolean opt-in/opt-out\n * form and the full LSPConfig object; anything else is treated as unset.\n */\nfunction parseLspSettings(raw: unknown): boolean | LSPConfig | undefined {\n if (typeof raw === 'boolean') return raw;\n if (raw && typeof raw === 'object') return raw as LSPConfig;\n return undefined;\n}\n\n/**\n * Resolve the effective LSP config. LSP is opt-in: `false` and an absent\n * setting both mean disabled, `true` means enabled with defaults.\n */\nexport function resolveLspSetting(lsp: boolean | LSPConfig | undefined): LSPConfig | false {\n if (lsp === true) return {};\n if (!lsp) return false;\n return lsp;\n}\n\n/**\n * Deep-merge and validate browser settings from JSON.\n * Explicitly validates types to handle malformed settings.json gracefully.\n */\nfunction parseBrowserSettings(rawBrowser: unknown): BrowserSettings {\n const raw = rawBrowser && typeof rawBrowser === 'object' ? (rawBrowser as Record<string, unknown>) : {};\n const rawStagehand =\n raw.stagehand && typeof raw.stagehand === 'object' ? (raw.stagehand as Record<string, unknown>) : {};\n const stagehandModel = parseStagehandModel(rawStagehand.model);\n const rawAgentBrowser =\n raw.agentBrowser && typeof raw.agentBrowser === 'object' ? (raw.agentBrowser as Record<string, unknown>) : {};\n\n return {\n enabled: typeof raw.enabled === 'boolean' ? raw.enabled : DEFAULTS.browser.enabled,\n provider:\n typeof raw.provider === 'string' && BROWSER_PROVIDERS.has(raw.provider as BrowserProvider)\n ? (raw.provider as BrowserProvider)\n : DEFAULTS.browser.provider,\n headless: typeof raw.headless === 'boolean' ? raw.headless : DEFAULTS.browser.headless,\n cdpUrl: typeof raw.cdpUrl === 'string' && raw.cdpUrl.trim() ? raw.cdpUrl.trim() : undefined,\n profile: typeof raw.profile === 'string' && raw.profile.trim() ? raw.profile.trim() : undefined,\n executablePath:\n typeof raw.executablePath === 'string' && raw.executablePath.trim() ? raw.executablePath.trim() : undefined,\n viewport: parseStoredViewport(raw.viewport),\n scope: typeof raw.scope === 'string' && (raw.scope === 'shared' || raw.scope === 'thread') ? raw.scope : undefined,\n stagehand: {\n env:\n typeof rawStagehand.env === 'string' && STAGEHAND_ENVS.has(rawStagehand.env as StagehandEnv)\n ? (rawStagehand.env as StagehandEnv)\n : DEFAULTS.browser.stagehand!.env,\n ...(typeof rawStagehand.apiKey === 'string' && rawStagehand.apiKey.trim()\n ? { apiKey: rawStagehand.apiKey.trim() }\n : {}),\n ...(typeof rawStagehand.projectId === 'string' && rawStagehand.projectId.trim()\n ? { projectId: rawStagehand.projectId.trim() }\n : {}),\n ...(stagehandModel ? { model: stagehandModel } : {}),\n ...(typeof rawStagehand.preserveUserDataDir === 'boolean'\n ? { preserveUserDataDir: rawStagehand.preserveUserDataDir }\n : {}),\n },\n agentBrowser:\n typeof rawAgentBrowser.storageState === 'string' && rawAgentBrowser.storageState.trim()\n ? { storageState: rawAgentBrowser.storageState.trim() }\n : undefined,\n };\n}\n\nfunction parseShellPassthroughSettings(rawShellPassthrough: unknown): ShellPassthroughSettings {\n const raw =\n rawShellPassthrough && typeof rawShellPassthrough === 'object'\n ? (rawShellPassthrough as Record<string, unknown>)\n : {};\n const executable = typeof raw.executable === 'string' && raw.executable.trim() ? raw.executable.trim() : undefined;\n const family = typeof raw.family === 'string' && raw.family.trim() ? raw.family.trim() : undefined;\n const mode = typeof raw.mode === 'string' && raw.mode.trim() ? raw.mode.trim() : undefined;\n const defaultMode = executable ? undefined : DEFAULTS.shellPassthrough.mode;\n\n return {\n ...((mode ?? defaultMode) ? { mode: mode ?? defaultMode } : {}),\n ...(executable ? { executable } : {}),\n ...(family ? { family } : {}),\n };\n}\n\nfunction parseVoiceSettings(rawVoice: unknown): VoiceSettings {\n const raw = rawVoice && typeof rawVoice === 'object' ? (rawVoice as Record<string, unknown>) : {};\n const enabled = typeof raw.enabled === 'boolean' ? raw.enabled : DEFAULTS.voice.enabled;\n const engine: VoiceEngine =\n raw.engine === 'macos-native' || raw.engine === 'cloud' ? raw.engine : defaultVoiceEngine();\n // Validate provider/model against the registry, falling back to a usable entry\n // so old `{ enabled }`-only files and unknown values still resolve cleanly.\n const provider = typeof raw.provider === 'string' ? raw.provider : DEFAULTS.voice.provider;\n const model = typeof raw.model === 'string' ? raw.model : undefined;\n const resolved = resolveSTTModel(provider, model);\n return {\n enabled,\n engine,\n provider: resolved.provider,\n model: resolved.model,\n };\n}\n\nconst VALID_PROJECT_ID = /^[a-zA-Z0-9_-]+$/;\n\nfunction parseObservabilitySettings(raw: unknown): ObservabilitySettings {\n if (!raw || typeof raw !== 'object') return { resources: {}, localTracing: false };\n const obj = raw as Record<string, unknown>;\n const localTracing = obj.localTracing === true;\n const rawResources = obj.resources;\n if (!rawResources || typeof rawResources !== 'object') return { resources: {}, localTracing };\n const resources: Record<string, ObservabilityResourceConfig> = {};\n for (const [key, val] of Object.entries(rawResources as Record<string, unknown>)) {\n if (val && typeof val === 'object') {\n const v = val as Record<string, unknown>;\n if (typeof v.projectId === 'string' && VALID_PROJECT_ID.test(v.projectId)) {\n resources[key] = {\n projectId: v.projectId,\n configuredAt: typeof v.configuredAt === 'string' ? v.configuredAt : new Date().toISOString(),\n };\n }\n }\n }\n return { resources, localTracing };\n}\n\n/**\n * One-time migration: move model-related data from auth.json to settings.json.\n * Reads `_modelRanks`, `_modeModelId_*`, `_subagentModelId*` from auth.json,\n * merges them into settings, removes them from auth.json, and writes both files.\n * No-ops if auth.json has no _ prefixed model data.\n */\nfunction migrateFromAuth(settingsPath: string): boolean {\n const authPath = join(getAppDataDir(), 'auth.json');\n if (!existsSync(authPath)) return false;\n\n let authData: Record<string, any>;\n try {\n authData = JSON.parse(readFileSync(authPath, 'utf-8'));\n } catch {\n return false;\n }\n\n const modelKeys = Object.keys(authData).filter(k => k.startsWith('_'));\n if (modelKeys.length === 0) return false;\n\n // Load existing settings (or defaults) and merge auth data into it\n let settings: GlobalSettings;\n if (existsSync(settingsPath)) {\n try {\n const raw = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n const rawCustomPacks: CustomPack[] = Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [];\n const modePackOverrides = parseModePackOverrides(raw.models?.modePackOverrides);\n const experimentalAgentSetting = loadExperimentalAgentSetting(raw.experimentalAgent, settingsPath);\n settings = {\n onboarding: { ...DEFAULTS.onboarding, ...raw.onboarding },\n models: {\n ...DEFAULTS.models,\n ...raw.models,\n modePackOverrides,\n modeThinkingDefaults: parseModeThinkingDefaults(raw.models?.modeThinkingDefaults),\n packFallbacks: loadPackFallbacks(raw.models?.packFallbacks, rawCustomPacks),\n packAccountPreferences: loadPackAccountPreferences(\n raw.models?.packAccountPreferences,\n rawCustomPacks,\n modePackOverrides,\n ),\n },\n preferences: parsePreferences(raw.preferences),\n storage: {\n ...STORAGE_DEFAULTS,\n ...raw.storage,\n libsql: { ...STORAGE_DEFAULTS.libsql, ...raw.storage?.libsql },\n pg: { ...STORAGE_DEFAULTS.pg, ...raw.storage?.pg },\n },\n customModelPacks: Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [],\n customProviders: parseCustomProviders(raw.customProviders),\n modelUseCounts: raw.modelUseCounts && typeof raw.modelUseCounts === 'object' ? raw.modelUseCounts : {},\n updateDismissedVersion: typeof raw.updateDismissedVersion === 'string' ? raw.updateDismissedVersion : null,\n memoryGateway: raw.memoryGateway && typeof raw.memoryGateway === 'object' ? raw.memoryGateway : {},\n lsp: parseLspSettings(raw.lsp),\n browser: parseBrowserSettings(raw.browser),\n shellPassthrough: parseShellPassthroughSettings(raw.shellPassthrough),\n voice: parseVoiceSettings(raw.voice),\n experimentalAgent: experimentalAgentSetting.selection,\n _experimentalAgentSettingsPath: experimentalAgentSetting.settingsPath,\n backgroundTools: parseBackgroundToolSettings(raw.backgroundTools),\n signals: parseSignalSettings(raw.signals),\n mcp: parseMcpDiscoverySettings(raw.mcp),\n observability: parseObservabilitySettings(raw.observability),\n factory: parseFactoryConnectionSettings(raw.factory),\n };\n } catch {\n settings = structuredClone(DEFAULTS);\n }\n } else {\n settings = structuredClone(DEFAULTS);\n }\n\n // Migrate model use counts (only if settings doesn't already have them)\n if (authData._modelRanks && typeof authData._modelRanks === 'object') {\n settings.modelUseCounts = { ...authData._modelRanks, ...settings.modelUseCounts };\n }\n\n // Migrate per-mode model defaults (don't overwrite existing settings)\n for (const key of modelKeys) {\n const modeMatch = key.match(/^_modeModelId_(.+)$/);\n if (modeMatch?.[1] && typeof authData[key] === 'string' && !settings.models.modeDefaults[modeMatch[1]]) {\n settings.models.modeDefaults[modeMatch[1]] = authData[key];\n }\n }\n\n // Migrate subagent models (don't overwrite existing settings)\n for (const key of modelKeys) {\n if (key === '_subagentModelId' && typeof authData[key] === 'string' && !settings.models.subagentModels['default']) {\n settings.models.subagentModels['default'] = authData[key];\n }\n const saMatch = key.match(/^_subagentModelId_(.+)$/);\n if (saMatch?.[1] && typeof authData[key] === 'string' && !settings.models.subagentModels[saMatch[1]]) {\n settings.models.subagentModels[saMatch[1]] = authData[key];\n }\n }\n\n // Write migrated settings\n saveSettings(settings, settingsPath);\n\n // Clean up auth.json — remove _ prefixed keys\n for (const key of modelKeys) {\n delete authData[key];\n }\n try {\n writeFileAtomically(authPath, JSON.stringify(authData, null, 2));\n } catch {\n // Non-fatal — settings are saved, auth cleanup can fail\n }\n\n return true;\n}\n\nconst LEGACY_VARIED_MODELS: Record<string, string> = {\n plan: 'openai/gpt-5.4',\n build: 'anthropic/claude-sonnet-4-5',\n fast: 'anthropic/claude-haiku-4-5',\n};\n\nexport function migrateLegacyVariedPack(settings: GlobalSettings): boolean {\n const legacyPackId = 'varied';\n const customPackId = 'custom:varied';\n const hasLegacyReference =\n settings.models.activeModelPackId === legacyPackId || settings.onboarding.modePackId === legacyPackId;\n\n if (!hasLegacyReference) return false;\n\n const existingIdx = settings.customModelPacks.findIndex(p => p.name === 'varied');\n if (existingIdx >= 0) {\n const existing = settings.customModelPacks[existingIdx]!;\n const modelsMatch = Object.entries(LEGACY_VARIED_MODELS).every(([k, v]) => existing.models[k] === v);\n if (!modelsMatch) {\n existing.models = { ...LEGACY_VARIED_MODELS };\n }\n } else {\n settings.customModelPacks.push({\n name: 'varied',\n models: { ...LEGACY_VARIED_MODELS },\n createdAt: new Date().toISOString(),\n });\n }\n\n if (settings.models.activeModelPackId === legacyPackId) {\n settings.models.activeModelPackId = customPackId;\n if (Object.keys(settings.models.modeDefaults).length === 0) {\n settings.models.modeDefaults = { ...LEGACY_VARIED_MODELS };\n }\n }\n\n if (settings.onboarding.modePackId === legacyPackId) {\n settings.onboarding.modePackId = customPackId;\n }\n\n return true;\n}\n\nexport function loadSettings(filePath: string = getSettingsPath()): GlobalSettings {\n // One-time migration: move model data from auth.json into settings.json\n migrateFromAuth(filePath);\n\n if (!existsSync(filePath)) return rememberLoadedSettings(structuredClone(DEFAULTS));\n try {\n const raw = JSON.parse(readFileSync(filePath, 'utf-8'));\n const rawCustomPacks: CustomPack[] = Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [];\n const modePackOverrides = parseModePackOverrides(raw.models?.modePackOverrides);\n const experimentalAgentSetting = loadExperimentalAgentSetting(raw.experimentalAgent, filePath);\n // Spread raw first to preserve unknown top-level keys (forward-compatibility),\n // then overlay with parsed/typed fields so known keys are always correct.\n const settings: GlobalSettings = {\n ...raw,\n onboarding: { ...DEFAULTS.onboarding, ...raw.onboarding },\n models: {\n ...DEFAULTS.models,\n ...raw.models,\n modePackOverrides,\n modeThinkingDefaults: parseModeThinkingDefaults(raw.models?.modeThinkingDefaults),\n packFallbacks: loadPackFallbacks(raw.models?.packFallbacks, rawCustomPacks),\n packAccountPreferences: loadPackAccountPreferences(\n raw.models?.packAccountPreferences,\n rawCustomPacks,\n modePackOverrides,\n ),\n },\n preferences: parsePreferences(raw.preferences),\n storage: {\n ...STORAGE_DEFAULTS,\n ...raw.storage,\n libsql: { ...STORAGE_DEFAULTS.libsql, ...raw.storage?.libsql },\n pg: { ...STORAGE_DEFAULTS.pg, ...raw.storage?.pg },\n },\n customModelPacks: Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [],\n customProviders: parseCustomProviders(raw.customProviders),\n modelUseCounts: raw.modelUseCounts && typeof raw.modelUseCounts === 'object' ? raw.modelUseCounts : {},\n updateDismissedVersion: typeof raw.updateDismissedVersion === 'string' ? raw.updateDismissedVersion : null,\n memoryGateway: raw.memoryGateway && typeof raw.memoryGateway === 'object' ? raw.memoryGateway : {},\n lsp: parseLspSettings(raw.lsp),\n browser: parseBrowserSettings(raw.browser),\n shellPassthrough: parseShellPassthroughSettings(raw.shellPassthrough),\n voice: parseVoiceSettings(raw.voice),\n experimentalAgent: experimentalAgentSetting.selection,\n _experimentalAgentSettingsPath: experimentalAgentSetting.settingsPath,\n backgroundTools: parseBackgroundToolSettings(raw.backgroundTools),\n signals: parseSignalSettings(raw.signals),\n mcp: parseMcpDiscoverySettings(raw.mcp),\n observability: parseObservabilitySettings(raw.observability),\n factory: parseFactoryConnectionSettings(raw.factory),\n };\n\n let settingsChanged = false;\n // Persist the resolved preview line limit under its current key. Legacy quiet-mode keys are\n // left untouched so older Mastra Code instances that are still running keep working.\n if (!isFiniteNumber(raw.preferences?.previewLines)) {\n settingsChanged = true;\n }\n // Migrate legacy omModelId → omModelOverride\n if (raw.models?.omModelId && !settings.models.omModelOverride) {\n settings.models.omModelOverride = raw.models.omModelId;\n settingsChanged = true;\n }\n\n if (migrateLegacyVariedPack(settings)) {\n settingsChanged = true;\n }\n\n if (settingsChanged) {\n saveSettings(settings, filePath);\n }\n\n return rememberLoadedSettings(settings);\n } catch {\n return rememberLoadedSettings(structuredClone(DEFAULTS));\n }\n}\n\nexport const THREAD_ACTIVE_MODEL_PACK_ID_KEY = 'activeModelPackId';\nexport const THREAD_FALLBACK_STATUS_KEY = 'mastracodeFallbackStatus';\n\nexport interface ThreadSettings {\n activeModelPackId: string | null;\n modeModelIds: Record<string, string>;\n}\n\nexport function parseThreadSettings(metadata: Record<string, unknown> | undefined): ThreadSettings {\n const modeModelIds: Record<string, string> = {};\n for (const [key, value] of Object.entries(metadata ?? {})) {\n const modeMatch = key.match(/^modeModelId_(.+)$/);\n if (modeMatch?.[1] && typeof value === 'string' && value.length > 0) {\n modeModelIds[modeMatch[1]] = value;\n }\n }\n\n const rawPackId = metadata?.[THREAD_ACTIVE_MODEL_PACK_ID_KEY];\n const activeModelPackId = typeof rawPackId === 'string' && rawPackId.length > 0 ? rawPackId : null;\n\n return {\n activeModelPackId,\n modeModelIds,\n };\n}\n\n/**\n * Resolve active model pack id for the current thread.\n *\n * Priority:\n * 1) explicit thread metadata activeModelPackId\n * 2) inferred from thread modeModelId_* values\n * 3) global settings.models.activeModelPackId\n */\nexport function resolveThreadActiveModelPackId(\n settings: GlobalSettings,\n builtinPacks: Array<{ id: string; models: Record<string, string> }>,\n metadata: Record<string, unknown> | undefined,\n): string | null {\n const threadSettings = parseThreadSettings(metadata);\n\n const isKnownPack = (packId: string): boolean => {\n if (packId.startsWith('custom:')) {\n const name = packId.slice('custom:'.length);\n return settings.customModelPacks.some(p => p.name === name);\n }\n return builtinPacks.some(p => p.id === packId);\n };\n\n if (threadSettings.activeModelPackId && isKnownPack(threadSettings.activeModelPackId)) {\n return threadSettings.activeModelPackId;\n }\n\n const allPacks: Array<{ id: string; models: Record<string, string> }> = [\n ...builtinPacks,\n ...settings.customModelPacks.map(p => ({ id: `custom:${p.name}`, models: p.models })),\n ];\n\n for (const pack of allPacks) {\n const packEntries = Object.entries(pack.models);\n const threadEntries = Object.keys(threadSettings.modeModelIds);\n const matches =\n packEntries.length === threadEntries.length &&\n packEntries.every(([modeId, modelId]) => threadSettings.modeModelIds[modeId] === modelId);\n if (matches) return pack.id;\n }\n\n if (settings.models.activeModelPackId && isKnownPack(settings.models.activeModelPackId)) {\n return settings.models.activeModelPackId;\n }\n\n return null;\n}\n\n/**\n * Resolve effective per-mode model defaults.\n *\n * If `activeModelPackId` is set, looks up the pack (built-in or custom) and\n * returns its models. Falls back to the explicit `modeDefaults` map.\n *\n * @param settings The loaded global settings.\n * @param builtinPacks Built-in packs for the current provider access\n * (from `getAvailableModePacks`). Pass `[]` if unavailable.\n */\nexport function resolveModePackModels(\n settings: GlobalSettings,\n pack: { id: string; models: Record<string, string> },\n): Record<string, string> {\n if (pack.id.startsWith('custom:') || pack.id === 'custom') return pack.models;\n return { ...pack.models, ...settings.models.modePackOverrides?.[pack.id] };\n}\n\n/**\n * Resolve a session's explicitly active pack when its mode model still matches.\n * Model matching alone is not pack identity: multiple packs may intentionally\n * use the same model, and inference would attach an unrelated fallback chain.\n */\nexport function findModePackForModel(\n settings: GlobalSettings,\n packs: Array<{ id: string; models: Record<string, string> }>,\n modelId: string,\n modeId: string,\n activePackId: string | undefined,\n): { id: string; models: Record<string, string> } | undefined {\n const activePack = packs.find(pack => pack.id === activePackId);\n return activePack && resolveModePackModels(settings, activePack)[modeId] === modelId ? activePack : undefined;\n}\n\nexport function resolveModelDefaults(\n settings: GlobalSettings,\n builtinPacks: Array<{ id: string; models: Record<string, string> }>,\n): Record<string, string> {\n const { activeModelPackId, modeDefaults } = settings.models;\n if (!activeModelPackId) return modeDefaults;\n\n // Custom pack: \"custom:<name>\"\n if (activeModelPackId.startsWith('custom:')) {\n const name = activeModelPackId.slice('custom:'.length);\n const pack = settings.customModelPacks.find(p => p.name === name);\n if (pack) return pack.models;\n // Custom pack was deleted — fall through to modeDefaults\n return modeDefaults;\n }\n\n // Built-in pack\n const builtin = builtinPacks.find(p => p.id === activeModelPackId);\n if (builtin) return resolveModePackModels(settings, builtin);\n\n // Unknown pack id — fall through\n return modeDefaults;\n}\n\n/**\n * Resolve the default reasoning-effort level for a mode.\n *\n * Lookup order:\n * 1. `models.modeThinkingDefaults[mode]` when set for the mode.\n * 2. The global `preferences.thinkingLevel`.\n *\n * Session-level overrides (via /think or the session settings panel) take\n * precedence over both and are handled by the caller.\n */\nexport function resolveDefaultThinkingLevel(\n settings: GlobalSettings,\n mode?: string | null,\n): { level: ThinkingLevelSetting; source: ThinkingLevelSource } {\n return resolveThinkingDefault(\n {\n globalDefault: settings.preferences.thinkingLevel,\n modeDefaults: settings.models.modeThinkingDefaults,\n },\n mode,\n );\n}\n\n/**\n * Resolve the effective model ID for one of the two OM roles.\n *\n * Lookup order:\n * 1. The role-specific override (`observerModelOverride` /\n * `reflectorModelOverride`) if set.\n * 2. If `activeOmPackId` points at a built-in pack, that pack's model.\n * 3. The shared `omModelOverride` fallback.\n *\n * @param settings The loaded global settings.\n * @param role Which OM role to resolve (`'observer'` or `'reflector'`).\n * @param builtinOmPacks Built-in OM packs for the current provider access\n * (from `getAvailableOmPacks`). Pass `[]` if unavailable.\n */\nexport function resolveOmRoleModel(\n settings: GlobalSettings,\n role: 'observer' | 'reflector',\n builtinOmPacks: Array<{ id: string; modelId: string }>,\n): string | null {\n const {\n activeOmPackId,\n omModelOverride,\n observerModelOverride,\n observerModelSelection,\n reflectorModelOverride,\n reflectorModelSelection,\n } = settings.models;\n const model = role === 'observer' ? observerModelSelection : reflectorModelSelection;\n if (model === 'auto') return null;\n if (model) return model;\n\n const roleOverride = role === 'observer' ? observerModelOverride : reflectorModelOverride;\n if (roleOverride) return roleOverride;\n\n if (!activeOmPackId) return omModelOverride;\n if (activeOmPackId === 'custom') return omModelOverride;\n\n const pack = builtinOmPacks.find(p => p.id === activeOmPackId);\n if (pack) return pack.modelId;\n\n return omModelOverride;\n}\n\n/**\n * @deprecated Use `resolveOmRoleModel(settings, 'observer' | 'reflector', ...)`.\n * Equivalent to resolving the observer role (existing callers set both observer\n * and reflector to the same value).\n */\nexport function resolveOmModel(\n settings: GlobalSettings,\n builtinOmPacks: Array<{ id: string; modelId: string }>,\n): string | null {\n return resolveOmRoleModel(settings, 'observer', builtinOmPacks);\n}\n\nfunction getSignalSettingsForSave(settings: GlobalSettings, filePath: string): SignalSettings {\n const loadedSignals = loadedSignalSettings.get(settings);\n if (!loadedSignals || !signalSettingsEqual(settings.signals, loadedSignals) || !existsSync(filePath)) {\n return settings.signals;\n }\n\n try {\n const currentRaw = JSON.parse(readFileSync(filePath, 'utf-8')) as Record<string, unknown>;\n const currentSignals = parseSignalSettings(currentRaw.signals);\n if (!signalSettingsEqual(currentSignals, loadedSignals)) {\n return currentSignals;\n }\n } catch {\n // If the current file is unreadable, fall back to the caller's settings.\n }\n\n return settings.signals;\n}\n\nfunction writeFileAtomically(filePath: string, content: string): void {\n const tempPath = `${filePath}.${process.pid}.${globalThis.crypto.randomUUID()}.tmp`;\n try {\n // Preserve the target's mode across the rename (auth.json keeps its 0600);\n // new files default to owner-only since these are local app-data files.\n const mode = existsSync(filePath) ? statSync(filePath).mode & 0o777 : 0o600;\n writeFileSync(tempPath, content, { encoding: 'utf-8', mode });\n renameSync(tempPath, filePath);\n } finally {\n rmSync(tempPath, { force: true });\n }\n}\n\nexport function saveSettings(settings: GlobalSettings, filePath: string = getSettingsPath()): void {\n const dir = dirname(filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n const signals = getSignalSettingsForSave(settings, filePath);\n settings.signals = signals;\n loadedSignalSettings.set(settings, cloneSignalSettings(signals));\n const settingsToSave: Record<string, unknown> = { ...settings };\n delete settingsToSave._experimentalAgentSettingsPath;\n writeFileAtomically(filePath, JSON.stringify(settingsToSave, null, 2));\n}\n\n/** Marker file name to track which provider last used a profile. */\nconst PROFILE_PROVIDER_MARKER = '.mastra-provider';\n\n/**\n * Check which provider last used a profile directory.\n * Returns the provider name if the marker exists, undefined otherwise.\n */\nexport function getProfileProvider(profilePath: string): BrowserProvider | undefined {\n const markerPath = join(profilePath, PROFILE_PROVIDER_MARKER);\n if (!existsSync(markerPath)) {\n return undefined;\n }\n try {\n const content = readFileSync(markerPath, 'utf-8').trim();\n if (content === 'stagehand' || content === 'agent-browser') {\n return content;\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Write the provider marker to a profile directory.\n * Creates the directory if it doesn't exist.\n */\nexport function setProfileProvider(profilePath: string, provider: BrowserProvider): void {\n const markerPath = join(profilePath, PROFILE_PROVIDER_MARKER);\n if (!existsSync(profilePath)) {\n mkdirSync(profilePath, { recursive: true });\n }\n writeFileSync(markerPath, provider, 'utf-8');\n}\n\n/**\n * Check if a profile has a provider mismatch.\n * Returns the existing provider if there's a mismatch, undefined otherwise.\n */\nexport function checkProfileProviderMismatch(\n profilePath: string | undefined,\n targetProvider: BrowserProvider,\n): BrowserProvider | undefined {\n if (!profilePath) {\n return undefined;\n }\n const existingProvider = getProfileProvider(profilePath);\n if (existingProvider && existingProvider !== targetProvider) {\n return existingProvider;\n }\n return undefined;\n}\n\nfunction browserRecordingOptions() {\n return { outputDir: join(getAppDataDir(), 'browser-recordings') };\n}\n\n/**\n * Snapshot of browser settings safe to store in session state (which session clients can read).\n * Strips credentials; keeps everything `/browser status` needs for drift detection.\n */\nexport function toActiveBrowserSettings(settings: BrowserSettings): BrowserSettings {\n if (!settings.stagehand) return { ...settings };\n const { apiKey: _apiKey, ...stagehand } = settings.stagehand;\n return { ...settings, stagehand };\n}\n\nexport type StagehandModelSource =\n /** `browser.stagehand.model` in settings. */\n | 'settings'\n /** No model configured; reusing the chat model that was active when the browser launched. */\n | 'chat-model'\n /** No usable model otherwise; the default model for the user's OpenAI Codex (ChatGPT) login. */\n | 'codex-oauth'\n /** Nothing else applies; Stagehand picks its own default from env API keys. */\n | 'stagehand-default';\n\nexport interface ResolvedStagehandModel {\n /** `provider/model` id, or undefined when Stagehand's own default applies. */\n modelName: string | undefined;\n source: StagehandModelSource;\n /** True when requests go through the user's OpenAI Codex OAuth login instead of an API key. */\n viaCodexOAuth: boolean;\n}\n\nexport interface ResolveStagehandModelOptions {\n /**\n * Chat model id at the moment the browser launches (`session.model.get()`).\n * The Stagehand instance is fixed once created and shared across threads, so\n * later chat-model switches do not affect it.\n */\n chatModelId?: string;\n authStorage?: AuthStorage;\n}\n\n/**\n * Env vars Stagehand reads for each provider it can route (mirrors\n * `STAGEHAND_MODEL_PROVIDERS` in `@mastra/stagehand` and Stagehand's own\n * `providerEnvVarMap`). `null` means the provider needs no API key.\n * Kept here instead of importing `@mastra/stagehand`, which would eagerly\n * load the browser stack into every settings consumer.\n */\nexport const STAGEHAND_PROVIDER_ENV_VARS: Record<string, readonly string[] | null> = {\n openai: ['OPENAI_API_KEY'],\n anthropic: ['ANTHROPIC_API_KEY'],\n google: ['GEMINI_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_API_KEY'],\n vertex: ['GOOGLE_VERTEX_AI_API_KEY'],\n groq: ['GROQ_API_KEY'],\n cerebras: ['CEREBRAS_API_KEY'],\n togetherai: ['TOGETHER_AI_API_KEY'],\n mistral: ['MISTRAL_API_KEY'],\n deepseek: ['DEEPSEEK_API_KEY'],\n perplexity: ['PERPLEXITY_API_KEY'],\n azure: ['AZURE_API_KEY'],\n xai: ['XAI_API_KEY'],\n gateway: ['AI_GATEWAY_API_KEY'],\n bedrock: null,\n ollama: null,\n};\n\nfunction hasCodexOAuthLogin(authStorage: AuthStorage): boolean {\n return authStorage.get('openai-codex')?.type === 'oauth';\n}\n\nfunction isOpenAIModel(modelId: string): boolean {\n return modelId.startsWith(OPENAI_PREFIX);\n}\n\n/**\n * Stagehand hands the segment after `provider/` straight to the AI SDK provider,\n * so apply the same id normalization the chat gateway does before it does.\n */\nfunction normalizeForStagehand(modelId: string): string {\n const bare = stripMastraGatewayPrefix(modelId.trim());\n return bare.startsWith(ANTHROPIC_PREFIX) ? normalizeAnthropicModelId(bare) : bare;\n}\n\n/** Whether Stagehand could run `provider/model` with the credentials available right now. */\nfunction stagehandCanRoute(modelId: string, codexOAuth: boolean): boolean {\n const provider = modelId.split('/', 1)[0];\n if (!provider || provider === modelId) return false;\n if (provider === 'openai' && codexOAuth) return true;\n const envVars = STAGEHAND_PROVIDER_ENV_VARS[provider];\n if (envVars === undefined) return false;\n if (envVars === null) return true;\n return envVars.some(name => Boolean(process.env[name]?.trim()));\n}\n\n/**\n * Resolve which model Stagehand will use and why, without creating a browser.\n * Order: configured `browser.stagehand.model` → the launch-time chat model when\n * Stagehand can route it → the Codex login's default model → Stagehand's own\n * default. Mirrors the selection in `createBrowserFromSettings` so the UI can\n * show it.\n */\nexport function resolveStagehandModel(\n settings: Pick<BrowserSettings, 'provider' | 'stagehand'>,\n { chatModelId, authStorage = new AuthStorage() }: ResolveStagehandModelOptions = {},\n): ResolvedStagehandModel {\n if (settings.provider !== 'stagehand') {\n return { modelName: undefined, source: 'stagehand-default', viaCodexOAuth: false };\n }\n const codexOAuth = hasCodexOAuthLogin(authStorage);\n const configured = settings.stagehand?.model ? normalizeForStagehand(settings.stagehand.model) : undefined;\n if (configured) {\n return { modelName: configured, source: 'settings', viaCodexOAuth: codexOAuth && isOpenAIModel(configured) };\n }\n const chatModel = chatModelId ? normalizeForStagehand(chatModelId) : undefined;\n if (chatModel && stagehandCanRoute(chatModel, codexOAuth)) {\n return { modelName: chatModel, source: 'chat-model', viaCodexOAuth: codexOAuth && isOpenAIModel(chatModel) };\n }\n if (codexOAuth) {\n return { modelName: PROVIDER_DEFAULT_MODELS['openai-codex'], source: 'codex-oauth', viaCodexOAuth: true };\n }\n return { modelName: undefined, source: 'stagehand-default', viaCodexOAuth: false };\n}\n\nexport interface CreateBrowserOptions {\n /** Chat model id at launch; see `ResolveStagehandModelOptions.chatModelId`. */\n chatModelId?: string;\n}\n\n/**\n * Create a browser instance from settings.\n * Shared by startup (main.ts) and live reconfiguration (/browser command).\n * Returns undefined if browser is disabled.\n */\nexport async function createBrowserFromSettings(\n settings: BrowserSettings,\n { chatModelId }: CreateBrowserOptions = {},\n): Promise<MastraBrowser | undefined> {\n if (!settings.enabled) {\n return undefined;\n }\n\n const { provider, headless, viewport, cdpUrl, profile, executablePath, stagehand, agentBrowser } = settings;\n\n // Chrome only allows one process per profile directory, so force 'shared' scope\n // when a profile is set. Otherwise use the user's setting (or provider default).\n const scope = profile ? ('shared' as const) : settings.scope;\n\n // Common launch options (no CDP)\n const launchConfig = { headless, viewport, profile, executablePath, scope } as const;\n\n if (provider === 'stagehand') {\n const { StagehandBrowser } = await import('@mastra/stagehand');\n const stagehandOpts: Record<string, unknown> = {\n env: stagehand?.env ?? 'LOCAL',\n apiKey: stagehand?.apiKey ?? process.env.BROWSERBASE_API_KEY,\n projectId: stagehand?.projectId ?? process.env.BROWSERBASE_PROJECT_ID,\n preserveUserDataDir: stagehand?.preserveUserDataDir,\n recording: browserRecordingOptions(),\n };\n\n // See resolveStagehandModel() for which model is picked. How it is reached\n // depends on the user's OpenAI auth, not on where the model came from:\n // any `openai/*` model goes through the Codex (ChatGPT) endpoint when the\n // user signed in with Codex OAuth, matching the chat agents. Everything\n // else is passed as a plain `provider/model` string and Stagehand resolves\n // the provider's API key from the environment.\n //\n // The Codex route uses the AI SDK provider's standard hooks:\n // - baseURL: target Codex's Responses API directly (no URL rewriting).\n // - headers: static Codex identifiers (originator, UA, account id).\n // - fetch: a tiny refresher that injects the live OAuth bearer per call,\n // since AI SDK takes `apiKey` as a static string.\n // - middleware: createCodexMiddleware() sets `store: false`, which Codex\n // requires on every request.\n const authStorage = new AuthStorage();\n const resolved = resolveStagehandModel(settings, { chatModelId, authStorage });\n if (resolved.modelName && resolved.viaCodexOAuth) {\n const accountId = (authStorage.get('openai-codex') as any)?.accountId as string | undefined;\n stagehandOpts.model = {\n modelName: remapOpenAIModelForCodexOAuth(resolved.modelName),\n apiKey: 'codex-oauth',\n baseURL: 'https://chatgpt.com/backend-api/codex',\n headers: {\n originator: 'mastracode',\n 'User-Agent': 'mastracode',\n ...(accountId ? { 'ChatGPT-Account-ID': accountId } : {}),\n },\n fetch: buildCodexStagehandFetch(authStorage),\n middleware: createCodexMiddleware(),\n } as any;\n } else if (resolved.modelName) {\n stagehandOpts.model = resolved.modelName;\n }\n\n return cdpUrl\n ? new StagehandBrowser({ ...launchConfig, cdpUrl, scope: 'shared', ...stagehandOpts })\n : new StagehandBrowser({ ...launchConfig, ...stagehandOpts });\n } else if (provider === 'agent-browser') {\n const { AgentBrowser } = await import('@mastra/agent-browser');\n const agentBrowserOpts = {\n storageState: agentBrowser?.storageState,\n recording: browserRecordingOptions(),\n };\n return cdpUrl\n ? new AgentBrowser({ ...launchConfig, cdpUrl, scope: 'shared', ...agentBrowserOpts })\n : new AgentBrowser({ ...launchConfig, ...agentBrowserOpts, scope });\n }\n\n throw new Error(`Unsupported browser provider: ${provider}`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"settings.js","names":["resolveThinkingDefault"],"sources":["../../src/onboarding/settings.ts"],"sourcesContent":["/**\n * Persistent global settings stored in the app data directory as settings.json.\n * This file persists onboarding state AND user preferences (model choices, yolo, etc.)\n * so they carry across threads and restarts.\n */\n\nimport { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { OMModel } from '@mastra/core/agent-controller';\nimport type { MastraBrowser } from '@mastra/core/browser';\nimport type { LSPConfig } from '@mastra/core/workspace';\nimport { AuthStorage, PROVIDER_DEFAULT_MODELS } from '../auth/storage.js';\nimport {\n ANTHROPIC_PREFIX,\n normalizeAnthropicModelId,\n OPENAI_PREFIX,\n remapOpenAIModelForCodexOAuth,\n stripMastraGatewayPrefix,\n} from '../providers/model-ids.js';\nimport { buildCodexStagehandFetch, createCodexMiddleware } from '../providers/openai-codex.js';\nimport {\n isThinkingLevelSetting,\n resolveDefaultThinkingLevel as resolveThinkingDefault,\n THINKING_LEVEL_VALUES,\n} from '../thinking.js';\nimport type { ThinkingLevelSetting, ThinkingLevelSource } from '../thinking.js';\nexport { isThinkingLevelSetting, THINKING_LEVEL_VALUES } from '../thinking.js';\nexport type { ThinkingLevelSetting, ThinkingLevelSource } from '../thinking.js';\nimport { getAppDataDir } from '../utils/project.js';\nimport { DEFAULT_STT_PROVIDER, resolveSTTModel } from '../voice/stt-registry.js';\nimport { pruneUnknownModePackFallbacks, pruneUnknownPackAccountPreferences } from './packs.js';\n\n/** A saved custom pack — user-defined model selections for each mode. */\nexport interface CustomPack {\n name: string;\n models: Record<string, string>;\n createdAt: string;\n}\n\n/** A saved custom provider for OpenAI-compatible endpoints. */\nexport interface CustomProviderSetting {\n name: string;\n url: string;\n apiKey?: string;\n models: string[];\n}\n\n/** Storage backend type. */\nexport type StorageBackend = 'libsql' | 'pg';\n\n/** Experimental agent implementation used by MastraCode. */\nexport type ExperimentalAgent = 'durable' | 'evented';\n\nexport class ExperimentalAgentSettingsError extends Error {\n readonly value: unknown;\n\n constructor(value: unknown, settingsPath?: string) {\n super(\n `Invalid \"experimentalAgent\" setting${settingsPath ? ` in ${settingsPath}` : ''}: ${JSON.stringify(value)}. ` +\n `Remove the \"experimentalAgent\" key or set it to \"durable\", \"evented\", or null.`,\n );\n this.name = 'ExperimentalAgentSettingsError';\n this.value = value;\n }\n}\n\n/** LibSQL-specific storage settings. */\nexport interface LibSQLStorageSettings {\n url?: string;\n authToken?: string;\n}\n\n/** PostgreSQL-specific storage settings. */\nexport interface PgStorageSettings {\n connectionString?: string;\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n password?: string;\n schemaName?: string;\n disableInit?: boolean;\n skipDefaultIndexes?: boolean;\n}\n\n/** Storage configuration persisted in global settings. */\nexport interface StorageSettings {\n /** Which backend to use. Default: 'libsql'. */\n backend: StorageBackend;\n /** LibSQL-specific config (used when backend is 'libsql'). */\n libsql: LibSQLStorageSettings;\n /** PostgreSQL-specific config (used when backend is 'pg'). */\n pg: PgStorageSettings;\n}\n\n/** Gateway provider key used in AuthStorage. */\nexport const MASTRA_GATEWAY_PROVIDER = 'mastra-gateway';\n\n/** Default gateway URL. */\nexport const MASTRA_GATEWAY_DEFAULT_URL = 'https://gateway-api.mastra.ai';\n\n/** @deprecated Renamed to {@link MASTRA_GATEWAY_PROVIDER}. */\nexport const MEMORY_GATEWAY_PROVIDER = MASTRA_GATEWAY_PROVIDER;\n\n/** @deprecated Renamed to {@link MASTRA_GATEWAY_DEFAULT_URL}. */\nexport const MEMORY_GATEWAY_DEFAULT_URL = MASTRA_GATEWAY_DEFAULT_URL;\n\n/** Preferred model-independent web search/extract provider. */\nexport type WebSearchProviderSetting = 'auto' | 'tavily' | 'parallel';\n\n/** Browser provider type. */\nexport type BrowserProvider = 'stagehand' | 'agent-browser';\n\n/** Direct TUI `!` shell passthrough mode. */\nexport type ShellPassthroughSettingsMode = 'default' | 'path' | 'login';\n\n/** Direct TUI `!` shell command language. */\nexport type ShellPassthroughSettingsFamily = 'posix' | 'cmd' | 'powershell';\n\n/** Direct TUI `!` shell passthrough configuration. */\nexport interface ShellPassthroughSettings {\n mode?: ShellPassthroughSettingsMode | string;\n executable?: string;\n family?: ShellPassthroughSettingsFamily | string;\n}\n\n/** STT engine: on-device macOS recognizer or a cloud provider. */\nexport type VoiceEngine = 'macos-native' | 'cloud';\n\n/** Voice (hold-space dictation) configuration persisted in global settings. */\nexport interface VoiceSettings {\n /** Whether hold-space voice input is enabled. */\n enabled: boolean;\n /** Which STT engine to use. Defaults to macOS native on darwin, else cloud. */\n engine: VoiceEngine;\n /** Cloud provider id (matches an STT registry entry). Cloud engine only. */\n provider: string;\n /** Cloud model id; defaults to the provider's first registry model. */\n model?: string;\n}\n\n/** Stagehand environment type. */\nexport type StagehandEnv = 'LOCAL' | 'BROWSERBASE';\n\n/**\n * Browser viewport: explicit dimensions, or `'window'` to follow the real\n * browser window instead of emulating a fixed size.\n */\nexport type BrowserViewport = { width: number; height: number } | 'window';\n\n/** Named viewport sizes offered by `/browser set viewport`. */\nexport const VIEWPORT_PRESETS = {\n desktop: { width: 1280, height: 720 },\n 'desktop-hd': { width: 1920, height: 1080 },\n laptop: { width: 1440, height: 900 },\n tablet: { width: 768, height: 1024 },\n mobile: { width: 390, height: 844 },\n} as const satisfies Record<string, { width: number; height: number }>;\n\nexport type ViewportPreset = keyof typeof VIEWPORT_PRESETS;\n\n/**\n * Largest viewport dimension accepted. Guards against typos that would launch a\n * browser far larger than any display.\n */\nconst MAX_VIEWPORT_DIMENSION = 10000;\n\nfunction isValidDimension(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 && value <= MAX_VIEWPORT_DIMENSION;\n}\n\n/**\n * Parse a `WIDTHxHEIGHT` string (e.g. `1280x720`), a preset name, or `window`.\n * Returns undefined when the input is not a usable viewport.\n */\nexport function parseViewportInput(input: string): BrowserViewport | undefined {\n const value = input.trim().toLowerCase();\n if (!value) return undefined;\n if (value === 'window') return 'window';\n if (value in VIEWPORT_PRESETS) return { ...VIEWPORT_PRESETS[value as ViewportPreset] };\n\n const match = /^(\\d+)\\s*[x×]\\s*(\\d+)$/.exec(value);\n if (!match) return undefined;\n const width = Number(match[1]);\n const height = Number(match[2]);\n if (!isValidDimension(width) || !isValidDimension(height)) return undefined;\n return { width, height };\n}\n\n/** Stagehand-specific browser settings. */\nexport interface StagehandSettings {\n env: StagehandEnv;\n apiKey?: string;\n projectId?: string;\n /**\n * Model Stagehand uses for its AI operations, as `provider/model`\n * (for example `anthropic/claude-sonnet-4-5`). Stagehand resolves the\n * provider's API key from the environment (`ANTHROPIC_API_KEY`,\n * `OPENAI_API_KEY`, and so on). Defaults to Stagehand's own default.\n */\n model?: string;\n /** Whether to preserve the user data directory after the browser closes. */\n preserveUserDataDir?: boolean;\n}\n\n/** AgentBrowser-specific browser settings. */\nexport interface AgentBrowserSettings {\n /** Path to a Playwright storage state file (JSON) containing cookies and localStorage. */\n storageState?: string;\n}\n\n/** Browser configuration persisted in global settings. */\nexport interface BrowserSettings {\n /** Whether browser automation is enabled. */\n enabled: boolean;\n /** Which browser provider to use. */\n provider: BrowserProvider;\n /** Whether to run headless (no visible browser window). */\n headless: boolean;\n /**\n * Browser viewport dimensions, or `'window'` to disable viewport emulation so\n * the page follows the real browser window.\n */\n viewport?: BrowserViewport;\n /** CDP URL for connecting to an existing browser. */\n cdpUrl?: string;\n /** Path to a Chrome/Chromium user data directory (profile). */\n profile?: string;\n /** Path to the browser executable to use. */\n executablePath?: string;\n /** Browser scope — 'shared' (all threads share one browser) or 'thread' (each thread gets its own). */\n scope?: 'shared' | 'thread';\n /** Stagehand-specific settings. */\n stagehand?: StagehandSettings;\n /** AgentBrowser-specific settings. */\n agentBrowser?: AgentBrowserSettings;\n}\n\nexport type PackAccountPreferences = Record<string, Record<string, string>>;\n\nexport interface GlobalSettings {\n // Onboarding tracking\n onboarding: {\n completedAt: string | null;\n skippedAt: string | null;\n version: number;\n modePackId: string | null;\n omPackId: string | null;\n };\n // Global model preferences (applied to new threads)\n models: {\n /**\n * Active model pack ID. Built-in packs use their id directly (\"anthropic\",\n * \"openai\"). Custom packs use \"custom:<name>\".\n * When set, models are resolved from the pack at startup so pack updates\n * (e.g. new model versions) apply automatically. Built-in packs may layer\n * explicit modePackOverrides over these defaults.\n */\n activeModelPackId: string | null;\n /** Per-mode overrides keyed by built-in pack ID. */\n modePackOverrides: Record<string, Record<string, string>>;\n /**\n * Fallback pack per pack ID (packId → packId; builtin ids and\n * \"custom:<name>\" both allowed). When every account serving a pack's\n * provider is exhausted — or the provider is persistently down — the turn\n * hops to the fallback pack's model. Chains are allowed; a cycle is\n * capped at one revisit per cascade, then the error surfaces.\n */\n packFallbacks: Record<string, string>;\n /** Preferred OAuth account by pack ID and resolved model ID. */\n packAccountPreferences: Record<string, Record<string, string>>;\n /** Explicit per-mode defaults — used when no activeModelPackId is set. */\n modeDefaults: Record<string, string>;\n /**\n * Per-mode reasoning-effort defaults (e.g. { build: \"high\", plan: \"xhigh\" }).\n * Resolved at request time; falls back to `preferences.thinkingLevel` for\n * modes without an entry. Overridden per-session via /think or the session\n * settings panel.\n */\n modeThinkingDefaults: Record<string, ThinkingLevelSetting>;\n /**\n * Active OM pack ID (e.g. \"gemini\", \"anthropic\", \"custom\").\n * When set, the OM model is resolved from the pack at startup so pack\n * updates (e.g. new model versions) apply automatically.\n * Cleared when the user manually overrides via /om (falls back to omModelOverride).\n */\n activeOmPackId: string | null;\n /**\n * Shared OM model override — used for both observer and reflector when a\n * role-specific override is not set. Kept for back-compat with older settings\n * files and set by onboarding when the user picks a custom OM pack.\n */\n omModelOverride: string | null;\n /**\n * Explicit Observer model override — takes precedence over `omModelOverride`\n * when set. Written by `/om` when the observer model is changed independently.\n */\n observerModelOverride: string | null;\n /** Persisted Observer model intent. Missing values use legacy-field compatibility. */\n observerModelSelection: OMModel | null;\n /**\n * Explicit Reflector model override — takes precedence over `omModelOverride`\n * when set. Written by `/om` when the reflector model is changed independently.\n */\n reflectorModelOverride: string | null;\n /** Persisted Reflector model intent. Missing values use legacy-field compatibility. */\n reflectorModelSelection: OMModel | null;\n /** Default OM observation threshold used for new threads unless overridden per-thread. */\n omObservationThreshold: number | null;\n /** Default OM reflection threshold used for new threads unless overridden per-thread. */\n omReflectionThreshold: number | null;\n /**\n * Whether observations and reflections use the terse caveman-style instruction.\n * `null` means inherit the built-in default (currently `false` — caveman is\n * opt-in via `/om` settings). Used as the default for new threads unless\n * overridden per-thread.\n */\n omCavemanObservations: boolean | null;\n /**\n * Whether Observational Memory forwards image/file attachment parts to the\n * Observer LLM. `null` ⇒ inherit built-in default ('auto'). 'auto' checks\n * model capabilities; true/false forces the setting.\n */\n omObserveAttachments: 'auto' | boolean | null;\n /** Per-agent-type subagent model overrides (e.g. { explore: \"openai/gpt-5.1-codex-mini\" }) */\n subagentModels: Record<string, string>;\n /** Default judge model for /goal. */\n goalJudgeModel: string | null;\n /** Default max attempts for /goal. */\n goalMaxTurns: number | null;\n };\n // Global behavior preferences\n preferences: {\n yolo: boolean | null;\n /** 'auto' | 'dark' | 'light', or the name of a custom theme file in ~/.mastracode/themes/<name>.json */\n theme: 'auto' | 'dark' | 'light' | (string & {});\n /** Default reasoning effort level used for all threads/models unless overridden in-session. */\n thinkingLevel: ThinkingLevelSetting;\n /** Whether native subagents are enabled for Mastra Code TUI sessions. */\n subagentsEnabled: boolean;\n /** Maximum detail preview lines shown under compact tool calls (0-8). Set to 0 to hide previews. */\n previewLines: number;\n /**\n * Default web search/extract provider. `auto` picks the first configured\n * provider key (Tavily, then Parallel). An explicit provider is only\n * honored while its API key is configured.\n */\n webSearchProvider: WebSearchProviderSetting;\n };\n // Storage backend configuration\n storage: StorageSettings;\n // User-created custom model packs\n customModelPacks: CustomPack[];\n // User-created custom providers with custom models\n customProviders: CustomProviderSetting[];\n // Model usage counts for ranking in the selector\n modelUseCounts: Record<string, number>;\n // Version the user dismissed the update prompt for (skip until they manually update past this)\n updateDismissedVersion: string | null;\n // Mastra gateway configuration\n memoryGateway: { baseUrl?: string };\n // LSP configuration forwarded to the workspace. Disabled unless the user\n // opts in with `true` or an LSPConfig object.\n lsp?: boolean | LSPConfig;\n // Browser automation configuration\n browser: BrowserSettings;\n // Direct TUI `!` shell passthrough configuration\n shellPassthrough: ShellPassthroughSettings;\n // Hold-space voice input configuration\n voice: VoiceSettings;\n // Raw persisted experimental agent value. Resolve through resolveExperimentalAgent() before use.\n experimentalAgent: unknown;\n // Internal load diagnostic retained on clones until the user repairs the setting.\n _experimentalAgentSettingsPath?: string;\n // Native background execution for eligible Mastra Code tools\n backgroundTools: BackgroundToolSettings;\n // Signal routing configuration\n signals: SignalSettings;\n // Read-only discovery of MCP servers configured by other coding agents\n mcp: McpDiscoverySettings;\n // Cloud observability configuration (per-resource project IDs; tokens stored in auth.json)\n observability: ObservabilitySettings;\n // Remote Factory connection selected via /factory (null = run locally)\n factory: FactoryConnectionSettings | null;\n}\n\nexport interface FactoryConnectionSettings {\n url: string;\n orgId: string;\n projectId: string;\n projectName: string;\n environmentId: string;\n environmentName: string;\n factoryProjectId: string;\n factoryProjectName: string;\n projectRepositoryId: string;\n repositorySlug: string;\n /** Factory user session ID; addresses the remote agent-controller session as its resourceId. */\n sessionId: string;\n branch: string;\n /** False keeps the connection saved but starts Mastra Code locally. */\n active?: boolean;\n}\n\nfunction parseFactoryConnectionSettings(raw: unknown): FactoryConnectionSettings | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const keys = [\n 'url',\n 'orgId',\n 'projectId',\n 'projectName',\n 'environmentId',\n 'environmentName',\n 'factoryProjectId',\n 'factoryProjectName',\n 'projectRepositoryId',\n 'repositorySlug',\n 'sessionId',\n 'branch',\n ] as const;\n if (!keys.every(key => typeof obj[key] === 'string' && obj[key])) return null;\n const parsed = Object.fromEntries(keys.map(key => [key, obj[key]])) as unknown as FactoryConnectionSettings;\n if (obj.active === false) parsed.active = false;\n return parsed;\n}\n\nexport interface McpDiscoverySettings {\n /** Reuse top-level MCP servers from ~/.claude.json. */\n claudeCodeGlobal: boolean;\n /** Reuse MCP servers from $CODEX_HOME/config.toml or ~/.codex/config.toml. */\n codexGlobal: boolean;\n}\n\nexport interface BackgroundToolSettings {\n /** Allow eligible Mastra Code tools to accept per-call background execution overrides. */\n enabled: boolean;\n}\n\nexport interface SignalSettings {\n /** Opt into local Unix socket PubSub for cross-process signal routing. */\n unixSocketPubSub: boolean;\n /** Experimental: enable GitHub PR subscription signals backed by gitcrawl. */\n experimentalGithubSignals: boolean;\n /** Experimental: enable cross-agent communication (thread ownership advertisement, peer discovery, and agent connection tools). */\n experimentalCrossAgentSignals: boolean;\n /** Experimental: give the agent tools to create and manage `/schedules` schedules on its thread. */\n experimentalScheduleTools: boolean;\n /** Poll interval for GitHub PR subscriptions. */\n githubPollIntervalMs: number;\n}\n\nexport interface ObservabilityResourceConfig {\n /** Cloud project ID for this resource */\n projectId: string;\n /** When this config was created */\n configuredAt: string;\n}\n\nexport interface ObservabilitySettings {\n /** Per-resource cloud project configs, keyed by resourceId */\n resources: Record<string, ObservabilityResourceConfig>;\n /** Whether to store traces locally in DuckDB. Off by default to avoid disk usage. */\n localTracing: boolean;\n}\n\n/** Auth key prefix for observability tokens stored per-resource in auth.json */\nexport const OBSERVABILITY_AUTH_PREFIX = 'observability:';\n\nexport const GITHUB_POLL_INTERVAL_DEFAULT_MS = 300_000;\nexport const GITHUB_POLL_INTERVAL_MIN_MS = 10_000;\nexport const GITHUB_POLL_INTERVAL_MAX_MS = 2_147_483_647;\n\nexport const STORAGE_DEFAULTS: StorageSettings = {\n backend: 'libsql',\n libsql: {},\n pg: {},\n};\n\n/** Default STT engine: on-device macOS recognizer where available, else cloud. */\nexport function defaultVoiceEngine(): VoiceEngine {\n return process.platform === 'darwin' ? 'macos-native' : 'cloud';\n}\n\nconst DEFAULTS: GlobalSettings = {\n onboarding: {\n completedAt: null,\n skippedAt: null,\n version: 0,\n modePackId: null,\n omPackId: null,\n },\n models: {\n activeModelPackId: null,\n modePackOverrides: {},\n packFallbacks: {},\n packAccountPreferences: {},\n modeDefaults: {},\n modeThinkingDefaults: {},\n activeOmPackId: null,\n omModelOverride: null,\n observerModelOverride: null,\n observerModelSelection: null,\n reflectorModelOverride: null,\n reflectorModelSelection: null,\n omObservationThreshold: null,\n omReflectionThreshold: null,\n omCavemanObservations: null,\n omObserveAttachments: null,\n subagentModels: {},\n goalJudgeModel: null,\n goalMaxTurns: null,\n },\n preferences: {\n yolo: null,\n theme: 'auto',\n thinkingLevel: 'off',\n subagentsEnabled: false,\n previewLines: 2,\n webSearchProvider: 'auto',\n },\n storage: { ...STORAGE_DEFAULTS },\n customModelPacks: [],\n customProviders: [],\n modelUseCounts: {},\n updateDismissedVersion: null,\n memoryGateway: {},\n lsp: false,\n browser: {\n enabled: false,\n provider: 'stagehand',\n headless: false,\n viewport: { ...VIEWPORT_PRESETS.desktop },\n stagehand: { env: 'LOCAL' },\n },\n shellPassthrough: { mode: 'default' },\n voice: { enabled: false, engine: defaultVoiceEngine(), provider: DEFAULT_STT_PROVIDER },\n experimentalAgent: null,\n backgroundTools: { enabled: false },\n signals: {\n unixSocketPubSub: false,\n experimentalGithubSignals: false,\n experimentalCrossAgentSignals: false,\n experimentalScheduleTools: false,\n githubPollIntervalMs: GITHUB_POLL_INTERVAL_DEFAULT_MS,\n },\n mcp: { claudeCodeGlobal: false, codexGlobal: false },\n observability: { resources: {}, localTracing: false },\n factory: null,\n};\n\nexport const WEB_SEARCH_PROVIDER_VALUES: WebSearchProviderSetting[] = ['auto', 'tavily', 'parallel'];\nconst PREVIEW_LINES_MAX = 8;\nconst loadedSignalSettings = new WeakMap<GlobalSettings, SignalSettings>();\n\nfunction cloneSignalSettings(signals: SignalSettings): SignalSettings {\n return { ...signals };\n}\n\nfunction rememberLoadedSettings(settings: GlobalSettings): GlobalSettings {\n loadedSignalSettings.set(settings, cloneSignalSettings(settings.signals));\n return settings;\n}\n\nfunction signalSettingsEqual(left: SignalSettings, right: SignalSettings): boolean {\n return (\n left.unixSocketPubSub === right.unixSocketPubSub &&\n left.experimentalGithubSignals === right.experimentalGithubSignals &&\n left.experimentalCrossAgentSignals === right.experimentalCrossAgentSignals &&\n left.experimentalScheduleTools === right.experimentalScheduleTools &&\n left.githubPollIntervalMs === right.githubPollIntervalMs\n );\n}\n\nfunction parseWebSearchProvider(value: unknown): WebSearchProviderSetting {\n return typeof value === 'string' && WEB_SEARCH_PROVIDER_VALUES.includes(value as WebSearchProviderSetting)\n ? (value as WebSearchProviderSetting)\n : DEFAULTS.preferences.webSearchProvider;\n}\n\nfunction parseThinkingLevel(value: unknown): ThinkingLevelSetting {\n return isThinkingLevelSetting(value) ? value : DEFAULTS.preferences.thinkingLevel;\n}\n\nfunction parseModeThinkingDefaults(value: unknown): Record<string, ThinkingLevelSetting> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, ThinkingLevelSetting> = {};\n for (const [mode, level] of Object.entries(value as Record<string, unknown>)) {\n if (isThinkingLevelSetting(level)) {\n result[mode] = level;\n }\n }\n return result;\n}\n\nfunction parseModePackOverrides(value: unknown): Record<string, Record<string, string>> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, Record<string, string>> = {};\n for (const [packId, overrides] of Object.entries(value as Record<string, unknown>)) {\n if (!overrides || typeof overrides !== 'object') continue;\n const parsedOverrides = Object.fromEntries(\n Object.entries(overrides as Record<string, unknown>).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1].length > 0,\n ),\n );\n if (Object.keys(parsedOverrides).length > 0) result[packId] = parsedOverrides;\n }\n return result;\n}\n\nfunction parsePackFallbacks(value: unknown): Record<string, string> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, string> = {};\n for (const [packId, fallbackId] of Object.entries(value as Record<string, unknown>)) {\n if (typeof fallbackId === 'string' && fallbackId.length > 0) result[packId] = fallbackId;\n }\n return result;\n}\n\n/** Shape-parse + drop entries whose source or target pack no longer exists. */\nfunction loadPackFallbacks(value: unknown, customModelPacks: Array<{ name: string }>): Record<string, string> {\n return pruneUnknownModePackFallbacks(parsePackFallbacks(value), customModelPacks);\n}\n\nfunction parsePackAccountPreferences(value: unknown): Record<string, Record<string, string>> {\n if (!value || typeof value !== 'object') return {};\n const result: Record<string, Record<string, string>> = {};\n for (const [packId, modelPreferences] of Object.entries(value as Record<string, unknown>)) {\n if (!modelPreferences || typeof modelPreferences !== 'object') continue;\n const parsed = Object.fromEntries(\n Object.entries(modelPreferences as Record<string, unknown>).filter(\n (entry): entry is [string, string] =>\n entry[0].length > 0 && typeof entry[1] === 'string' && entry[1].length > 0,\n ),\n );\n if (Object.keys(parsed).length > 0) result[packId] = parsed;\n }\n return result;\n}\n\nfunction loadPackAccountPreferences(\n value: unknown,\n customModelPacks: CustomPack[],\n modePackOverrides: Record<string, Record<string, string>>,\n): PackAccountPreferences {\n return pruneUnknownPackAccountPreferences(parsePackAccountPreferences(value), customModelPacks, modePackOverrides);\n}\n\n/** Move persisted routing choices when re-authentication changes an account instance id. */\nexport function migrateAccountPreferences(\n settings: GlobalSettings,\n previousAccountId: string,\n nextAccountId: string,\n): void {\n if (previousAccountId === nextAccountId) return;\n for (const modelPreferences of Object.values(settings.models.packAccountPreferences ?? {})) {\n for (const [modelId, accountInstanceId] of Object.entries(modelPreferences)) {\n if (accountInstanceId === previousAccountId) modelPreferences[modelId] = nextAccountId;\n }\n }\n}\n\n/** Remove persisted routing choices that point at deleted OAuth account instances. */\nexport function pruneRemovedAccountPreferences(settings: GlobalSettings, removedAccountIds: Iterable<string>): void {\n const removed = new Set(removedAccountIds);\n if (removed.size === 0) return;\n\n const next: PackAccountPreferences = {};\n for (const [packId, modelPreferences] of Object.entries(settings.models.packAccountPreferences ?? {})) {\n const retained = Object.fromEntries(\n Object.entries(modelPreferences).filter(([, accountInstanceId]) => !removed.has(accountInstanceId)),\n );\n if (Object.keys(retained).length > 0) next[packId] = retained;\n }\n settings.models.packAccountPreferences = next;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/**\n * Resolves the preview line limit. `previewLines` wins when valid; otherwise the legacy\n * `quietModeMaxToolPreviewLines` key (still written by older Mastra Code versions) is used.\n */\nfunction parsePreviewLines(raw: Record<string, unknown>): number {\n const value = isFiniteNumber(raw.previewLines)\n ? raw.previewLines\n : isFiniteNumber(raw.quietModeMaxToolPreviewLines)\n ? raw.quietModeMaxToolPreviewLines\n : DEFAULTS.preferences.previewLines;\n return Math.min(PREVIEW_LINES_MAX, Math.max(0, Math.floor(value)));\n}\n\nfunction parsePreferences(rawPreferences: unknown): GlobalSettings['preferences'] {\n const raw = rawPreferences && typeof rawPreferences === 'object' ? (rawPreferences as Record<string, unknown>) : {};\n\n return {\n ...DEFAULTS.preferences,\n ...raw,\n thinkingLevel: parseThinkingLevel(raw.thinkingLevel),\n subagentsEnabled:\n typeof raw.subagentsEnabled === 'boolean' ? raw.subagentsEnabled : DEFAULTS.preferences.subagentsEnabled,\n previewLines: parsePreviewLines(raw),\n webSearchProvider: parseWebSearchProvider(raw.webSearchProvider),\n };\n}\n\nfunction parseGithubPollIntervalMs(value: unknown): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return DEFAULTS.signals.githubPollIntervalMs;\n const intervalMs = Math.floor(value);\n if (intervalMs < GITHUB_POLL_INTERVAL_MIN_MS) return DEFAULTS.signals.githubPollIntervalMs;\n return Math.min(intervalMs, GITHUB_POLL_INTERVAL_MAX_MS);\n}\n\nexport function parseExperimentalAgentSetting(value: unknown, settingsPath?: string): ExperimentalAgent | null {\n if (value === undefined || value === null) return null;\n if (value === 'durable' || value === 'evented') return value;\n throw new ExperimentalAgentSettingsError(value, settingsPath);\n}\n\nfunction loadExperimentalAgentSetting(\n value: unknown,\n settingsPath: string,\n): { selection: unknown; settingsPath?: string } {\n try {\n return { selection: parseExperimentalAgentSetting(value, settingsPath) };\n } catch (error) {\n if (error instanceof ExperimentalAgentSettingsError) {\n return { selection: error.value, settingsPath };\n }\n throw error;\n }\n}\n\nfunction parseBackgroundToolSettings(rawBackgroundTools: unknown): BackgroundToolSettings {\n const raw =\n rawBackgroundTools && typeof rawBackgroundTools === 'object' ? (rawBackgroundTools as Record<string, unknown>) : {};\n return {\n enabled: typeof raw.enabled === 'boolean' ? raw.enabled : DEFAULTS.backgroundTools.enabled,\n };\n}\n\nfunction parseSignalSettings(rawSignals: unknown): SignalSettings {\n const raw = rawSignals && typeof rawSignals === 'object' ? (rawSignals as Record<string, unknown>) : {};\n return {\n unixSocketPubSub:\n typeof raw.unixSocketPubSub === 'boolean' ? raw.unixSocketPubSub : DEFAULTS.signals.unixSocketPubSub,\n experimentalGithubSignals:\n typeof raw.experimentalGithubSignals === 'boolean'\n ? raw.experimentalGithubSignals\n : DEFAULTS.signals.experimentalGithubSignals,\n experimentalCrossAgentSignals:\n typeof raw.experimentalCrossAgentSignals === 'boolean'\n ? raw.experimentalCrossAgentSignals\n : DEFAULTS.signals.experimentalCrossAgentSignals,\n experimentalScheduleTools:\n typeof raw.experimentalScheduleTools === 'boolean'\n ? raw.experimentalScheduleTools\n : DEFAULTS.signals.experimentalScheduleTools,\n githubPollIntervalMs: parseGithubPollIntervalMs(raw.githubPollIntervalMs),\n };\n}\n\nfunction parseMcpDiscoverySettings(rawMcp: unknown): McpDiscoverySettings {\n const raw = rawMcp && typeof rawMcp === 'object' ? (rawMcp as Record<string, unknown>) : {};\n return {\n claudeCodeGlobal: typeof raw.claudeCodeGlobal === 'boolean' ? raw.claudeCodeGlobal : DEFAULTS.mcp.claudeCodeGlobal,\n codexGlobal: typeof raw.codexGlobal === 'boolean' ? raw.codexGlobal : DEFAULTS.mcp.codexGlobal,\n };\n}\n\nexport function getSettingsPath(): string {\n return join(getAppDataDir(), 'settings.json');\n}\n\nexport function getCustomProviderId(name: string): string {\n const slug = name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return slug || 'provider';\n}\n\nexport function toCustomProviderModelId(providerName: string, modelName: string): string {\n const providerId = getCustomProviderId(providerName);\n const trimmedModelName = modelName.trim();\n const providerPrefix = `${providerId}/`;\n if (trimmedModelName.startsWith(providerPrefix)) {\n return trimmedModelName;\n }\n return `${providerId}/${trimmedModelName}`;\n}\n\n/**\n * The shared gateway catalog namespaces provider keys under their owning\n * gateway id, so a custom provider's models surface in the `/models` catalog\n * as `mastracode/<providerId>/<model>` instead of the canonical\n * `<providerId>/<model>` that model resolution expects. Persisting the\n * gateway-qualified id verbatim breaks lookup later (the provider is parsed\n * as `mastracode`). Strip the prefix before saving — but only when the\n * middle segment matches one of the user's configured custom providers, so\n * legitimate `mastracode/...` gateway-routed ids are left untouched.\n */\nexport function stripMastraCodeCustomProviderPrefix(\n modelId: string,\n customProviders: Array<Pick<CustomProviderSetting, 'name'>>,\n): string {\n const gatewayPrefix = 'mastracode/';\n if (!modelId.startsWith(gatewayPrefix)) return modelId;\n\n const rest = modelId.slice(gatewayPrefix.length);\n const [providerId, ...modelParts] = rest.split('/');\n if (!providerId || modelParts.length === 0 || modelParts.some(part => part.length === 0)) return modelId;\n\n const isCustomProvider = customProviders.some(provider => getCustomProviderId(provider.name) === providerId);\n return isCustomProvider ? rest : modelId;\n}\n\nexport function parseCustomProviders(rawProviders: unknown): CustomProviderSetting[] {\n if (!Array.isArray(rawProviders)) return [];\n\n const parsedProviders: CustomProviderSetting[] = [];\n for (const rawProvider of rawProviders) {\n if (!rawProvider || typeof rawProvider !== 'object') continue;\n\n const candidate = rawProvider as Record<string, unknown>;\n const name = typeof candidate.name === 'string' ? candidate.name.trim() : '';\n const url = typeof candidate.url === 'string' ? candidate.url.trim() : '';\n if (!name || !url) continue;\n\n const providerId = getCustomProviderId(name);\n const models = Array.isArray(candidate.models)\n ? [\n ...new Set(\n candidate.models\n .filter((model): model is string => typeof model === 'string')\n .map(model => model.trim())\n .map(model => {\n const providerPrefix = `${providerId}/`;\n if (model.startsWith(providerPrefix)) {\n return model.slice(providerPrefix.length);\n }\n return model;\n }),\n ),\n ].filter(model => model.length > 0)\n : [];\n\n const apiKey =\n typeof candidate.apiKey === 'string' && candidate.apiKey.trim().length > 0 ? candidate.apiKey.trim() : undefined;\n\n parsedProviders.push({\n name,\n url,\n ...(apiKey ? { apiKey } : {}),\n models,\n });\n }\n\n return parsedProviders;\n}\n\nconst BROWSER_PROVIDERS = new Set<BrowserProvider>(['stagehand', 'agent-browser']);\nconst STAGEHAND_ENVS = new Set<StagehandEnv>(['LOCAL', 'BROWSERBASE']);\n\n/**\n * Normalize a Stagehand model id, which must be provider-qualified.\n *\n * Stagehand reads the segment before the first slash as the provider, so a\n * bare id like `gpt-4.1` is rejected as an unknown provider and a trailing\n * slash leaves an empty model name that only fails once a request is made.\n * Neither is usable, so both are dropped here rather than persisted.\n *\n * The provider name itself is checked where the command is issued, which can\n * name the supported providers in an error; this module is on the startup path\n * and only imports Stagehand lazily.\n *\n * @returns the trimmed model id, or undefined when it is unusable.\n */\nfunction parseStagehandModel(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const model = value.trim();\n const separator = model.indexOf('/');\n if (separator <= 0) return undefined;\n return model.slice(separator + 1).trim() ? model : undefined;\n}\n\n/**\n * Validate a viewport read from settings.json, falling back to the default when\n * it is missing or malformed.\n */\nfunction parseStoredViewport(raw: unknown): BrowserViewport {\n if (raw === 'window') return 'window';\n if (raw && typeof raw === 'object') {\n const { width, height } = raw as Record<string, unknown>;\n if (isValidDimension(width) && isValidDimension(height)) return { width, height };\n }\n return { ...VIEWPORT_PRESETS.desktop };\n}\n\n/**\n * Validate the `lsp` setting from JSON. Accepts both the boolean opt-in/opt-out\n * form and the full LSPConfig object; anything else is treated as unset.\n */\nfunction parseLspSettings(raw: unknown): boolean | LSPConfig | undefined {\n if (typeof raw === 'boolean') return raw;\n if (raw && typeof raw === 'object') return raw as LSPConfig;\n return undefined;\n}\n\n/**\n * Resolve the effective LSP config. LSP is opt-in: `false` and an absent\n * setting both mean disabled, `true` means enabled with defaults.\n */\nexport function resolveLspSetting(lsp: boolean | LSPConfig | undefined): LSPConfig | false {\n if (lsp === true) return {};\n if (!lsp) return false;\n return lsp;\n}\n\n/**\n * Deep-merge and validate browser settings from JSON.\n * Explicitly validates types to handle malformed settings.json gracefully.\n */\nfunction parseBrowserSettings(rawBrowser: unknown): BrowserSettings {\n const raw = rawBrowser && typeof rawBrowser === 'object' ? (rawBrowser as Record<string, unknown>) : {};\n const rawStagehand =\n raw.stagehand && typeof raw.stagehand === 'object' ? (raw.stagehand as Record<string, unknown>) : {};\n const stagehandModel = parseStagehandModel(rawStagehand.model);\n const rawAgentBrowser =\n raw.agentBrowser && typeof raw.agentBrowser === 'object' ? (raw.agentBrowser as Record<string, unknown>) : {};\n\n return {\n enabled: typeof raw.enabled === 'boolean' ? raw.enabled : DEFAULTS.browser.enabled,\n provider:\n typeof raw.provider === 'string' && BROWSER_PROVIDERS.has(raw.provider as BrowserProvider)\n ? (raw.provider as BrowserProvider)\n : DEFAULTS.browser.provider,\n headless: typeof raw.headless === 'boolean' ? raw.headless : DEFAULTS.browser.headless,\n cdpUrl: typeof raw.cdpUrl === 'string' && raw.cdpUrl.trim() ? raw.cdpUrl.trim() : undefined,\n profile: typeof raw.profile === 'string' && raw.profile.trim() ? raw.profile.trim() : undefined,\n executablePath:\n typeof raw.executablePath === 'string' && raw.executablePath.trim() ? raw.executablePath.trim() : undefined,\n viewport: parseStoredViewport(raw.viewport),\n scope: typeof raw.scope === 'string' && (raw.scope === 'shared' || raw.scope === 'thread') ? raw.scope : undefined,\n stagehand: {\n env:\n typeof rawStagehand.env === 'string' && STAGEHAND_ENVS.has(rawStagehand.env as StagehandEnv)\n ? (rawStagehand.env as StagehandEnv)\n : DEFAULTS.browser.stagehand!.env,\n ...(typeof rawStagehand.apiKey === 'string' && rawStagehand.apiKey.trim()\n ? { apiKey: rawStagehand.apiKey.trim() }\n : {}),\n ...(typeof rawStagehand.projectId === 'string' && rawStagehand.projectId.trim()\n ? { projectId: rawStagehand.projectId.trim() }\n : {}),\n ...(stagehandModel ? { model: stagehandModel } : {}),\n ...(typeof rawStagehand.preserveUserDataDir === 'boolean'\n ? { preserveUserDataDir: rawStagehand.preserveUserDataDir }\n : {}),\n },\n agentBrowser:\n typeof rawAgentBrowser.storageState === 'string' && rawAgentBrowser.storageState.trim()\n ? { storageState: rawAgentBrowser.storageState.trim() }\n : undefined,\n };\n}\n\nfunction parseShellPassthroughSettings(rawShellPassthrough: unknown): ShellPassthroughSettings {\n const raw =\n rawShellPassthrough && typeof rawShellPassthrough === 'object'\n ? (rawShellPassthrough as Record<string, unknown>)\n : {};\n const executable = typeof raw.executable === 'string' && raw.executable.trim() ? raw.executable.trim() : undefined;\n const family = typeof raw.family === 'string' && raw.family.trim() ? raw.family.trim() : undefined;\n const mode = typeof raw.mode === 'string' && raw.mode.trim() ? raw.mode.trim() : undefined;\n const defaultMode = executable ? undefined : DEFAULTS.shellPassthrough.mode;\n\n return {\n ...((mode ?? defaultMode) ? { mode: mode ?? defaultMode } : {}),\n ...(executable ? { executable } : {}),\n ...(family ? { family } : {}),\n };\n}\n\nfunction parseVoiceSettings(rawVoice: unknown): VoiceSettings {\n const raw = rawVoice && typeof rawVoice === 'object' ? (rawVoice as Record<string, unknown>) : {};\n const enabled = typeof raw.enabled === 'boolean' ? raw.enabled : DEFAULTS.voice.enabled;\n const engine: VoiceEngine =\n raw.engine === 'macos-native' || raw.engine === 'cloud' ? raw.engine : defaultVoiceEngine();\n // Validate provider/model against the registry, falling back to a usable entry\n // so old `{ enabled }`-only files and unknown values still resolve cleanly.\n const provider = typeof raw.provider === 'string' ? raw.provider : DEFAULTS.voice.provider;\n const model = typeof raw.model === 'string' ? raw.model : undefined;\n const resolved = resolveSTTModel(provider, model);\n return {\n enabled,\n engine,\n provider: resolved.provider,\n model: resolved.model,\n };\n}\n\nconst VALID_PROJECT_ID = /^[a-zA-Z0-9_-]+$/;\n\nfunction parseObservabilitySettings(raw: unknown): ObservabilitySettings {\n if (!raw || typeof raw !== 'object') return { resources: {}, localTracing: false };\n const obj = raw as Record<string, unknown>;\n const localTracing = obj.localTracing === true;\n const rawResources = obj.resources;\n if (!rawResources || typeof rawResources !== 'object') return { resources: {}, localTracing };\n const resources: Record<string, ObservabilityResourceConfig> = {};\n for (const [key, val] of Object.entries(rawResources as Record<string, unknown>)) {\n if (val && typeof val === 'object') {\n const v = val as Record<string, unknown>;\n if (typeof v.projectId === 'string' && VALID_PROJECT_ID.test(v.projectId)) {\n resources[key] = {\n projectId: v.projectId,\n configuredAt: typeof v.configuredAt === 'string' ? v.configuredAt : new Date().toISOString(),\n };\n }\n }\n }\n return { resources, localTracing };\n}\n\n/**\n * One-time migration: move model-related data from auth.json to settings.json.\n * Reads `_modelRanks`, `_modeModelId_*`, `_subagentModelId*` from auth.json,\n * merges them into settings, removes them from auth.json, and writes both files.\n * No-ops if auth.json has no _ prefixed model data.\n */\nfunction migrateFromAuth(settingsPath: string): boolean {\n const authPath = join(getAppDataDir(), 'auth.json');\n if (!existsSync(authPath)) return false;\n\n let authData: Record<string, any>;\n try {\n authData = JSON.parse(readFileSync(authPath, 'utf-8'));\n } catch {\n return false;\n }\n\n const modelKeys = Object.keys(authData).filter(k => k.startsWith('_'));\n if (modelKeys.length === 0) return false;\n\n // Load existing settings (or defaults) and merge auth data into it\n let settings: GlobalSettings;\n if (existsSync(settingsPath)) {\n try {\n const raw = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n const rawCustomPacks: CustomPack[] = Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [];\n const modePackOverrides = parseModePackOverrides(raw.models?.modePackOverrides);\n const experimentalAgentSetting = loadExperimentalAgentSetting(raw.experimentalAgent, settingsPath);\n settings = {\n onboarding: { ...DEFAULTS.onboarding, ...raw.onboarding },\n models: {\n ...DEFAULTS.models,\n ...raw.models,\n modePackOverrides,\n modeThinkingDefaults: parseModeThinkingDefaults(raw.models?.modeThinkingDefaults),\n packFallbacks: loadPackFallbacks(raw.models?.packFallbacks, rawCustomPacks),\n packAccountPreferences: loadPackAccountPreferences(\n raw.models?.packAccountPreferences,\n rawCustomPacks,\n modePackOverrides,\n ),\n },\n preferences: parsePreferences(raw.preferences),\n storage: {\n ...STORAGE_DEFAULTS,\n ...raw.storage,\n libsql: { ...STORAGE_DEFAULTS.libsql, ...raw.storage?.libsql },\n pg: { ...STORAGE_DEFAULTS.pg, ...raw.storage?.pg },\n },\n customModelPacks: Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [],\n customProviders: parseCustomProviders(raw.customProviders),\n modelUseCounts: raw.modelUseCounts && typeof raw.modelUseCounts === 'object' ? raw.modelUseCounts : {},\n updateDismissedVersion: typeof raw.updateDismissedVersion === 'string' ? raw.updateDismissedVersion : null,\n memoryGateway: raw.memoryGateway && typeof raw.memoryGateway === 'object' ? raw.memoryGateway : {},\n lsp: parseLspSettings(raw.lsp),\n browser: parseBrowserSettings(raw.browser),\n shellPassthrough: parseShellPassthroughSettings(raw.shellPassthrough),\n voice: parseVoiceSettings(raw.voice),\n experimentalAgent: experimentalAgentSetting.selection,\n _experimentalAgentSettingsPath: experimentalAgentSetting.settingsPath,\n backgroundTools: parseBackgroundToolSettings(raw.backgroundTools),\n signals: parseSignalSettings(raw.signals),\n mcp: parseMcpDiscoverySettings(raw.mcp),\n observability: parseObservabilitySettings(raw.observability),\n factory: parseFactoryConnectionSettings(raw.factory),\n };\n } catch {\n settings = structuredClone(DEFAULTS);\n }\n } else {\n settings = structuredClone(DEFAULTS);\n }\n\n // Migrate model use counts (only if settings doesn't already have them)\n if (authData._modelRanks && typeof authData._modelRanks === 'object') {\n settings.modelUseCounts = { ...authData._modelRanks, ...settings.modelUseCounts };\n }\n\n // Migrate per-mode model defaults (don't overwrite existing settings)\n for (const key of modelKeys) {\n const modeMatch = key.match(/^_modeModelId_(.+)$/);\n if (modeMatch?.[1] && typeof authData[key] === 'string' && !settings.models.modeDefaults[modeMatch[1]]) {\n settings.models.modeDefaults[modeMatch[1]] = authData[key];\n }\n }\n\n // Migrate subagent models (don't overwrite existing settings)\n for (const key of modelKeys) {\n if (key === '_subagentModelId' && typeof authData[key] === 'string' && !settings.models.subagentModels['default']) {\n settings.models.subagentModels['default'] = authData[key];\n }\n const saMatch = key.match(/^_subagentModelId_(.+)$/);\n if (saMatch?.[1] && typeof authData[key] === 'string' && !settings.models.subagentModels[saMatch[1]]) {\n settings.models.subagentModels[saMatch[1]] = authData[key];\n }\n }\n\n // Write migrated settings\n saveSettings(settings, settingsPath);\n\n // Clean up auth.json — remove _ prefixed keys\n for (const key of modelKeys) {\n delete authData[key];\n }\n try {\n writeFileAtomically(authPath, JSON.stringify(authData, null, 2));\n } catch {\n // Non-fatal — settings are saved, auth cleanup can fail\n }\n\n return true;\n}\n\nconst LEGACY_VARIED_MODELS: Record<string, string> = {\n plan: 'openai/gpt-5.4',\n build: 'anthropic/claude-sonnet-4-5',\n fast: 'anthropic/claude-haiku-4-5',\n};\n\nexport function migrateLegacyVariedPack(settings: GlobalSettings): boolean {\n const legacyPackId = 'varied';\n const customPackId = 'custom:varied';\n const hasLegacyReference =\n settings.models.activeModelPackId === legacyPackId || settings.onboarding.modePackId === legacyPackId;\n\n if (!hasLegacyReference) return false;\n\n const existingIdx = settings.customModelPacks.findIndex(p => p.name === 'varied');\n if (existingIdx >= 0) {\n const existing = settings.customModelPacks[existingIdx]!;\n const modelsMatch = Object.entries(LEGACY_VARIED_MODELS).every(([k, v]) => existing.models[k] === v);\n if (!modelsMatch) {\n existing.models = { ...LEGACY_VARIED_MODELS };\n }\n } else {\n settings.customModelPacks.push({\n name: 'varied',\n models: { ...LEGACY_VARIED_MODELS },\n createdAt: new Date().toISOString(),\n });\n }\n\n if (settings.models.activeModelPackId === legacyPackId) {\n settings.models.activeModelPackId = customPackId;\n if (Object.keys(settings.models.modeDefaults).length === 0) {\n settings.models.modeDefaults = { ...LEGACY_VARIED_MODELS };\n }\n }\n\n if (settings.onboarding.modePackId === legacyPackId) {\n settings.onboarding.modePackId = customPackId;\n }\n\n return true;\n}\n\nexport function loadSettings(filePath: string = getSettingsPath()): GlobalSettings {\n // One-time migration: move model data from auth.json into settings.json\n migrateFromAuth(filePath);\n\n if (!existsSync(filePath)) return rememberLoadedSettings(structuredClone(DEFAULTS));\n try {\n const raw = JSON.parse(readFileSync(filePath, 'utf-8'));\n const rawCustomPacks: CustomPack[] = Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [];\n const modePackOverrides = parseModePackOverrides(raw.models?.modePackOverrides);\n const experimentalAgentSetting = loadExperimentalAgentSetting(raw.experimentalAgent, filePath);\n // Spread raw first to preserve unknown top-level keys (forward-compatibility),\n // then overlay with parsed/typed fields so known keys are always correct.\n const settings: GlobalSettings = {\n ...raw,\n onboarding: { ...DEFAULTS.onboarding, ...raw.onboarding },\n models: {\n ...DEFAULTS.models,\n ...raw.models,\n modePackOverrides,\n modeThinkingDefaults: parseModeThinkingDefaults(raw.models?.modeThinkingDefaults),\n packFallbacks: loadPackFallbacks(raw.models?.packFallbacks, rawCustomPacks),\n packAccountPreferences: loadPackAccountPreferences(\n raw.models?.packAccountPreferences,\n rawCustomPacks,\n modePackOverrides,\n ),\n },\n preferences: parsePreferences(raw.preferences),\n storage: {\n ...STORAGE_DEFAULTS,\n ...raw.storage,\n libsql: { ...STORAGE_DEFAULTS.libsql, ...raw.storage?.libsql },\n pg: { ...STORAGE_DEFAULTS.pg, ...raw.storage?.pg },\n },\n customModelPacks: Array.isArray(raw.customModelPacks) ? raw.customModelPacks : [],\n customProviders: parseCustomProviders(raw.customProviders),\n modelUseCounts: raw.modelUseCounts && typeof raw.modelUseCounts === 'object' ? raw.modelUseCounts : {},\n updateDismissedVersion: typeof raw.updateDismissedVersion === 'string' ? raw.updateDismissedVersion : null,\n memoryGateway: raw.memoryGateway && typeof raw.memoryGateway === 'object' ? raw.memoryGateway : {},\n lsp: parseLspSettings(raw.lsp),\n browser: parseBrowserSettings(raw.browser),\n shellPassthrough: parseShellPassthroughSettings(raw.shellPassthrough),\n voice: parseVoiceSettings(raw.voice),\n experimentalAgent: experimentalAgentSetting.selection,\n _experimentalAgentSettingsPath: experimentalAgentSetting.settingsPath,\n backgroundTools: parseBackgroundToolSettings(raw.backgroundTools),\n signals: parseSignalSettings(raw.signals),\n mcp: parseMcpDiscoverySettings(raw.mcp),\n observability: parseObservabilitySettings(raw.observability),\n factory: parseFactoryConnectionSettings(raw.factory),\n };\n\n let settingsChanged = false;\n // Persist the resolved preview line limit under its current key. Legacy quiet-mode keys are\n // left untouched so older Mastra Code instances that are still running keep working.\n if (!isFiniteNumber(raw.preferences?.previewLines)) {\n settingsChanged = true;\n }\n // Migrate legacy omModelId → omModelOverride\n if (raw.models?.omModelId && !settings.models.omModelOverride) {\n settings.models.omModelOverride = raw.models.omModelId;\n settingsChanged = true;\n }\n\n if (migrateLegacyVariedPack(settings)) {\n settingsChanged = true;\n }\n\n if (settingsChanged) {\n saveSettings(settings, filePath);\n }\n\n return rememberLoadedSettings(settings);\n } catch {\n return rememberLoadedSettings(structuredClone(DEFAULTS));\n }\n}\n\nexport const THREAD_ACTIVE_MODEL_PACK_ID_KEY = 'activeModelPackId';\nexport const THREAD_FALLBACK_STATUS_KEY = 'mastracodeFallbackStatus';\n\nexport interface ThreadSettings {\n activeModelPackId: string | null;\n modeModelIds: Record<string, string>;\n}\n\nexport function parseThreadSettings(metadata: Record<string, unknown> | undefined): ThreadSettings {\n const modeModelIds: Record<string, string> = {};\n for (const [key, value] of Object.entries(metadata ?? {})) {\n const modeMatch = key.match(/^modeModelId_(.+)$/);\n if (modeMatch?.[1] && typeof value === 'string' && value.length > 0) {\n modeModelIds[modeMatch[1]] = value;\n }\n }\n\n const rawPackId = metadata?.[THREAD_ACTIVE_MODEL_PACK_ID_KEY];\n const activeModelPackId = typeof rawPackId === 'string' && rawPackId.length > 0 ? rawPackId : null;\n\n return {\n activeModelPackId,\n modeModelIds,\n };\n}\n\n/**\n * Resolve active model pack id for the current thread.\n *\n * Priority:\n * 1) explicit thread metadata activeModelPackId\n * 2) inferred from thread modeModelId_* values\n * 3) global settings.models.activeModelPackId\n */\nexport function resolveThreadActiveModelPackId(\n settings: GlobalSettings,\n builtinPacks: Array<{ id: string; models: Record<string, string> }>,\n metadata: Record<string, unknown> | undefined,\n): string | null {\n const threadSettings = parseThreadSettings(metadata);\n\n const isKnownPack = (packId: string): boolean => {\n if (packId.startsWith('custom:')) {\n const name = packId.slice('custom:'.length);\n return settings.customModelPacks.some(p => p.name === name);\n }\n return builtinPacks.some(p => p.id === packId);\n };\n\n if (threadSettings.activeModelPackId && isKnownPack(threadSettings.activeModelPackId)) {\n return threadSettings.activeModelPackId;\n }\n\n const allPacks: Array<{ id: string; models: Record<string, string> }> = [\n ...builtinPacks,\n ...settings.customModelPacks.map(p => ({ id: `custom:${p.name}`, models: p.models })),\n ];\n\n for (const pack of allPacks) {\n const packEntries = Object.entries(pack.models);\n const threadEntries = Object.keys(threadSettings.modeModelIds);\n const matches =\n packEntries.length === threadEntries.length &&\n packEntries.every(([modeId, modelId]) => threadSettings.modeModelIds[modeId] === modelId);\n if (matches) return pack.id;\n }\n\n if (settings.models.activeModelPackId && isKnownPack(settings.models.activeModelPackId)) {\n return settings.models.activeModelPackId;\n }\n\n return null;\n}\n\n/**\n * Resolve effective per-mode model defaults.\n *\n * If `activeModelPackId` is set, looks up the pack (built-in or custom) and\n * returns its models. Falls back to the explicit `modeDefaults` map.\n *\n * @param settings The loaded global settings.\n * @param builtinPacks Built-in packs for the current provider access\n * (from `getAvailableModePacks`). Pass `[]` if unavailable.\n */\nexport function resolveModePackModels(\n settings: GlobalSettings,\n pack: { id: string; models: Record<string, string> },\n): Record<string, string> {\n if (pack.id.startsWith('custom:') || pack.id === 'custom') return pack.models;\n return { ...pack.models, ...settings.models.modePackOverrides?.[pack.id] };\n}\n\n/**\n * Resolve a session's explicitly active pack when its mode model still matches.\n * Model matching alone is not pack identity: multiple packs may intentionally\n * use the same model, and inference would attach an unrelated fallback chain.\n */\nexport function findModePackForModel(\n settings: GlobalSettings,\n packs: Array<{ id: string; models: Record<string, string> }>,\n modelId: string,\n modeId: string,\n activePackId: string | undefined,\n): { id: string; models: Record<string, string> } | undefined {\n const activePack = packs.find(pack => pack.id === activePackId);\n return activePack && resolveModePackModels(settings, activePack)[modeId] === modelId ? activePack : undefined;\n}\n\nexport function resolveModelDefaults(\n settings: GlobalSettings,\n builtinPacks: Array<{ id: string; models: Record<string, string> }>,\n): Record<string, string> {\n const { activeModelPackId, modeDefaults } = settings.models;\n if (!activeModelPackId) return modeDefaults;\n\n // Custom pack: \"custom:<name>\"\n if (activeModelPackId.startsWith('custom:')) {\n const name = activeModelPackId.slice('custom:'.length);\n const pack = settings.customModelPacks.find(p => p.name === name);\n if (pack) return pack.models;\n // Custom pack was deleted — fall through to modeDefaults\n return modeDefaults;\n }\n\n // Built-in pack\n const builtin = builtinPacks.find(p => p.id === activeModelPackId);\n if (builtin) return resolveModePackModels(settings, builtin);\n\n // Unknown pack id — fall through\n return modeDefaults;\n}\n\n/**\n * Resolve the default reasoning-effort level for a mode.\n *\n * Lookup order:\n * 1. `models.modeThinkingDefaults[mode]` when set for the mode.\n * 2. The global `preferences.thinkingLevel`.\n *\n * Session-level overrides (via /think or the session settings panel) take\n * precedence over both and are handled by the caller.\n */\nexport function resolveDefaultThinkingLevel(\n settings: GlobalSettings,\n mode?: string | null,\n): { level: ThinkingLevelSetting; source: ThinkingLevelSource } {\n return resolveThinkingDefault(\n {\n globalDefault: settings.preferences.thinkingLevel,\n modeDefaults: settings.models.modeThinkingDefaults,\n },\n mode,\n );\n}\n\n/**\n * Resolve the effective model ID for one of the two OM roles.\n *\n * Lookup order:\n * 1. The role-specific override (`observerModelOverride` /\n * `reflectorModelOverride`) if set.\n * 2. If `activeOmPackId` points at a built-in pack, that pack's model.\n * 3. The shared `omModelOverride` fallback.\n *\n * @param settings The loaded global settings.\n * @param role Which OM role to resolve (`'observer'` or `'reflector'`).\n * @param builtinOmPacks Built-in OM packs for the current provider access\n * (from `getAvailableOmPacks`). Pass `[]` if unavailable.\n */\nexport function resolveOmRoleModel(\n settings: GlobalSettings,\n role: 'observer' | 'reflector',\n builtinOmPacks: Array<{ id: string; modelId: string }>,\n): string | null {\n const {\n activeOmPackId,\n omModelOverride,\n observerModelOverride,\n observerModelSelection,\n reflectorModelOverride,\n reflectorModelSelection,\n } = settings.models;\n const model = role === 'observer' ? observerModelSelection : reflectorModelSelection;\n if (model === 'auto') return null;\n if (model) return model;\n\n const roleOverride = role === 'observer' ? observerModelOverride : reflectorModelOverride;\n if (roleOverride) return roleOverride;\n\n if (!activeOmPackId) return omModelOverride;\n if (activeOmPackId === 'custom') return omModelOverride;\n\n const pack = builtinOmPacks.find(p => p.id === activeOmPackId);\n if (pack) return pack.modelId;\n\n return omModelOverride;\n}\n\n/**\n * @deprecated Use `resolveOmRoleModel(settings, 'observer' | 'reflector', ...)`.\n * Equivalent to resolving the observer role (existing callers set both observer\n * and reflector to the same value).\n */\nexport function resolveOmModel(\n settings: GlobalSettings,\n builtinOmPacks: Array<{ id: string; modelId: string }>,\n): string | null {\n return resolveOmRoleModel(settings, 'observer', builtinOmPacks);\n}\n\nfunction getSignalSettingsForSave(settings: GlobalSettings, filePath: string): SignalSettings {\n const loadedSignals = loadedSignalSettings.get(settings);\n if (!loadedSignals || !signalSettingsEqual(settings.signals, loadedSignals) || !existsSync(filePath)) {\n return settings.signals;\n }\n\n try {\n const currentRaw = JSON.parse(readFileSync(filePath, 'utf-8')) as Record<string, unknown>;\n const currentSignals = parseSignalSettings(currentRaw.signals);\n if (!signalSettingsEqual(currentSignals, loadedSignals)) {\n return currentSignals;\n }\n } catch {\n // If the current file is unreadable, fall back to the caller's settings.\n }\n\n return settings.signals;\n}\n\nfunction writeFileAtomically(filePath: string, content: string): void {\n const tempPath = `${filePath}.${process.pid}.${globalThis.crypto.randomUUID()}.tmp`;\n try {\n // Preserve the target's mode across the rename (auth.json keeps its 0600);\n // new files default to owner-only since these are local app-data files.\n const mode = existsSync(filePath) ? statSync(filePath).mode & 0o777 : 0o600;\n writeFileSync(tempPath, content, { encoding: 'utf-8', mode });\n renameSync(tempPath, filePath);\n } finally {\n rmSync(tempPath, { force: true });\n }\n}\n\nexport function saveSettings(settings: GlobalSettings, filePath: string = getSettingsPath()): void {\n const dir = dirname(filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n const signals = getSignalSettingsForSave(settings, filePath);\n settings.signals = signals;\n loadedSignalSettings.set(settings, cloneSignalSettings(signals));\n const settingsToSave: Record<string, unknown> = { ...settings };\n delete settingsToSave._experimentalAgentSettingsPath;\n writeFileAtomically(filePath, JSON.stringify(settingsToSave, null, 2));\n}\n\n/** Marker file name to track which provider last used a profile. */\nconst PROFILE_PROVIDER_MARKER = '.mastra-provider';\n\n/**\n * Check which provider last used a profile directory.\n * Returns the provider name if the marker exists, undefined otherwise.\n */\nexport function getProfileProvider(profilePath: string): BrowserProvider | undefined {\n const markerPath = join(profilePath, PROFILE_PROVIDER_MARKER);\n if (!existsSync(markerPath)) {\n return undefined;\n }\n try {\n const content = readFileSync(markerPath, 'utf-8').trim();\n if (content === 'stagehand' || content === 'agent-browser') {\n return content;\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Write the provider marker to a profile directory.\n * Creates the directory if it doesn't exist.\n */\nexport function setProfileProvider(profilePath: string, provider: BrowserProvider): void {\n const markerPath = join(profilePath, PROFILE_PROVIDER_MARKER);\n if (!existsSync(profilePath)) {\n mkdirSync(profilePath, { recursive: true });\n }\n writeFileSync(markerPath, provider, 'utf-8');\n}\n\n/**\n * Check if a profile has a provider mismatch.\n * Returns the existing provider if there's a mismatch, undefined otherwise.\n */\nexport function checkProfileProviderMismatch(\n profilePath: string | undefined,\n targetProvider: BrowserProvider,\n): BrowserProvider | undefined {\n if (!profilePath) {\n return undefined;\n }\n const existingProvider = getProfileProvider(profilePath);\n if (existingProvider && existingProvider !== targetProvider) {\n return existingProvider;\n }\n return undefined;\n}\n\nfunction browserRecordingOptions() {\n return { outputDir: join(getAppDataDir(), 'browser-recordings') };\n}\n\n/**\n * Snapshot of browser settings safe to store in session state (which session clients can read).\n * Strips credentials; keeps everything `/browser status` needs for drift detection.\n */\nexport function toActiveBrowserSettings(settings: BrowserSettings): BrowserSettings {\n if (!settings.stagehand) return { ...settings };\n const { apiKey: _apiKey, ...stagehand } = settings.stagehand;\n return { ...settings, stagehand };\n}\n\nexport type StagehandModelSource =\n /** `browser.stagehand.model` in settings. */\n | 'settings'\n /** No model configured; reusing the chat model that was active when the browser launched. */\n | 'chat-model'\n /** No usable model otherwise; the default model for the user's OpenAI Codex (ChatGPT) login. */\n | 'codex-oauth'\n /** Nothing else applies; Stagehand picks its own default from env API keys. */\n | 'stagehand-default';\n\nexport interface ResolvedStagehandModel {\n /** `provider/model` id, or undefined when Stagehand's own default applies. */\n modelName: string | undefined;\n source: StagehandModelSource;\n /** True when requests go through the user's OpenAI Codex OAuth login instead of an API key. */\n viaCodexOAuth: boolean;\n}\n\nexport interface ResolveStagehandModelOptions {\n /**\n * Chat model id at the moment the browser launches (`session.model.get()`).\n * The Stagehand instance is fixed once created and shared across threads, so\n * later chat-model switches do not affect it.\n */\n chatModelId?: string;\n authStorage?: AuthStorage;\n}\n\n/**\n * Env vars Stagehand reads for each provider it can route (mirrors\n * `STAGEHAND_MODEL_PROVIDERS` in `@mastra/stagehand` and Stagehand's own\n * `providerEnvVarMap`). `null` means the provider needs no API key.\n * Kept here instead of importing `@mastra/stagehand`, which would eagerly\n * load the browser stack into every settings consumer.\n */\nexport const STAGEHAND_PROVIDER_ENV_VARS: Record<string, readonly string[] | null> = {\n openai: ['OPENAI_API_KEY'],\n anthropic: ['ANTHROPIC_API_KEY'],\n google: ['GEMINI_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_API_KEY'],\n vertex: ['GOOGLE_VERTEX_AI_API_KEY'],\n groq: ['GROQ_API_KEY'],\n cerebras: ['CEREBRAS_API_KEY'],\n togetherai: ['TOGETHER_AI_API_KEY'],\n mistral: ['MISTRAL_API_KEY'],\n deepseek: ['DEEPSEEK_API_KEY'],\n perplexity: ['PERPLEXITY_API_KEY'],\n azure: ['AZURE_API_KEY'],\n xai: ['XAI_API_KEY'],\n gateway: ['AI_GATEWAY_API_KEY'],\n bedrock: null,\n ollama: null,\n};\n\nfunction hasCodexOAuthLogin(authStorage: AuthStorage): boolean {\n return authStorage.get('openai-codex')?.type === 'oauth';\n}\n\nfunction isOpenAIModel(modelId: string): boolean {\n return modelId.startsWith(OPENAI_PREFIX);\n}\n\n/**\n * Stagehand hands the segment after `provider/` straight to the AI SDK provider,\n * so apply the same id normalization the chat gateway does before it does.\n */\nfunction normalizeForStagehand(modelId: string): string {\n const bare = stripMastraGatewayPrefix(modelId.trim());\n return bare.startsWith(ANTHROPIC_PREFIX) ? normalizeAnthropicModelId(bare) : bare;\n}\n\n/** Whether Stagehand could run `provider/model` with the credentials available right now. */\nfunction stagehandCanRoute(modelId: string, codexOAuth: boolean): boolean {\n const provider = modelId.split('/', 1)[0];\n if (!provider || provider === modelId) return false;\n if (provider === 'openai' && codexOAuth) return true;\n const envVars = STAGEHAND_PROVIDER_ENV_VARS[provider];\n if (envVars === undefined) return false;\n if (envVars === null) return true;\n return envVars.some(name => Boolean(process.env[name]?.trim()));\n}\n\n/**\n * Resolve which model Stagehand will use and why, without creating a browser.\n * Order: configured `browser.stagehand.model` → the launch-time chat model when\n * Stagehand can route it → the Codex login's default model → Stagehand's own\n * default. Mirrors the selection in `createBrowserFromSettings` so the UI can\n * show it.\n */\nexport function resolveStagehandModel(\n settings: Pick<BrowserSettings, 'provider' | 'stagehand'>,\n { chatModelId, authStorage = new AuthStorage() }: ResolveStagehandModelOptions = {},\n): ResolvedStagehandModel {\n if (settings.provider !== 'stagehand') {\n return { modelName: undefined, source: 'stagehand-default', viaCodexOAuth: false };\n }\n const codexOAuth = hasCodexOAuthLogin(authStorage);\n const configured = settings.stagehand?.model ? normalizeForStagehand(settings.stagehand.model) : undefined;\n if (configured) {\n return { modelName: configured, source: 'settings', viaCodexOAuth: codexOAuth && isOpenAIModel(configured) };\n }\n const chatModel = chatModelId ? normalizeForStagehand(chatModelId) : undefined;\n if (chatModel && stagehandCanRoute(chatModel, codexOAuth)) {\n return { modelName: chatModel, source: 'chat-model', viaCodexOAuth: codexOAuth && isOpenAIModel(chatModel) };\n }\n if (codexOAuth) {\n return { modelName: PROVIDER_DEFAULT_MODELS['openai-codex'], source: 'codex-oauth', viaCodexOAuth: true };\n }\n return { modelName: undefined, source: 'stagehand-default', viaCodexOAuth: false };\n}\n\nexport interface CreateBrowserOptions {\n /** Chat model id at launch; see `ResolveStagehandModelOptions.chatModelId`. */\n chatModelId?: string;\n}\n\n/**\n * Create a browser instance from settings.\n * Shared by startup (main.ts) and live reconfiguration (/browser command).\n * Returns undefined if browser is disabled.\n */\nexport async function createBrowserFromSettings(\n settings: BrowserSettings,\n { chatModelId }: CreateBrowserOptions = {},\n): Promise<MastraBrowser | undefined> {\n if (!settings.enabled) {\n return undefined;\n }\n\n const { provider, headless, viewport, cdpUrl, profile, executablePath, stagehand, agentBrowser } = settings;\n\n // Chrome only allows one process per profile directory, so force 'shared' scope\n // when a profile is set. Otherwise use the user's setting (or provider default).\n const scope = profile ? ('shared' as const) : settings.scope;\n\n // Common launch options (no CDP)\n const launchConfig = { headless, viewport, profile, executablePath, scope } as const;\n\n if (provider === 'stagehand') {\n const { StagehandBrowser } = await import('@mastra/stagehand');\n const stagehandOpts: Record<string, unknown> = {\n env: stagehand?.env ?? 'LOCAL',\n apiKey: stagehand?.apiKey ?? process.env.BROWSERBASE_API_KEY,\n projectId: stagehand?.projectId ?? process.env.BROWSERBASE_PROJECT_ID,\n preserveUserDataDir: stagehand?.preserveUserDataDir,\n recording: browserRecordingOptions(),\n };\n\n // See resolveStagehandModel() for which model is picked. How it is reached\n // depends on the user's OpenAI auth, not on where the model came from:\n // any `openai/*` model goes through the Codex (ChatGPT) endpoint when the\n // user signed in with Codex OAuth, matching the chat agents. Everything\n // else is passed as a plain `provider/model` string and Stagehand resolves\n // the provider's API key from the environment.\n //\n // The Codex route uses the AI SDK provider's standard hooks:\n // - baseURL: target Codex's Responses API directly (no URL rewriting).\n // - headers: static Codex identifiers (originator, UA, account id).\n // - fetch: a tiny refresher that injects the live OAuth bearer per call,\n // since AI SDK takes `apiKey` as a static string.\n // - middleware: createCodexMiddleware() sets `store: false`, which Codex\n // requires on every request.\n const authStorage = new AuthStorage();\n const resolved = resolveStagehandModel(settings, { chatModelId, authStorage });\n if (resolved.modelName && resolved.viaCodexOAuth) {\n const accountId = (authStorage.get('openai-codex') as any)?.accountId as string | undefined;\n stagehandOpts.model = {\n modelName: remapOpenAIModelForCodexOAuth(resolved.modelName),\n apiKey: 'codex-oauth',\n baseURL: 'https://chatgpt.com/backend-api/codex',\n headers: {\n originator: 'mastracode',\n 'User-Agent': 'mastracode',\n ...(accountId ? { 'ChatGPT-Account-ID': accountId } : {}),\n },\n fetch: buildCodexStagehandFetch(authStorage),\n middleware: createCodexMiddleware(),\n } as any;\n } else if (resolved.modelName) {\n stagehandOpts.model = resolved.modelName;\n }\n\n return cdpUrl\n ? new StagehandBrowser({ ...launchConfig, cdpUrl, scope: 'shared', ...stagehandOpts })\n : new StagehandBrowser({ ...launchConfig, ...stagehandOpts });\n } else if (provider === 'agent-browser') {\n const { AgentBrowser } = await import('@mastra/agent-browser');\n const agentBrowserOpts = {\n storageState: agentBrowser?.storageState,\n recording: browserRecordingOptions(),\n };\n return cdpUrl\n ? new AgentBrowser({ ...launchConfig, cdpUrl, scope: 'shared', ...agentBrowserOpts })\n : new AgentBrowser({ ...launchConfig, ...agentBrowserOpts, scope });\n }\n\n throw new Error(`Unsupported browser provider: ${provider}`);\n}\n"],"mappings":"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"}
|
package/dist/platform/index.js
CHANGED
|
@@ -12,7 +12,8 @@ import { createServer } from "http";
|
|
|
12
12
|
* stdin, so it is safe to drive from the TUI.
|
|
13
13
|
*/
|
|
14
14
|
const MASTRA_PLATFORM_API_URL = process.env.MASTRA_PLATFORM_API_URL || "https://platform.mastra.ai";
|
|
15
|
-
const
|
|
15
|
+
const CREDENTIALS_DIR = join(homedir(), ".mastra");
|
|
16
|
+
const CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.json");
|
|
16
17
|
async function loadPlatformCredentials(filePath = CREDENTIALS_FILE) {
|
|
17
18
|
try {
|
|
18
19
|
return JSON.parse(await readFile(filePath, "utf-8"));
|
|
@@ -21,7 +22,8 @@ async function loadPlatformCredentials(filePath = CREDENTIALS_FILE) {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
async function savePlatformCredentials(creds, filePath = CREDENTIALS_FILE) {
|
|
24
|
-
|
|
25
|
+
const dir = join(filePath, "..");
|
|
26
|
+
await mkdir(dir, {
|
|
25
27
|
recursive: true,
|
|
26
28
|
mode: 448
|
|
27
29
|
});
|
|
@@ -119,7 +121,7 @@ async function loginToPlatform(options = {}) {
|
|
|
119
121
|
server.closeAllConnections();
|
|
120
122
|
};
|
|
121
123
|
const onAbort = () => finish(() => reject(/* @__PURE__ */ new Error("Login cancelled")));
|
|
122
|
-
const timeout = setTimeout(() => finish(() => reject(/* @__PURE__ */ new Error("Login timed out"))), options.timeoutMs ??
|
|
124
|
+
const timeout = setTimeout(() => finish(() => reject(/* @__PURE__ */ new Error("Login timed out"))), options.timeoutMs ?? 3e5);
|
|
123
125
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
124
126
|
server.on("request", (req, res) => {
|
|
125
127
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/platform/index.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:http';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Mastra Platform client for Mastra Code.\n *\n * Shares `~/.mastra/credentials.json` with the `mastra` CLI so a single login\n * works for both. Unlike the CLI flow, nothing here writes to stdout or reads\n * stdin, so it is safe to drive from the TUI.\n */\n\nexport const MASTRA_PLATFORM_API_URL = process.env.MASTRA_PLATFORM_API_URL || 'https://platform.mastra.ai';\n\nconst CREDENTIALS_DIR = join(homedir(), '.mastra');\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');\n\nexport interface PlatformCredentials {\n token: string;\n refreshToken?: string;\n user: { id: string; email: string; firstName: string | null; lastName: string | null };\n organizationId: string;\n currentOrgId?: string;\n}\n\nexport interface PlatformOrg {\n id: string;\n name: string;\n role?: string;\n isCurrent?: boolean;\n}\n\nexport interface PlatformProject {\n id: string;\n name: string;\n slug: string | null;\n organizationId: string;\n}\n\nexport interface PlatformEnvironment {\n id: string;\n projectId: string;\n name: string;\n slug: string;\n type: 'production' | 'staging' | 'preview';\n instanceUrl: string | null;\n customServerUrl: string | null;\n}\n\nexport interface PlatformSession {\n token: string;\n orgId: string;\n}\n\nexport async function loadPlatformCredentials(filePath = CREDENTIALS_FILE): Promise<PlatformCredentials | null> {\n try {\n return JSON.parse(await readFile(filePath, 'utf-8')) as PlatformCredentials;\n } catch {\n return null;\n }\n}\n\nexport async function savePlatformCredentials(creds: PlatformCredentials, filePath = CREDENTIALS_FILE): Promise<void> {\n const dir = join(filePath, '..');\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 0o600 });\n await chmod(filePath, 0o600).catch(() => {});\n}\n\nasync function verifyToken(token: string, signal?: AbortSignal): Promise<boolean> {\n try {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/verify`, {\n headers: { Authorization: `Bearer ${token}` },\n signal,\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nasync function refreshToken(creds: PlatformCredentials, signal?: AbortSignal): Promise<string | null> {\n if (!creds.refreshToken) return null;\n try {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/refresh-token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n signal,\n });\n if (!res.ok) return null;\n const data = (await res.json()) as { accessToken: string; refreshToken: string };\n creds.token = data.accessToken;\n creds.refreshToken = data.refreshToken;\n await savePlatformCredentials(creds);\n return data.accessToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns a valid session from env (`MASTRA_API_TOKEN` + `MASTRA_ORG_ID`) or\n * stored credentials, refreshing the token if needed. Returns null when the\n * user must log in.\n */\nexport async function getPlatformSession(signal?: AbortSignal): Promise<PlatformSession | null> {\n const envToken = process.env.MASTRA_API_TOKEN;\n const envOrg = process.env.MASTRA_ORG_ID;\n if (envToken && envOrg) return { token: envToken, orgId: envOrg };\n\n const creds = await loadPlatformCredentials();\n if (!creds) return null;\n const orgId = envOrg ?? creds.currentOrgId ?? creds.organizationId;\n if (await verifyToken(creds.token, signal)) return { token: creds.token, orgId };\n const refreshed = await refreshToken(creds, signal);\n return refreshed ? { token: refreshed, orgId } : null;\n}\n\nfunction openBrowser(url: string): void {\n const [cmd, args] =\n process.platform === 'darwin'\n ? ['open', [url]]\n : process.platform === 'win32'\n ? ['cmd', ['/c', 'start', '', url]]\n : ['xdg-open', [url]];\n execFile(cmd, args as string[], () => {});\n}\n\nexport interface PlatformLoginOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n /** Called with the login URL so the UI can display it in case the browser does not open. */\n onUrl?: (url: string) => void;\n /** Override for tests. */\n openUrl?: (url: string) => void;\n credentialsPath?: string;\n}\n\nconst CALLBACK_HTML = (ok: boolean) =>\n `<!doctype html><html><body style=\"background:#0d0d0d;color:#fff;font-family:system-ui;display:flex;align-items:center;justify-content:center;min-height:100vh\"><div style=\"text-align:center\"><h1>${\n ok ? 'Logged in!' : 'Login failed'\n }</h1><p>${ok ? 'You can close this tab and return to Mastra Code.' : 'Close this tab and try again.'}</p></div></body></html>`;\n\n/** Browser-based Mastra Platform login using the same callback protocol as `mastra auth login`. */\nexport async function loginToPlatform(options: PlatformLoginOptions = {}): Promise<PlatformCredentials> {\n const { signal } = options;\n signal?.throwIfAborted();\n\n const server = createServer();\n const state = Buffer.from(globalThis.crypto.getRandomValues(new Uint8Array(16))).toString('hex');\n const port = await new Promise<number>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n if (typeof addr === 'object' && addr) resolve(addr.port);\n });\n });\n\n const loginUrl = `${MASTRA_PLATFORM_API_URL}/v1/auth/login?product=cli&cli_port=${port}&state=${state}`;\n options.onUrl?.(loginUrl);\n (options.openUrl ?? openBrowser)(loginUrl);\n\n const creds = await new Promise<PlatformCredentials>((resolve, reject) => {\n let settled = false;\n const finish = (cb: () => void) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n server.close(cb);\n server.closeAllConnections();\n };\n const onAbort = () => finish(() => reject(new Error('Login cancelled')));\n const timeout = setTimeout(\n () => finish(() => reject(new Error('Login timed out'))),\n options.timeoutMs ?? 5 * 60 * 1000,\n );\n signal?.addEventListener('abort', onAbort, { once: true });\n\n server.on('request', (req, res) => {\n const url = new URL(req.url ?? '/', `http://localhost:${port}`);\n if (url.pathname !== '/callback') return void res.writeHead(404).end();\n\n const token = url.searchParams.get('token');\n const userParam = url.searchParams.get('user');\n const orgId = url.searchParams.get('org');\n if (url.searchParams.get('state') !== state || !token || !userParam || !orgId) {\n res.writeHead(400, { 'Content-Type': 'text/html' }).end(CALLBACK_HTML(false));\n return;\n }\n let user: PlatformCredentials['user'];\n try {\n user = JSON.parse(decodeURIComponent(userParam));\n } catch {\n res.writeHead(400, { 'Content-Type': 'text/html' }).end(CALLBACK_HTML(false));\n return;\n }\n const refresh = url.searchParams.get('refresh_token');\n res.writeHead(200, { 'Content-Type': 'text/html', Connection: 'close' }).end(CALLBACK_HTML(true));\n finish(() =>\n resolve({\n token,\n ...(refresh ? { refreshToken: refresh } : {}),\n user,\n organizationId: orgId,\n }),\n );\n });\n });\n\n await savePlatformCredentials(creds, options.credentialsPath);\n return creds;\n}\n\nasync function platformGet<T>(session: PlatformSession, path: string, signal?: AbortSignal): Promise<T> {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}${path}`, {\n headers: { Authorization: `Bearer ${session.token}`, 'x-organization-id': session.orgId },\n signal,\n });\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: string; message?: string };\n throw new Error(`Mastra Platform request failed (${res.status}): ${body.message ?? body.error ?? path}`);\n }\n return (await res.json()) as T;\n}\n\nexport async function fetchPlatformOrgs(session: PlatformSession, signal?: AbortSignal): Promise<PlatformOrg[]> {\n const data = await platformGet<{ organizations?: PlatformOrg[]; orgs?: PlatformOrg[] }>(\n session,\n '/v1/auth/orgs',\n signal,\n );\n return data.organizations ?? data.orgs ?? [];\n}\n\nexport async function fetchPlatformProjects(\n session: PlatformSession,\n signal?: AbortSignal,\n): Promise<PlatformProject[]> {\n return (await platformGet<{ projects: PlatformProject[] }>(session, '/v1/projects', signal)).projects;\n}\n\nexport async function fetchPlatformEnvironments(\n session: PlatformSession,\n projectId: string,\n signal?: AbortSignal,\n): Promise<PlatformEnvironment[]> {\n return (\n await platformGet<{ environments: PlatformEnvironment[] }>(\n session,\n `/v1/projects/${encodeURIComponent(projectId)}/environments`,\n signal,\n )\n ).environments;\n}\n\nexport const FACTORY_DOMAIN = 'factory.mastra.cloud';\n\n/**\n * The Factory server URL for a deployed environment: a custom server wins,\n * otherwise the managed `<env slug>.factory.mastra.cloud` domain.\n */\nexport function resolveFactoryUrl(env: PlatformEnvironment): string | null {\n if (env.customServerUrl) {\n // The Platform session token is sent to this URL, so only accept HTTPS.\n try {\n const url = new URL(\n /^[a-z][a-z\\d+.-]*:\\/\\//i.test(env.customServerUrl) ? env.customServerUrl : `https://${env.customServerUrl}`,\n );\n if (url.protocol !== 'https:') return null;\n return `${url.origin}${url.pathname}`.replace(/\\/+$/, '');\n } catch {\n return null;\n }\n }\n if (!env.instanceUrl) return null;\n return `https://${env.slug}.${FACTORY_DOMAIN}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/platform/index.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:http';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Mastra Platform client for Mastra Code.\n *\n * Shares `~/.mastra/credentials.json` with the `mastra` CLI so a single login\n * works for both. Unlike the CLI flow, nothing here writes to stdout or reads\n * stdin, so it is safe to drive from the TUI.\n */\n\nexport const MASTRA_PLATFORM_API_URL = process.env.MASTRA_PLATFORM_API_URL || 'https://platform.mastra.ai';\n\nconst CREDENTIALS_DIR = join(homedir(), '.mastra');\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');\n\nexport interface PlatformCredentials {\n token: string;\n refreshToken?: string;\n user: { id: string; email: string; firstName: string | null; lastName: string | null };\n organizationId: string;\n currentOrgId?: string;\n}\n\nexport interface PlatformOrg {\n id: string;\n name: string;\n role?: string;\n isCurrent?: boolean;\n}\n\nexport interface PlatformProject {\n id: string;\n name: string;\n slug: string | null;\n organizationId: string;\n}\n\nexport interface PlatformEnvironment {\n id: string;\n projectId: string;\n name: string;\n slug: string;\n type: 'production' | 'staging' | 'preview';\n instanceUrl: string | null;\n customServerUrl: string | null;\n}\n\nexport interface PlatformSession {\n token: string;\n orgId: string;\n}\n\nexport async function loadPlatformCredentials(filePath = CREDENTIALS_FILE): Promise<PlatformCredentials | null> {\n try {\n return JSON.parse(await readFile(filePath, 'utf-8')) as PlatformCredentials;\n } catch {\n return null;\n }\n}\n\nexport async function savePlatformCredentials(creds: PlatformCredentials, filePath = CREDENTIALS_FILE): Promise<void> {\n const dir = join(filePath, '..');\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 0o600 });\n await chmod(filePath, 0o600).catch(() => {});\n}\n\nasync function verifyToken(token: string, signal?: AbortSignal): Promise<boolean> {\n try {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/verify`, {\n headers: { Authorization: `Bearer ${token}` },\n signal,\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nasync function refreshToken(creds: PlatformCredentials, signal?: AbortSignal): Promise<string | null> {\n if (!creds.refreshToken) return null;\n try {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/refresh-token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n signal,\n });\n if (!res.ok) return null;\n const data = (await res.json()) as { accessToken: string; refreshToken: string };\n creds.token = data.accessToken;\n creds.refreshToken = data.refreshToken;\n await savePlatformCredentials(creds);\n return data.accessToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns a valid session from env (`MASTRA_API_TOKEN` + `MASTRA_ORG_ID`) or\n * stored credentials, refreshing the token if needed. Returns null when the\n * user must log in.\n */\nexport async function getPlatformSession(signal?: AbortSignal): Promise<PlatformSession | null> {\n const envToken = process.env.MASTRA_API_TOKEN;\n const envOrg = process.env.MASTRA_ORG_ID;\n if (envToken && envOrg) return { token: envToken, orgId: envOrg };\n\n const creds = await loadPlatformCredentials();\n if (!creds) return null;\n const orgId = envOrg ?? creds.currentOrgId ?? creds.organizationId;\n if (await verifyToken(creds.token, signal)) return { token: creds.token, orgId };\n const refreshed = await refreshToken(creds, signal);\n return refreshed ? { token: refreshed, orgId } : null;\n}\n\nfunction openBrowser(url: string): void {\n const [cmd, args] =\n process.platform === 'darwin'\n ? ['open', [url]]\n : process.platform === 'win32'\n ? ['cmd', ['/c', 'start', '', url]]\n : ['xdg-open', [url]];\n execFile(cmd, args as string[], () => {});\n}\n\nexport interface PlatformLoginOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n /** Called with the login URL so the UI can display it in case the browser does not open. */\n onUrl?: (url: string) => void;\n /** Override for tests. */\n openUrl?: (url: string) => void;\n credentialsPath?: string;\n}\n\nconst CALLBACK_HTML = (ok: boolean) =>\n `<!doctype html><html><body style=\"background:#0d0d0d;color:#fff;font-family:system-ui;display:flex;align-items:center;justify-content:center;min-height:100vh\"><div style=\"text-align:center\"><h1>${\n ok ? 'Logged in!' : 'Login failed'\n }</h1><p>${ok ? 'You can close this tab and return to Mastra Code.' : 'Close this tab and try again.'}</p></div></body></html>`;\n\n/** Browser-based Mastra Platform login using the same callback protocol as `mastra auth login`. */\nexport async function loginToPlatform(options: PlatformLoginOptions = {}): Promise<PlatformCredentials> {\n const { signal } = options;\n signal?.throwIfAborted();\n\n const server = createServer();\n const state = Buffer.from(globalThis.crypto.getRandomValues(new Uint8Array(16))).toString('hex');\n const port = await new Promise<number>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n if (typeof addr === 'object' && addr) resolve(addr.port);\n });\n });\n\n const loginUrl = `${MASTRA_PLATFORM_API_URL}/v1/auth/login?product=cli&cli_port=${port}&state=${state}`;\n options.onUrl?.(loginUrl);\n (options.openUrl ?? openBrowser)(loginUrl);\n\n const creds = await new Promise<PlatformCredentials>((resolve, reject) => {\n let settled = false;\n const finish = (cb: () => void) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n server.close(cb);\n server.closeAllConnections();\n };\n const onAbort = () => finish(() => reject(new Error('Login cancelled')));\n const timeout = setTimeout(\n () => finish(() => reject(new Error('Login timed out'))),\n options.timeoutMs ?? 5 * 60 * 1000,\n );\n signal?.addEventListener('abort', onAbort, { once: true });\n\n server.on('request', (req, res) => {\n const url = new URL(req.url ?? '/', `http://localhost:${port}`);\n if (url.pathname !== '/callback') return void res.writeHead(404).end();\n\n const token = url.searchParams.get('token');\n const userParam = url.searchParams.get('user');\n const orgId = url.searchParams.get('org');\n if (url.searchParams.get('state') !== state || !token || !userParam || !orgId) {\n res.writeHead(400, { 'Content-Type': 'text/html' }).end(CALLBACK_HTML(false));\n return;\n }\n let user: PlatformCredentials['user'];\n try {\n user = JSON.parse(decodeURIComponent(userParam));\n } catch {\n res.writeHead(400, { 'Content-Type': 'text/html' }).end(CALLBACK_HTML(false));\n return;\n }\n const refresh = url.searchParams.get('refresh_token');\n res.writeHead(200, { 'Content-Type': 'text/html', Connection: 'close' }).end(CALLBACK_HTML(true));\n finish(() =>\n resolve({\n token,\n ...(refresh ? { refreshToken: refresh } : {}),\n user,\n organizationId: orgId,\n }),\n );\n });\n });\n\n await savePlatformCredentials(creds, options.credentialsPath);\n return creds;\n}\n\nasync function platformGet<T>(session: PlatformSession, path: string, signal?: AbortSignal): Promise<T> {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}${path}`, {\n headers: { Authorization: `Bearer ${session.token}`, 'x-organization-id': session.orgId },\n signal,\n });\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: string; message?: string };\n throw new Error(`Mastra Platform request failed (${res.status}): ${body.message ?? body.error ?? path}`);\n }\n return (await res.json()) as T;\n}\n\nexport async function fetchPlatformOrgs(session: PlatformSession, signal?: AbortSignal): Promise<PlatformOrg[]> {\n const data = await platformGet<{ organizations?: PlatformOrg[]; orgs?: PlatformOrg[] }>(\n session,\n '/v1/auth/orgs',\n signal,\n );\n return data.organizations ?? data.orgs ?? [];\n}\n\nexport async function fetchPlatformProjects(\n session: PlatformSession,\n signal?: AbortSignal,\n): Promise<PlatformProject[]> {\n return (await platformGet<{ projects: PlatformProject[] }>(session, '/v1/projects', signal)).projects;\n}\n\nexport async function fetchPlatformEnvironments(\n session: PlatformSession,\n projectId: string,\n signal?: AbortSignal,\n): Promise<PlatformEnvironment[]> {\n return (\n await platformGet<{ environments: PlatformEnvironment[] }>(\n session,\n `/v1/projects/${encodeURIComponent(projectId)}/environments`,\n signal,\n )\n ).environments;\n}\n\nexport const FACTORY_DOMAIN = 'factory.mastra.cloud';\n\n/**\n * The Factory server URL for a deployed environment: a custom server wins,\n * otherwise the managed `<env slug>.factory.mastra.cloud` domain.\n */\nexport function resolveFactoryUrl(env: PlatformEnvironment): string | null {\n if (env.customServerUrl) {\n // The Platform session token is sent to this URL, so only accept HTTPS.\n try {\n const url = new URL(\n /^[a-z][a-z\\d+.-]*:\\/\\//i.test(env.customServerUrl) ? env.customServerUrl : `https://${env.customServerUrl}`,\n );\n if (url.protocol !== 'https:') return null;\n return `${url.origin}${url.pathname}`.replace(/\\/+$/, '');\n } catch {\n return null;\n }\n }\n if (!env.instanceUrl) return null;\n return `https://${env.slug}.${FACTORY_DOMAIN}`;\n}\n"],"mappings":"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"}
|