open-multi-agent-kit 0.90.5 → 0.90.7
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/CHANGELOG.md +39 -1
- package/README.md +9 -9
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/codexbar-cli.d.ts +39 -0
- package/dist/codexbar-cli.d.ts.map +1 -0
- package/dist/codexbar-cli.js +230 -0
- package/dist/codexbar-cli.js.map +1 -0
- package/dist/commands/doctor-provider.d.ts.map +1 -1
- package/dist/commands/doctor-provider.js +16 -3
- package/dist/commands/doctor-provider.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +30 -8
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/codexbar-adapter.d.ts +44 -0
- package/dist/core/codexbar-adapter.d.ts.map +1 -0
- package/dist/core/codexbar-adapter.js +211 -0
- package/dist/core/codexbar-adapter.js.map +1 -0
- package/dist/core/command-safety.d.ts.map +1 -1
- package/dist/core/command-safety.js +7 -0
- package/dist/core/command-safety.js.map +1 -1
- package/dist/core/compaction/index.d.ts +2 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +2 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/model-policy.d.ts +9 -0
- package/dist/core/compaction/model-policy.d.ts.map +1 -0
- package/dist/core/compaction/model-policy.js +37 -0
- package/dist/core/compaction/model-policy.js.map +1 -0
- package/dist/core/compaction/resume-policy.d.ts +6 -0
- package/dist/core/compaction/resume-policy.d.ts.map +1 -0
- package/dist/core/compaction/resume-policy.js +8 -0
- package/dist/core/compaction/resume-policy.js.map +1 -0
- package/dist/core/domain-loadouts.d.ts.map +1 -1
- package/dist/core/domain-loadouts.js +68 -1
- package/dist/core/domain-loadouts.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +12 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +15 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/grok-harness-dispatch.d.ts +22 -0
- package/dist/core/grok-harness-dispatch.d.ts.map +1 -0
- package/dist/core/grok-harness-dispatch.js +44 -0
- package/dist/core/grok-harness-dispatch.js.map +1 -0
- package/dist/core/grok-harness.d.ts +25 -0
- package/dist/core/grok-harness.d.ts.map +1 -0
- package/dist/core/grok-harness.js +61 -0
- package/dist/core/grok-harness.js.map +1 -0
- package/dist/core/grok-playbook.d.ts +7 -0
- package/dist/core/grok-playbook.d.ts.map +1 -0
- package/dist/core/grok-playbook.js +34 -0
- package/dist/core/grok-playbook.js.map +1 -0
- package/dist/core/reasoning-router-v4-normalize.d.ts +11 -0
- package/dist/core/reasoning-router-v4-normalize.d.ts.map +1 -0
- package/dist/core/reasoning-router-v4-normalize.js +224 -0
- package/dist/core/reasoning-router-v4-normalize.js.map +1 -0
- package/dist/core/reasoning-router-v4-weights.d.ts +13 -5
- package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4-weights.js +8 -4
- package/dist/core/reasoning-router-v4-weights.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +3 -3
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +394 -58
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/router-feedback-collector.d.ts +1 -1
- package/dist/core/router-feedback-collector.d.ts.map +1 -1
- package/dist/core/router-feedback-collector.js +9 -1
- package/dist/core/router-feedback-collector.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +31 -12
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +4 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +1 -0
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +2 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +3 -2
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +42 -17
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/adaptorch-preview.md +84 -0
- package/docs/correctness-wall.md +117 -0
- package/docs/grok-harness.md +63 -0
- package/docs/loadout-domains/README.md +2 -1
- package/docs/loadout-domains/ai-agent-ops.md +8 -1
- package/docs/loadout-domains/frontend-ui.md +5 -1
- package/docs/loadout-domains/grok-harness.md +74 -0
- package/docs/providers.md +4 -0
- package/examples/extensions/correctness-wall/LOADOUT.md +87 -0
- package/examples/extensions/correctness-wall/README.md +111 -0
- package/examples/extensions/correctness-wall/adjudication-fixture.ts +151 -0
- package/examples/extensions/correctness-wall/index.ts +470 -0
- package/examples/extensions/correctness-wall/repair-state.ts +77 -0
- package/examples/extensions/correctness-wall/wall-cache.ts +81 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/preset.ts +2 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +5 -5
package/dist/core/sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { Agent, type AgentMessage, type ThinkingLevel } from \"omk-agent-core\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple } from \"omk-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession } from \"./agent-session.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport { createDomainDispatchRuntimeSession, isDomainRoutingEnabled, tryDomainDispatch } from \"./domain-dispatch.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport type { LoadoutAccessPolicy } from \"./loadout-access-policy.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport type { BashSandboxPreflight } from \"./tools/bash.ts\";\nimport {\n\tallToolNames,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.omk/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: ModelRegistry.create(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, OMK enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n\t/**\n\t * Optional prompt hint used only for opt-in domain routing (`OMK_DOMAIN_ROUTING=1`).\n\t * This text only selects a loadout policy and is never sent to the model.\n\t */\n\tdomainRoutingPrompt?: string;\n\t/** Optional loadout enforcement policy for SDK-created sessions. */\n\tloadoutAccessPolicy?: LoadoutAccessPolicy;\n\t/** Trusted sandbox preflight used for built-in local bash execution. */\n\tbashSandboxPreflight?: BashSandboxPreflight;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\nfunction getDomainDispatchBaseToolNames(options: CreateAgentSessionOptions): string[] {\n\tif (!options.tools && (options.noTools === \"all\" || options.noTools === \"builtin\")) {\n\t\treturn [];\n\t}\n\treturn [...allToolNames];\n}\n\nfunction getAllowedToolNamesForDomainDispatch(options: CreateAgentSessionOptions): string[] | undefined {\n\treturn options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n}\n\nfunction createEffectiveLoadoutAccessPolicy(\n\toptions: CreateAgentSessionOptions,\n\tresourceLoader: ResourceLoader,\n\tcwd: string,\n\tagentDir: string,\n): LoadoutAccessPolicy | undefined {\n\tif (options.loadoutAccessPolicy) {\n\t\treturn options.loadoutAccessPolicy;\n\t}\n\tconst domainRoutingPrompt = options.domainRoutingPrompt?.trim();\n\tif (!domainRoutingPrompt || !isDomainRoutingEnabled(process.env)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst dispatch = tryDomainDispatch({\n\t\t\trole: \"coder\",\n\t\t\tinitialPrompt: domainRoutingPrompt,\n\t\t\tsession: createDomainDispatchRuntimeSession({\n\t\t\t\tbaseToolNames: getDomainDispatchBaseToolNames(options),\n\t\t\t\tresourceLoader,\n\t\t\t\tcustomTools: options.customTools,\n\t\t\t\tallowedToolNames: getAllowedToolNamesForDomainDispatch(options),\n\t\t\t\texcludedToolNames: options.excludeTools,\n\t\t\t}),\n\t\t\tresourceLoader,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tenv: process.env,\n\t\t});\n\t\treturn dispatch.loadoutAccessPolicy;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from 'omk-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Compute effective loadout access policy from explicit option or opt-in domain routing hint.\n\t// The policy is not wired into AgentSession in this lane; it is computed here so the option\n\t// surface exists and downstream lanes can apply it without changing the public type again.\n\tconst effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(options, resourceLoader, cwd, agentDir);\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst auth = await modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (!auth.ok) {\n\t\t\t\tthrow new Error(auth.error);\n\t\t\t}\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\treturn streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\theaders: mergeProviderAttributionHeaders(\n\t\t\t\t\tmodel,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\tauth.headers,\n\t\t\t\t\toptions?.headers,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tloadoutAccessPolicy: effectiveLoadoutAccessPolicy,\n\t\tbashSandboxPreflight: options.bashSandboxPreflight,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { Agent, type AgentMessage, type ThinkingLevel } from \"omk-agent-core\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple } from \"omk-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession } from \"./agent-session.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport { createDomainDispatchRuntimeSession, isDomainRoutingEnabled, tryDomainDispatch } from \"./domain-dispatch.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { tryGrokHarnessDispatch } from \"./grok-harness-dispatch.ts\";\nimport type { LoadoutAccessPolicy } from \"./loadout-access-policy.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport type { BashSandboxPreflight } from \"./tools/bash.ts\";\nimport {\n\tallToolNames,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.omk/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: ModelRegistry.create(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, OMK enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n\t/**\n\t * Optional prompt hint used only for opt-in domain routing (`OMK_DOMAIN_ROUTING=1`).\n\t * This text only selects a loadout policy and is never sent to the model.\n\t */\n\tdomainRoutingPrompt?: string;\n\t/** Optional loadout enforcement policy for SDK-created sessions. */\n\tloadoutAccessPolicy?: LoadoutAccessPolicy;\n\t/** Trusted sandbox preflight used for built-in local bash execution. */\n\tbashSandboxPreflight?: BashSandboxPreflight;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\nfunction getDomainDispatchBaseToolNames(options: CreateAgentSessionOptions): string[] {\n\tif (!options.tools && (options.noTools === \"all\" || options.noTools === \"builtin\")) {\n\t\treturn [];\n\t}\n\treturn [...allToolNames];\n}\n\nfunction getAllowedToolNamesForDomainDispatch(options: CreateAgentSessionOptions): string[] | undefined {\n\treturn options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n}\n\nfunction createEffectiveLoadoutAccessPolicy(\n\toptions: CreateAgentSessionOptions,\n\tresourceLoader: ResourceLoader,\n\tcwd: string,\n\tagentDir: string,\n\tprovider?: string,\n): LoadoutAccessPolicy | undefined {\n\tif (options.loadoutAccessPolicy) {\n\t\treturn options.loadoutAccessPolicy;\n\t}\n\n\tconst session = createDomainDispatchRuntimeSession({\n\t\tbaseToolNames: getDomainDispatchBaseToolNames(options),\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tallowedToolNames: getAllowedToolNamesForDomainDispatch(options),\n\t\texcludedToolNames: options.excludeTools,\n\t});\n\n\t// Grok OAuth: apply grok-harness domain loadout without requiring OMK_DOMAIN_ROUTING=1.\n\tif (provider) {\n\t\ttry {\n\t\t\tconst grokDispatch = tryGrokHarnessDispatch({\n\t\t\t\tprovider,\n\t\t\t\tsession,\n\t\t\t\tresourceLoader,\n\t\t\t\tcwd,\n\t\t\t\tagentDir,\n\t\t\t\tenv: process.env,\n\t\t\t});\n\t\t\tif (grokDispatch.loadoutAccessPolicy) {\n\t\t\t\treturn grokDispatch.loadoutAccessPolicy;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to opt-in domain routing.\n\t\t}\n\t}\n\n\tconst domainRoutingPrompt = options.domainRoutingPrompt?.trim();\n\tif (!domainRoutingPrompt || !isDomainRoutingEnabled(process.env)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst dispatch = tryDomainDispatch({\n\t\t\trole: \"coder\",\n\t\t\tinitialPrompt: domainRoutingPrompt,\n\t\t\tsession,\n\t\t\tresourceLoader,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tenv: process.env,\n\t\t});\n\t\treturn dispatch.loadoutAccessPolicy;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from 'omk-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\t// Loadout policy after model resolution so Grok OAuth can auto-apply grok-harness.\n\tconst effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(\n\t\toptions,\n\t\tresourceLoader,\n\t\tcwd,\n\t\tagentDir,\n\t\tmodel?.provider,\n\t);\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst auth = await modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (!auth.ok) {\n\t\t\t\tthrow new Error(auth.error);\n\t\t\t}\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\treturn streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\theaders: mergeProviderAttributionHeaders(\n\t\t\t\t\tmodel,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\tauth.headers,\n\t\t\t\t\toptions?.headers,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tloadoutAccessPolicy: effectiveLoadoutAccessPolicy,\n\t\tbashSandboxPreflight: options.bashSandboxPreflight,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
package/dist/core/sdk.js
CHANGED
|
@@ -8,6 +8,7 @@ import { formatNoModelsAvailableMessage } from "./auth-guidance.js";
|
|
|
8
8
|
import { AuthStorage } from "./auth-storage.js";
|
|
9
9
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
10
10
|
import { createDomainDispatchRuntimeSession, isDomainRoutingEnabled, tryDomainDispatch } from "./domain-dispatch.js";
|
|
11
|
+
import { tryGrokHarnessDispatch } from "./grok-harness-dispatch.js";
|
|
11
12
|
import { convertToLlm } from "./messages.js";
|
|
12
13
|
import { ModelRegistry } from "./model-registry.js";
|
|
13
14
|
import { findInitialModel } from "./model-resolver.js";
|
|
@@ -35,10 +36,36 @@ function getDomainDispatchBaseToolNames(options) {
|
|
|
35
36
|
function getAllowedToolNamesForDomainDispatch(options) {
|
|
36
37
|
return options.tools ?? (options.noTools === "all" ? [] : undefined);
|
|
37
38
|
}
|
|
38
|
-
function createEffectiveLoadoutAccessPolicy(options, resourceLoader, cwd, agentDir) {
|
|
39
|
+
function createEffectiveLoadoutAccessPolicy(options, resourceLoader, cwd, agentDir, provider) {
|
|
39
40
|
if (options.loadoutAccessPolicy) {
|
|
40
41
|
return options.loadoutAccessPolicy;
|
|
41
42
|
}
|
|
43
|
+
const session = createDomainDispatchRuntimeSession({
|
|
44
|
+
baseToolNames: getDomainDispatchBaseToolNames(options),
|
|
45
|
+
resourceLoader,
|
|
46
|
+
customTools: options.customTools,
|
|
47
|
+
allowedToolNames: getAllowedToolNamesForDomainDispatch(options),
|
|
48
|
+
excludedToolNames: options.excludeTools,
|
|
49
|
+
});
|
|
50
|
+
// Grok OAuth: apply grok-harness domain loadout without requiring OMK_DOMAIN_ROUTING=1.
|
|
51
|
+
if (provider) {
|
|
52
|
+
try {
|
|
53
|
+
const grokDispatch = tryGrokHarnessDispatch({
|
|
54
|
+
provider,
|
|
55
|
+
session,
|
|
56
|
+
resourceLoader,
|
|
57
|
+
cwd,
|
|
58
|
+
agentDir,
|
|
59
|
+
env: process.env,
|
|
60
|
+
});
|
|
61
|
+
if (grokDispatch.loadoutAccessPolicy) {
|
|
62
|
+
return grokDispatch.loadoutAccessPolicy;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Fall through to opt-in domain routing.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
42
69
|
const domainRoutingPrompt = options.domainRoutingPrompt?.trim();
|
|
43
70
|
if (!domainRoutingPrompt || !isDomainRoutingEnabled(process.env)) {
|
|
44
71
|
return undefined;
|
|
@@ -47,13 +74,7 @@ function createEffectiveLoadoutAccessPolicy(options, resourceLoader, cwd, agentD
|
|
|
47
74
|
const dispatch = tryDomainDispatch({
|
|
48
75
|
role: "coder",
|
|
49
76
|
initialPrompt: domainRoutingPrompt,
|
|
50
|
-
session
|
|
51
|
-
baseToolNames: getDomainDispatchBaseToolNames(options),
|
|
52
|
-
resourceLoader,
|
|
53
|
-
customTools: options.customTools,
|
|
54
|
-
allowedToolNames: getAllowedToolNamesForDomainDispatch(options),
|
|
55
|
-
excludedToolNames: options.excludeTools,
|
|
56
|
-
}),
|
|
77
|
+
session,
|
|
57
78
|
resourceLoader,
|
|
58
79
|
cwd,
|
|
59
80
|
agentDir,
|
|
@@ -116,10 +137,6 @@ export async function createAgentSession(options = {}) {
|
|
|
116
137
|
await resourceLoader.reload();
|
|
117
138
|
time("resourceLoader.reload");
|
|
118
139
|
}
|
|
119
|
-
// Compute effective loadout access policy from explicit option or opt-in domain routing hint.
|
|
120
|
-
// The policy is not wired into AgentSession in this lane; it is computed here so the option
|
|
121
|
-
// surface exists and downstream lanes can apply it without changing the public type again.
|
|
122
|
-
const effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(options, resourceLoader, cwd, agentDir);
|
|
123
140
|
// Check if session has existing data to restore
|
|
124
141
|
const existingSession = sessionManager.buildSessionContext();
|
|
125
142
|
const hasExistingSession = existingSession.messages.length > 0;
|
|
@@ -154,6 +171,8 @@ export async function createAgentSession(options = {}) {
|
|
|
154
171
|
modelFallbackMessage += `. Using ${model.provider}/${model.id}`;
|
|
155
172
|
}
|
|
156
173
|
}
|
|
174
|
+
// Loadout policy after model resolution so Grok OAuth can auto-apply grok-harness.
|
|
175
|
+
const effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(options, resourceLoader, cwd, agentDir, model?.provider);
|
|
157
176
|
let thinkingLevel = options.thinkingLevel;
|
|
158
177
|
// If session has data, restore thinking level from it
|
|
159
178
|
if (thinkingLevel === undefined && hasExistingSession) {
|
package/dist/core/sdk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { Agent, type AgentMessage, type ThinkingLevel } from \"omk-agent-core\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple } from \"omk-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession } from \"./agent-session.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport { createDomainDispatchRuntimeSession, isDomainRoutingEnabled, tryDomainDispatch } from \"./domain-dispatch.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport type { LoadoutAccessPolicy } from \"./loadout-access-policy.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport type { BashSandboxPreflight } from \"./tools/bash.ts\";\nimport {\n\tallToolNames,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.omk/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: ModelRegistry.create(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, OMK enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n\t/**\n\t * Optional prompt hint used only for opt-in domain routing (`OMK_DOMAIN_ROUTING=1`).\n\t * This text only selects a loadout policy and is never sent to the model.\n\t */\n\tdomainRoutingPrompt?: string;\n\t/** Optional loadout enforcement policy for SDK-created sessions. */\n\tloadoutAccessPolicy?: LoadoutAccessPolicy;\n\t/** Trusted sandbox preflight used for built-in local bash execution. */\n\tbashSandboxPreflight?: BashSandboxPreflight;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\nfunction getDomainDispatchBaseToolNames(options: CreateAgentSessionOptions): string[] {\n\tif (!options.tools && (options.noTools === \"all\" || options.noTools === \"builtin\")) {\n\t\treturn [];\n\t}\n\treturn [...allToolNames];\n}\n\nfunction getAllowedToolNamesForDomainDispatch(options: CreateAgentSessionOptions): string[] | undefined {\n\treturn options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n}\n\nfunction createEffectiveLoadoutAccessPolicy(\n\toptions: CreateAgentSessionOptions,\n\tresourceLoader: ResourceLoader,\n\tcwd: string,\n\tagentDir: string,\n): LoadoutAccessPolicy | undefined {\n\tif (options.loadoutAccessPolicy) {\n\t\treturn options.loadoutAccessPolicy;\n\t}\n\tconst domainRoutingPrompt = options.domainRoutingPrompt?.trim();\n\tif (!domainRoutingPrompt || !isDomainRoutingEnabled(process.env)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst dispatch = tryDomainDispatch({\n\t\t\trole: \"coder\",\n\t\t\tinitialPrompt: domainRoutingPrompt,\n\t\t\tsession: createDomainDispatchRuntimeSession({\n\t\t\t\tbaseToolNames: getDomainDispatchBaseToolNames(options),\n\t\t\t\tresourceLoader,\n\t\t\t\tcustomTools: options.customTools,\n\t\t\t\tallowedToolNames: getAllowedToolNamesForDomainDispatch(options),\n\t\t\t\texcludedToolNames: options.excludeTools,\n\t\t\t}),\n\t\t\tresourceLoader,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tenv: process.env,\n\t\t});\n\t\treturn dispatch.loadoutAccessPolicy;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from 'omk-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Compute effective loadout access policy from explicit option or opt-in domain routing hint.\n\t// The policy is not wired into AgentSession in this lane; it is computed here so the option\n\t// surface exists and downstream lanes can apply it without changing the public type again.\n\tconst effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(options, resourceLoader, cwd, agentDir);\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst auth = await modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (!auth.ok) {\n\t\t\t\tthrow new Error(auth.error);\n\t\t\t}\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\treturn streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\theaders: mergeProviderAttributionHeaders(\n\t\t\t\t\tmodel,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\tauth.headers,\n\t\t\t\t\toptions?.headers,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tloadoutAccessPolicy: effectiveLoadoutAccessPolicy,\n\t\tbashSandboxPreflight: options.bashSandboxPreflight,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { Agent, type AgentMessage, type ThinkingLevel } from \"omk-agent-core\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple } from \"omk-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession } from \"./agent-session.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport { createDomainDispatchRuntimeSession, isDomainRoutingEnabled, tryDomainDispatch } from \"./domain-dispatch.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { tryGrokHarnessDispatch } from \"./grok-harness-dispatch.ts\";\nimport type { LoadoutAccessPolicy } from \"./loadout-access-policy.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport type { BashSandboxPreflight } from \"./tools/bash.ts\";\nimport {\n\tallToolNames,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.omk/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: ModelRegistry.create(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, OMK enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n\t/**\n\t * Optional prompt hint used only for opt-in domain routing (`OMK_DOMAIN_ROUTING=1`).\n\t * This text only selects a loadout policy and is never sent to the model.\n\t */\n\tdomainRoutingPrompt?: string;\n\t/** Optional loadout enforcement policy for SDK-created sessions. */\n\tloadoutAccessPolicy?: LoadoutAccessPolicy;\n\t/** Trusted sandbox preflight used for built-in local bash execution. */\n\tbashSandboxPreflight?: BashSandboxPreflight;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\nfunction getDomainDispatchBaseToolNames(options: CreateAgentSessionOptions): string[] {\n\tif (!options.tools && (options.noTools === \"all\" || options.noTools === \"builtin\")) {\n\t\treturn [];\n\t}\n\treturn [...allToolNames];\n}\n\nfunction getAllowedToolNamesForDomainDispatch(options: CreateAgentSessionOptions): string[] | undefined {\n\treturn options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n}\n\nfunction createEffectiveLoadoutAccessPolicy(\n\toptions: CreateAgentSessionOptions,\n\tresourceLoader: ResourceLoader,\n\tcwd: string,\n\tagentDir: string,\n\tprovider?: string,\n): LoadoutAccessPolicy | undefined {\n\tif (options.loadoutAccessPolicy) {\n\t\treturn options.loadoutAccessPolicy;\n\t}\n\n\tconst session = createDomainDispatchRuntimeSession({\n\t\tbaseToolNames: getDomainDispatchBaseToolNames(options),\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tallowedToolNames: getAllowedToolNamesForDomainDispatch(options),\n\t\texcludedToolNames: options.excludeTools,\n\t});\n\n\t// Grok OAuth: apply grok-harness domain loadout without requiring OMK_DOMAIN_ROUTING=1.\n\tif (provider) {\n\t\ttry {\n\t\t\tconst grokDispatch = tryGrokHarnessDispatch({\n\t\t\t\tprovider,\n\t\t\t\tsession,\n\t\t\t\tresourceLoader,\n\t\t\t\tcwd,\n\t\t\t\tagentDir,\n\t\t\t\tenv: process.env,\n\t\t\t});\n\t\t\tif (grokDispatch.loadoutAccessPolicy) {\n\t\t\t\treturn grokDispatch.loadoutAccessPolicy;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to opt-in domain routing.\n\t\t}\n\t}\n\n\tconst domainRoutingPrompt = options.domainRoutingPrompt?.trim();\n\tif (!domainRoutingPrompt || !isDomainRoutingEnabled(process.env)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst dispatch = tryDomainDispatch({\n\t\t\trole: \"coder\",\n\t\t\tinitialPrompt: domainRoutingPrompt,\n\t\t\tsession,\n\t\t\tresourceLoader,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tenv: process.env,\n\t\t});\n\t\treturn dispatch.loadoutAccessPolicy;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from 'omk-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\t// Loadout policy after model resolution so Grok OAuth can auto-apply grok-harness.\n\tconst effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(\n\t\toptions,\n\t\tresourceLoader,\n\t\tcwd,\n\t\tagentDir,\n\t\tmodel?.provider,\n\t);\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst auth = await modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (!auth.ok) {\n\t\t\t\tthrow new Error(auth.error);\n\t\t\t}\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\treturn streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\theaders: mergeProviderAttributionHeaders(\n\t\t\t\t\tmodel,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\tauth.headers,\n\t\t\t\t\toptions?.headers,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tloadoutAccessPolicy: effectiveLoadoutAccessPolicy,\n\t\tbashSandboxPreflight: options.bashSandboxPreflight,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
@@ -76,7 +76,7 @@ export interface Settings {
|
|
|
76
76
|
lastChangelogVersion?: string;
|
|
77
77
|
defaultProvider?: string;
|
|
78
78
|
defaultModel?: string;
|
|
79
|
-
defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
79
|
+
defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | "ultra";
|
|
80
80
|
transport?: TransportSetting;
|
|
81
81
|
steeringMode?: "all" | "one-at-a-time";
|
|
82
82
|
followUpMode?: "all" | "one-at-a-time";
|
|
@@ -189,8 +189,8 @@ export declare class SettingsManager {
|
|
|
189
189
|
setFollowUpMode(mode: "all" | "one-at-a-time"): void;
|
|
190
190
|
getTheme(): string | undefined;
|
|
191
191
|
setTheme(theme: string): void;
|
|
192
|
-
getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
193
|
-
setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"): void;
|
|
192
|
+
getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | "ultra" | undefined;
|
|
193
|
+
setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | "ultra"): void;
|
|
194
194
|
getTransport(): TransportSetting;
|
|
195
195
|
setTransport(transport: TransportSetting): void;
|
|
196
196
|
getCompactionEnabled(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport type { Transport } from \"omk-ai\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { normalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from \"./http-dispatcher.ts\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n\tmaxUsageRatio?: number; // default: 0.9\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\n/**\n * Opt-in reasoning-router learning bias settings (Goal 010 Lane I). Global\n * scope only by construction: every `SettingsManager` getter for this field\n * reads directly from the raw global settings file (`globalSettings`), never\n * the merged/project-overridable view (`settings`) that most other fields\n * use -- so a project-scope `.omk/settings.json` value for any key here is\n * always ignored, never activates or redirects this feature. Default is\n * fully off; there is no project-scope setter for this field.\n */\nexport interface ReasoningRouterLearningSettings {\n\t/** default: false */\n\tenabled?: boolean;\n\t/** Override path for the compiled bias snapshot the v4 auto-router reads (see reasoning-router-bias.ts for the default). */\n\tbiasSnapshotPath?: string;\n\t/** Override path for the local feedback ledger the v4 auto-router appends to (see router-feedback-collector.ts for the default). */\n\tfeedbackLedgerPath?: string;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport interface WarningSettings {\n\tanthropicExtraUsage?: boolean; // default: true\n}\n\nexport type TransportSetting = Transport;\n\n/**\n * Package source for npm/git packages.\n * - String form: load all resources from the package\n * - Object form: filter which resources to load\n */\nexport type PackageSource =\n\t| string\n\t| {\n\t\t\tsource: string;\n\t\t\textensions?: string[];\n\t\t\tskills?: string[];\n\t\t\tprompts?: string[];\n\t\t\tthemes?: string[];\n\t };\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\ttransport?: TransportSetting; // default: \"auto\"\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tbranchSummary?: BranchSummarySettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tquietStartup?: boolean;\n\tshellCommandPrefix?: string; // Prefix prepended to every bash command (e.g., \"shopt -s expand_aliases\" for alias support)\n\tnpmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., [\"mise\", \"exec\", \"node@20\", \"--\", \"npm\"])\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\tenableInstallTelemetry?: boolean; // default: true - anonymous version/update ping after changelog-detected updates\n\tpackages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)\n\textensions?: string[]; // Array of local extension file paths or directories\n\tskills?: string[]; // Array of local skill file paths or directories\n\tprompts?: string[]; // Array of local prompt template paths or directories\n\tthemes?: string[]; // Array of local theme file paths or directories\n\tenableSkillCommands?: boolean; // default: true - register skills as /skill:name commands\n\tterminal?: TerminalSettings;\n\timages?: ImageSettings;\n\tenabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)\n\tdoubleEscapeAction?: \"fork\" | \"tree\" | \"none\"; // Action for double-escape with empty editor (default: \"tree\")\n\ttreeFilterMode?: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"; // Default filter when opening /tree\n\tthinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels\n\treasoningRouterLearning?: ReasoningRouterLearningSettings; // Opt-in v4 learning bias (default off; global-only, see SettingsManager getters)\n\teditorPaddingX?: number; // Horizontal padding for input editor (default: 0)\n\tautocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)\n\tshowHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME\n\tmarkdown?: MarkdownSettings;\n\twarnings?: WarningSettings;\n\tsessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)\n\thttpIdleTimeoutMs?: number; // HTTP header/body idle timeout in milliseconds; 0 disables it\n\twebsocketConnectTimeoutMs?: number; // WebSocket connect/open handshake timeout in milliseconds; 0 disables it\n}\n\n/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */\nfunction deepMergeSettings(base: Settings, overrides: Settings): Settings {\n\tconst result: Settings = { ...base };\n\n\tfor (const key of Object.keys(overrides) as (keyof Settings)[]) {\n\t\tconst overrideValue = overrides[key];\n\t\tconst baseValue = base[key];\n\n\t\tif (overrideValue === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// For nested objects, merge recursively\n\t\tif (\n\t\t\ttypeof overrideValue === \"object\" &&\n\t\t\toverrideValue !== null &&\n\t\t\t!Array.isArray(overrideValue) &&\n\t\t\ttypeof baseValue === \"object\" &&\n\t\t\tbaseValue !== null &&\n\t\t\t!Array.isArray(baseValue)\n\t\t) {\n\t\t\t(result as Record<string, unknown>)[key] = { ...baseValue, ...overrideValue };\n\t\t} else {\n\t\t\t// For primitives and arrays, override value wins\n\t\t\t(result as Record<string, unknown>)[key] = overrideValue;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction parseTimeoutSetting(value: unknown, settingName: string): number | undefined {\n\tconst timeoutMs = parseHttpIdleTimeoutMs(value);\n\tif (timeoutMs !== undefined) {\n\t\treturn timeoutMs;\n\t}\n\tif (value !== undefined) {\n\t\tthrow new Error(`Invalid ${settingName} setting: ${String(value)}`);\n\t}\n\treturn undefined;\n}\n\nexport type SettingsScope = \"global\" | \"project\";\n\nexport interface SettingsStorage {\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void;\n}\n\nexport interface SettingsError {\n\tscope: SettingsScope;\n\terror: Error;\n}\n\nexport class FileSettingsStorage implements SettingsStorage {\n\tprivate globalSettingsPath: string;\n\tprivate projectSettingsPath: string;\n\n\tconstructor(cwd: string, agentDir: string) {\n\t\tconst resolvedCwd = resolvePath(cwd);\n\t\tconst resolvedAgentDir = resolvePath(agentDir);\n\t\tthis.globalSettingsPath = join(resolvedAgentDir, \"settings.json\");\n\t\tthis.projectSettingsPath = join(resolvedCwd, CONFIG_DIR_NAME, \"settings.json\");\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire settings lock\");\n\t}\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst path = scope === \"global\" ? this.globalSettingsPath : this.projectSettingsPath;\n\t\tconst dir = dirname(path);\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\t// Only create directory and lock if file exists or we need to write\n\t\t\tconst fileExists = existsSync(path);\n\t\t\tif (fileExists) {\n\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t}\n\t\t\tconst current = fileExists ? readFileSync(path, \"utf-8\") : undefined;\n\t\t\tconst next = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\t// Only create directory when we actually need to write\n\t\t\t\tif (!existsSync(dir)) {\n\t\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t\t}\n\t\t\t\tif (!release) {\n\t\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t\t}\n\t\t\t\twriteFileSync(path, next, \"utf-8\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemorySettingsStorage implements SettingsStorage {\n\tprivate global: string | undefined;\n\tprivate project: string | undefined;\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst current = scope === \"global\" ? this.global : this.project;\n\t\tconst next = fn(current);\n\t\tif (next !== undefined) {\n\t\t\tif (scope === \"global\") {\n\t\t\t\tthis.global = next;\n\t\t\t} else {\n\t\t\t\tthis.project = next;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class SettingsManager {\n\tprivate storage: SettingsStorage;\n\tprivate globalSettings: Settings;\n\tprivate projectSettings: Settings;\n\tprivate settings: Settings;\n\tprivate modifiedFields = new Set<keyof Settings>(); // Track global fields modified during session\n\tprivate modifiedNestedFields = new Map<keyof Settings, Set<string>>(); // Track global nested field modifications\n\tprivate modifiedProjectFields = new Set<keyof Settings>(); // Track project fields modified during session\n\tprivate modifiedProjectNestedFields = new Map<keyof Settings, Set<string>>(); // Track project nested field modifications\n\tprivate globalSettingsLoadError: Error | null = null; // Track if global settings file had parse errors\n\tprivate projectSettingsLoadError: Error | null = null; // Track if project settings file had parse errors\n\tprivate writeQueue: Promise<void> = Promise.resolve();\n\tprivate errors: SettingsError[];\n\n\tprivate constructor(\n\t\tstorage: SettingsStorage,\n\t\tinitialGlobal: Settings,\n\t\tinitialProject: Settings,\n\t\tglobalLoadError: Error | null = null,\n\t\tprojectLoadError: Error | null = null,\n\t\tinitialErrors: SettingsError[] = [],\n\t) {\n\t\tthis.storage = storage;\n\t\tthis.globalSettings = initialGlobal;\n\t\tthis.projectSettings = initialProject;\n\t\tthis.globalSettingsLoadError = globalLoadError;\n\t\tthis.projectSettingsLoadError = projectLoadError;\n\t\tthis.errors = [...initialErrors];\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Create a SettingsManager that loads from files */\n\tstatic create(cwd: string, agentDir: string = getAgentDir()): SettingsManager {\n\t\tconst storage = new FileSettingsStorage(cwd, agentDir);\n\t\treturn SettingsManager.fromStorage(storage);\n\t}\n\n\t/** Create a SettingsManager from an arbitrary storage backend */\n\tstatic fromStorage(storage: SettingsStorage): SettingsManager {\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(storage, \"global\");\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(storage, \"project\");\n\t\tconst initialErrors: SettingsError[] = [];\n\t\tif (globalLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"global\", error: globalLoad.error });\n\t\t}\n\t\tif (projectLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"project\", error: projectLoad.error });\n\t\t}\n\n\t\treturn new SettingsManager(\n\t\t\tstorage,\n\t\t\tglobalLoad.settings,\n\t\t\tprojectLoad.settings,\n\t\t\tglobalLoad.error,\n\t\t\tprojectLoad.error,\n\t\t\tinitialErrors,\n\t\t);\n\t}\n\n\t/** Create an in-memory SettingsManager (no file I/O) */\n\tstatic inMemory(settings: Partial<Settings> = {}): SettingsManager {\n\t\tconst storage = new InMemorySettingsStorage();\n\t\tconst initialSettings = SettingsManager.migrateSettings(structuredClone(settings) as Record<string, unknown>);\n\t\tstorage.withLock(\"global\", () => JSON.stringify(initialSettings, null, 2));\n\t\treturn SettingsManager.fromStorage(storage);\n\t}\n\n\tprivate static loadFromStorage(storage: SettingsStorage, scope: SettingsScope): Settings {\n\t\tlet content: string | undefined;\n\t\tstorage.withLock(scope, (current) => {\n\t\t\tcontent = current;\n\t\t\treturn undefined;\n\t\t});\n\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\tconst settings = JSON.parse(content);\n\t\treturn SettingsManager.migrateSettings(settings);\n\t}\n\n\tprivate static tryLoadFromStorage(\n\t\tstorage: SettingsStorage,\n\t\tscope: SettingsScope,\n\t): { settings: Settings; error: Error | null } {\n\t\ttry {\n\t\t\treturn { settings: SettingsManager.loadFromStorage(storage, scope), error: null };\n\t\t} catch (error) {\n\t\t\treturn { settings: {}, error: error as Error };\n\t\t}\n\t}\n\n\t/** Migrate old settings format to new format */\n\tprivate static migrateSettings(settings: Record<string, unknown>): Settings {\n\t\t// Migrate queueMode -> steeringMode\n\t\tif (\"queueMode\" in settings && !(\"steeringMode\" in settings)) {\n\t\t\tsettings.steeringMode = settings.queueMode;\n\t\t\tdelete settings.queueMode;\n\t\t}\n\n\t\t// Migrate legacy websockets boolean -> transport enum\n\t\tif (!(\"transport\" in settings) && typeof settings.websockets === \"boolean\") {\n\t\t\tsettings.transport = settings.websockets ? \"websocket\" : \"sse\";\n\t\t\tdelete settings.websockets;\n\t\t}\n\n\t\t// Migrate old skills object format to new array format\n\t\tif (\n\t\t\t\"skills\" in settings &&\n\t\t\ttypeof settings.skills === \"object\" &&\n\t\t\tsettings.skills !== null &&\n\t\t\t!Array.isArray(settings.skills)\n\t\t) {\n\t\t\tconst skillsSettings = settings.skills as {\n\t\t\t\tenableSkillCommands?: boolean;\n\t\t\t\tcustomDirectories?: unknown;\n\t\t\t};\n\t\t\tif (skillsSettings.enableSkillCommands !== undefined && settings.enableSkillCommands === undefined) {\n\t\t\t\tsettings.enableSkillCommands = skillsSettings.enableSkillCommands;\n\t\t\t}\n\t\t\tif (Array.isArray(skillsSettings.customDirectories) && skillsSettings.customDirectories.length > 0) {\n\t\t\t\tsettings.skills = skillsSettings.customDirectories;\n\t\t\t} else {\n\t\t\t\tdelete settings.skills;\n\t\t\t}\n\t\t}\n\n\t\t// Migrate retry.maxDelayMs -> retry.provider.maxRetryDelayMs\n\t\tif (\n\t\t\t\"retry\" in settings &&\n\t\t\ttypeof settings.retry === \"object\" &&\n\t\t\tsettings.retry !== null &&\n\t\t\t!Array.isArray(settings.retry)\n\t\t) {\n\t\t\tconst retrySettings = settings.retry as Record<string, unknown>;\n\t\t\tconst providerSettings =\n\t\t\t\ttypeof retrySettings.provider === \"object\" && retrySettings.provider !== null\n\t\t\t\t\t? (retrySettings.provider as Record<string, unknown>)\n\t\t\t\t\t: undefined;\n\t\t\tif (\n\t\t\t\ttypeof retrySettings.maxDelayMs === \"number\" &&\n\t\t\t\t(providerSettings?.maxRetryDelayMs === undefined || providerSettings?.maxRetryDelayMs === null)\n\t\t\t) {\n\t\t\t\tretrySettings.provider = {\n\t\t\t\t\t...(providerSettings ?? {}),\n\t\t\t\t\tmaxRetryDelayMs: retrySettings.maxDelayMs,\n\t\t\t\t};\n\t\t\t}\n\t\t\tdelete retrySettings.maxDelayMs;\n\t\t}\n\n\t\treturn settings as Settings;\n\t}\n\n\tgetGlobalSettings(): Settings {\n\t\treturn structuredClone(this.globalSettings);\n\t}\n\n\tgetProjectSettings(): Settings {\n\t\treturn structuredClone(this.projectSettings);\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait this.writeQueue;\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(this.storage, \"global\");\n\t\tif (!globalLoad.error) {\n\t\t\tthis.globalSettings = globalLoad.settings;\n\t\t\tthis.globalSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.globalSettingsLoadError = globalLoad.error;\n\t\t\tthis.recordError(\"global\", globalLoad.error);\n\t\t}\n\n\t\tthis.modifiedFields.clear();\n\t\tthis.modifiedNestedFields.clear();\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(this.storage, \"project\");\n\t\tif (!projectLoad.error) {\n\t\t\tthis.projectSettings = projectLoad.settings;\n\t\t\tthis.projectSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.projectSettingsLoadError = projectLoad.error;\n\t\t\tthis.recordError(\"project\", projectLoad.error);\n\t\t}\n\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Apply additional overrides on top of current settings */\n\tapplyOverrides(overrides: Partial<Settings>): void {\n\t\tthis.settings = deepMergeSettings(this.settings, overrides);\n\t}\n\n\t/** Mark a global field as modified during this session */\n\tprivate markModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedNestedFields.has(field)) {\n\t\t\t\tthis.modifiedNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\t/** Mark a project field as modified during this session */\n\tprivate markProjectModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedProjectFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedProjectNestedFields.has(field)) {\n\t\t\t\tthis.modifiedProjectNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedProjectNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\tprivate recordError(scope: SettingsScope, error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push({ scope, error: normalizedError });\n\t}\n\n\tprivate clearModifiedScope(scope: SettingsScope): void {\n\t\tif (scope === \"global\") {\n\t\t\tthis.modifiedFields.clear();\n\t\t\tthis.modifiedNestedFields.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\t}\n\n\tprivate enqueueWrite(scope: SettingsScope, task: () => void): void {\n\t\tthis.writeQueue = this.writeQueue\n\t\t\t.then(() => {\n\t\t\t\ttask();\n\t\t\t\tthis.clearModifiedScope(scope);\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.recordError(scope, error);\n\t\t\t});\n\t}\n\n\tprivate cloneModifiedNestedFields(source: Map<keyof Settings, Set<string>>): Map<keyof Settings, Set<string>> {\n\t\tconst snapshot = new Map<keyof Settings, Set<string>>();\n\t\tfor (const [key, value] of source.entries()) {\n\t\t\tsnapshot.set(key, new Set(value));\n\t\t}\n\t\treturn snapshot;\n\t}\n\n\tprivate persistScopedSettings(\n\t\tscope: SettingsScope,\n\t\tsnapshotSettings: Settings,\n\t\tmodifiedFields: Set<keyof Settings>,\n\t\tmodifiedNestedFields: Map<keyof Settings, Set<string>>,\n\t): void {\n\t\tthis.storage.withLock(scope, (current) => {\n\t\t\tconst currentFileSettings = current\n\t\t\t\t? SettingsManager.migrateSettings(JSON.parse(current) as Record<string, unknown>)\n\t\t\t\t: {};\n\t\t\tconst mergedSettings: Settings = { ...currentFileSettings };\n\t\t\tfor (const field of modifiedFields) {\n\t\t\t\tconst value = snapshotSettings[field];\n\t\t\t\tif (modifiedNestedFields.has(field) && typeof value === \"object\" && value !== null) {\n\t\t\t\t\tconst nestedModified = modifiedNestedFields.get(field)!;\n\t\t\t\t\tconst baseNested = (currentFileSettings[field] as Record<string, unknown>) ?? {};\n\t\t\t\t\tconst inMemoryNested = value as Record<string, unknown>;\n\t\t\t\t\tconst mergedNested = { ...baseNested };\n\t\t\t\t\tfor (const nestedKey of nestedModified) {\n\t\t\t\t\t\tmergedNested[nestedKey] = inMemoryNested[nestedKey];\n\t\t\t\t\t}\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = mergedNested;\n\t\t\t\t} else {\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn JSON.stringify(mergedSettings, null, 2);\n\t\t});\n\t}\n\n\tprivate save(): void {\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.globalSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotGlobalSettings = structuredClone(this.globalSettings);\n\t\tconst modifiedFields = new Set(this.modifiedFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedNestedFields);\n\n\t\tthis.enqueueWrite(\"global\", () => {\n\t\t\tthis.persistScopedSettings(\"global\", snapshotGlobalSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tprivate saveProjectSettings(settings: Settings): void {\n\t\tthis.projectSettings = structuredClone(settings);\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.projectSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotProjectSettings = structuredClone(this.projectSettings);\n\t\tconst modifiedFields = new Set(this.modifiedProjectFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);\n\t\tthis.enqueueWrite(\"project\", () => {\n\t\t\tthis.persistScopedSettings(\"project\", snapshotProjectSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.writeQueue;\n\t}\n\n\tdrainErrors(): SettingsError[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\tgetLastChangelogVersion(): string | undefined {\n\t\treturn this.settings.lastChangelogVersion;\n\t}\n\n\tsetLastChangelogVersion(version: string): void {\n\t\tthis.globalSettings.lastChangelogVersion = version;\n\t\tthis.markModified(\"lastChangelogVersion\");\n\t\tthis.save();\n\t}\n\n\tgetSessionDir(): string | undefined {\n\t\tconst sessionDir = this.settings.sessionDir;\n\t\treturn sessionDir ? normalizePath(sessionDir) : sessionDir;\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tgetSteeringMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.steeringMode || \"one-at-a-time\";\n\t}\n\n\tsetSteeringMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.steeringMode = mode;\n\t\tthis.markModified(\"steeringMode\");\n\t\tthis.save();\n\t}\n\n\tgetFollowUpMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.followUpMode || \"one-at-a-time\";\n\t}\n\n\tsetFollowUpMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.followUpMode = mode;\n\t\tthis.markModified(\"followUpMode\");\n\t\tthis.save();\n\t}\n\n\tgetTheme(): string | undefined {\n\t\treturn this.settings.theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.globalSettings.theme = theme;\n\t\tthis.markModified(\"theme\");\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\"): void {\n\t\tthis.globalSettings.defaultThinkingLevel = level;\n\t\tthis.markModified(\"defaultThinkingLevel\");\n\t\tthis.save();\n\t}\n\n\tgetTransport(): TransportSetting {\n\t\treturn this.settings.transport ?? \"auto\";\n\t}\n\n\tsetTransport(transport: TransportSetting): void {\n\t\tthis.globalSettings.transport = transport;\n\t\tthis.markModified(\"transport\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.compaction) {\n\t\t\tthis.globalSettings.compaction = {};\n\t\t}\n\t\tthis.globalSettings.compaction.enabled = enabled;\n\t\tthis.markModified(\"compaction\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionMaxUsageRatio(): number {\n\t\treturn this.settings.compaction?.maxUsageRatio ?? 0.9;\n\t}\n\n\tgetCompactionSettings(): {\n\t\tenabled: boolean;\n\t\treserveTokens: number;\n\t\tkeepRecentTokens: number;\n\t\tmaxUsageRatio: number;\n\t} {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t\tmaxUsageRatio: this.getCompactionMaxUsageRatio(),\n\t\t};\n\t}\n\n\tgetBranchSummarySettings(): { reserveTokens: number; skipPrompt: boolean } {\n\t\treturn {\n\t\t\treserveTokens: this.settings.branchSummary?.reserveTokens ?? 16384,\n\t\t\tskipPrompt: this.settings.branchSummary?.skipPrompt ?? false,\n\t\t};\n\t}\n\n\tgetBranchSummarySkipPrompt(): boolean {\n\t\treturn this.settings.branchSummary?.skipPrompt ?? false;\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.retry) {\n\t\t\tthis.globalSettings.retry = {};\n\t\t}\n\t\tthis.globalSettings.retry.enabled = enabled;\n\t\tthis.markModified(\"retry\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHttpIdleTimeoutMs(): number {\n\t\treturn parseTimeoutSetting(this.settings.httpIdleTimeoutMs, \"httpIdleTimeoutMs\") ?? DEFAULT_HTTP_IDLE_TIMEOUT_MS;\n\t}\n\n\tsetHttpIdleTimeoutMs(timeoutMs: number): void {\n\t\tif (!Number.isFinite(timeoutMs) || timeoutMs < 0) {\n\t\t\tthrow new Error(`Invalid httpIdleTimeoutMs setting: ${String(timeoutMs)}`);\n\t\t}\n\t\tthis.globalSettings.httpIdleTimeoutMs = Math.floor(timeoutMs);\n\t\tthis.markModified(\"httpIdleTimeoutMs\");\n\t\tthis.save();\n\t}\n\n\tgetProviderRetrySettings(): { timeoutMs?: number; maxRetries?: number; maxRetryDelayMs: number } {\n\t\treturn {\n\t\t\ttimeoutMs: this.settings.retry?.provider?.timeoutMs,\n\t\t\tmaxRetries: this.settings.retry?.provider?.maxRetries,\n\t\t\tmaxRetryDelayMs: this.settings.retry?.provider?.maxRetryDelayMs ?? 60000,\n\t\t};\n\t}\n\n\tgetWebSocketConnectTimeoutMs(): number | undefined {\n\t\treturn parseTimeoutSetting(this.settings.websocketConnectTimeoutMs, \"websocketConnectTimeoutMs\");\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.globalSettings.hideThinkingBlock = hide;\n\t\tthis.markModified(\"hideThinkingBlock\");\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\treturn this.settings.shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.globalSettings.shellPath = path;\n\t\tthis.markModified(\"shellPath\");\n\t\tthis.save();\n\t}\n\n\tgetQuietStartup(): boolean {\n\t\treturn this.settings.quietStartup ?? false;\n\t}\n\n\tsetQuietStartup(quiet: boolean): void {\n\t\tthis.globalSettings.quietStartup = quiet;\n\t\tthis.markModified(\"quietStartup\");\n\t\tthis.save();\n\t}\n\n\tgetShellCommandPrefix(): string | undefined {\n\t\treturn this.settings.shellCommandPrefix;\n\t}\n\n\tsetShellCommandPrefix(prefix: string | undefined): void {\n\t\tthis.globalSettings.shellCommandPrefix = prefix;\n\t\tthis.markModified(\"shellCommandPrefix\");\n\t\tthis.save();\n\t}\n\n\tgetNpmCommand(): string[] | undefined {\n\t\treturn this.settings.npmCommand ? [...this.settings.npmCommand] : undefined;\n\t}\n\n\tsetNpmCommand(command: string[] | undefined): void {\n\t\tthis.globalSettings.npmCommand = command ? [...command] : undefined;\n\t\tthis.markModified(\"npmCommand\");\n\t\tthis.save();\n\t}\n\n\tgetCollapseChangelog(): boolean {\n\t\treturn this.settings.collapseChangelog ?? false;\n\t}\n\n\tsetCollapseChangelog(collapse: boolean): void {\n\t\tthis.globalSettings.collapseChangelog = collapse;\n\t\tthis.markModified(\"collapseChangelog\");\n\t\tthis.save();\n\t}\n\n\tgetEnableInstallTelemetry(): boolean {\n\t\treturn this.settings.enableInstallTelemetry ?? true;\n\t}\n\n\tsetEnableInstallTelemetry(enabled: boolean): void {\n\t\tthis.globalSettings.enableInstallTelemetry = enabled;\n\t\tthis.markModified(\"enableInstallTelemetry\");\n\t\tthis.save();\n\t}\n\n\tgetPackages(): PackageSource[] {\n\t\treturn [...(this.settings.packages ?? [])];\n\t}\n\n\tsetPackages(packages: PackageSource[]): void {\n\t\tthis.globalSettings.packages = packages;\n\t\tthis.markModified(\"packages\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPackages(packages: PackageSource[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.packages = packages;\n\t\tthis.markProjectModified(\"packages\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetExtensionPaths(): string[] {\n\t\treturn [...(this.settings.extensions ?? [])];\n\t}\n\n\tsetExtensionPaths(paths: string[]): void {\n\t\tthis.globalSettings.extensions = paths;\n\t\tthis.markModified(\"extensions\");\n\t\tthis.save();\n\t}\n\n\tsetProjectExtensionPaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.extensions = paths;\n\t\tthis.markProjectModified(\"extensions\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetSkillPaths(): string[] {\n\t\treturn [...(this.settings.skills ?? [])];\n\t}\n\n\tsetSkillPaths(paths: string[]): void {\n\t\tthis.globalSettings.skills = paths;\n\t\tthis.markModified(\"skills\");\n\t\tthis.save();\n\t}\n\n\tsetProjectSkillPaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.skills = paths;\n\t\tthis.markProjectModified(\"skills\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetPromptTemplatePaths(): string[] {\n\t\treturn [...(this.settings.prompts ?? [])];\n\t}\n\n\tsetPromptTemplatePaths(paths: string[]): void {\n\t\tthis.globalSettings.prompts = paths;\n\t\tthis.markModified(\"prompts\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPromptTemplatePaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.prompts = paths;\n\t\tthis.markProjectModified(\"prompts\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetThemePaths(): string[] {\n\t\treturn [...(this.settings.themes ?? [])];\n\t}\n\n\tsetThemePaths(paths: string[]): void {\n\t\tthis.globalSettings.themes = paths;\n\t\tthis.markModified(\"themes\");\n\t\tthis.save();\n\t}\n\n\tsetProjectThemePaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.themes = paths;\n\t\tthis.markProjectModified(\"themes\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetEnableSkillCommands(): boolean {\n\t\treturn this.settings.enableSkillCommands ?? true;\n\t}\n\n\tsetEnableSkillCommands(enabled: boolean): void {\n\t\tthis.globalSettings.enableSkillCommands = enabled;\n\t\tthis.markModified(\"enableSkillCommands\");\n\t\tthis.save();\n\t}\n\n\tgetThinkingBudgets(): ThinkingBudgetsSettings | undefined {\n\t\treturn this.settings.thinkingBudgets;\n\t}\n\n\t/**\n\t * Reasoning-router learning opt-in (Goal 010 Lane I). Default off. Read\n\t * directly from `globalSettings`, never the merged `settings` view, so a\n\t * project-scope `.omk/settings.json` value can never turn this on.\n\t */\n\tgetReasoningRouterLearningEnabled(): boolean {\n\t\treturn this.globalSettings.reasoningRouterLearning?.enabled === true;\n\t}\n\n\t/** Global-only override path for the compiled reasoning-router bias snapshot; undefined uses the default. */\n\tgetReasoningRouterLearningBiasSnapshotPath(): string | undefined {\n\t\treturn this.globalSettings.reasoningRouterLearning?.biasSnapshotPath;\n\t}\n\n\t/** Global-only override path for the reasoning-router feedback ledger; undefined uses the default. */\n\tgetReasoningRouterLearningFeedbackLedgerPath(): string | undefined {\n\t\treturn this.globalSettings.reasoningRouterLearning?.feedbackLedgerPath;\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showImages = show;\n\t\tthis.markModified(\"terminal\", \"showImages\");\n\t\tthis.save();\n\t}\n\n\tgetImageWidthCells(): number {\n\t\tconst width = this.settings.terminal?.imageWidthCells;\n\t\tif (typeof width !== \"number\" || !Number.isFinite(width)) {\n\t\t\treturn 60;\n\t\t}\n\t\treturn Math.max(1, Math.floor(width));\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.markModified(\"terminal\", \"imageWidthCells\");\n\t\tthis.save();\n\t}\n\n\tgetClearOnShrink(): boolean {\n\t\t// Settings takes precedence, then env var, then default false\n\t\tif (this.settings.terminal?.clearOnShrink !== undefined) {\n\t\t\treturn this.settings.terminal.clearOnShrink;\n\t\t}\n\t\treturn process.env.OMK_CLEAR_ON_SHRINK === \"1\";\n\t}\n\n\tsetClearOnShrink(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.clearOnShrink = enabled;\n\t\tthis.markModified(\"terminal\", \"clearOnShrink\");\n\t\tthis.save();\n\t}\n\n\tgetShowTerminalProgress(): boolean {\n\t\treturn this.settings.terminal?.showTerminalProgress ?? false;\n\t}\n\n\tsetShowTerminalProgress(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showTerminalProgress = enabled;\n\t\tthis.markModified(\"terminal\", \"showTerminalProgress\");\n\t\tthis.save();\n\t}\n\n\tgetImageAutoResize(): boolean {\n\t\treturn this.settings.images?.autoResize ?? true;\n\t}\n\n\tsetImageAutoResize(enabled: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.autoResize = enabled;\n\t\tthis.markModified(\"images\", \"autoResize\");\n\t\tthis.save();\n\t}\n\n\tgetBlockImages(): boolean {\n\t\treturn this.settings.images?.blockImages ?? false;\n\t}\n\n\tsetBlockImages(blocked: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.blockImages = blocked;\n\t\tthis.markModified(\"images\", \"blockImages\");\n\t\tthis.save();\n\t}\n\n\tgetEnabledModels(): string[] | undefined {\n\t\treturn this.settings.enabledModels;\n\t}\n\n\tsetEnabledModels(patterns: string[] | undefined): void {\n\t\tthis.globalSettings.enabledModels = patterns;\n\t\tthis.markModified(\"enabledModels\");\n\t\tthis.save();\n\t}\n\n\tgetDoubleEscapeAction(): \"fork\" | \"tree\" | \"none\" {\n\t\treturn this.settings.doubleEscapeAction ?? \"tree\";\n\t}\n\n\tsetDoubleEscapeAction(action: \"fork\" | \"tree\" | \"none\"): void {\n\t\tthis.globalSettings.doubleEscapeAction = action;\n\t\tthis.markModified(\"doubleEscapeAction\");\n\t\tthis.save();\n\t}\n\n\tgetTreeFilterMode(): \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\" {\n\t\tconst mode = this.settings.treeFilterMode;\n\t\tconst valid = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n\t\treturn mode && valid.includes(mode) ? mode : \"default\";\n\t}\n\n\tsetTreeFilterMode(mode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"): void {\n\t\tthis.globalSettings.treeFilterMode = mode;\n\t\tthis.markModified(\"treeFilterMode\");\n\t\tthis.save();\n\t}\n\n\tgetShowHardwareCursor(): boolean {\n\t\treturn this.settings.showHardwareCursor ?? process.env.OMK_HARDWARE_CURSOR === \"1\";\n\t}\n\n\tsetShowHardwareCursor(enabled: boolean): void {\n\t\tthis.globalSettings.showHardwareCursor = enabled;\n\t\tthis.markModified(\"showHardwareCursor\");\n\t\tthis.save();\n\t}\n\n\tgetEditorPaddingX(): number {\n\t\treturn this.settings.editorPaddingX ?? 0;\n\t}\n\n\tsetEditorPaddingX(padding: number): void {\n\t\tthis.globalSettings.editorPaddingX = Math.max(0, Math.min(3, Math.floor(padding)));\n\t\tthis.markModified(\"editorPaddingX\");\n\t\tthis.save();\n\t}\n\n\tgetAutocompleteMaxVisible(): number {\n\t\treturn this.settings.autocompleteMaxVisible ?? 5;\n\t}\n\n\tsetAutocompleteMaxVisible(maxVisible: number): void {\n\t\tthis.globalSettings.autocompleteMaxVisible = Math.max(3, Math.min(20, Math.floor(maxVisible)));\n\t\tthis.markModified(\"autocompleteMaxVisible\");\n\t\tthis.save();\n\t}\n\n\tgetCodeBlockIndent(): string {\n\t\treturn this.settings.markdown?.codeBlockIndent ?? \" \";\n\t}\n\n\tgetWarnings(): WarningSettings {\n\t\treturn { ...(this.settings.warnings ?? {}) };\n\t}\n\n\tsetWarnings(warnings: WarningSettings): void {\n\t\tthis.globalSettings.warnings = { ...warnings };\n\t\tthis.markModified(\"warnings\");\n\t\tthis.save();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings-manager.d.ts","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport type { Transport } from \"omk-ai\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.ts\";\nimport { normalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from \"./http-dispatcher.ts\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n\tmaxUsageRatio?: number; // default: 0.9\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\n/**\n * Opt-in reasoning-router learning bias settings (Goal 010 Lane I). Global\n * scope only by construction: every `SettingsManager` getter for this field\n * reads directly from the raw global settings file (`globalSettings`), never\n * the merged/project-overridable view (`settings`) that most other fields\n * use -- so a project-scope `.omk/settings.json` value for any key here is\n * always ignored, never activates or redirects this feature. Default is\n * fully off; there is no project-scope setter for this field.\n */\nexport interface ReasoningRouterLearningSettings {\n\t/** default: false */\n\tenabled?: boolean;\n\t/** Override path for the compiled bias snapshot the v4 auto-router reads (see reasoning-router-bias.ts for the default). */\n\tbiasSnapshotPath?: string;\n\t/** Override path for the local feedback ledger the v4 auto-router appends to (see router-feedback-collector.ts for the default). */\n\tfeedbackLedgerPath?: string;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport interface WarningSettings {\n\tanthropicExtraUsage?: boolean; // default: true\n}\n\nexport type TransportSetting = Transport;\n\n/**\n * Package source for npm/git packages.\n * - String form: load all resources from the package\n * - Object form: filter which resources to load\n */\nexport type PackageSource =\n\t| string\n\t| {\n\t\t\tsource: string;\n\t\t\textensions?: string[];\n\t\t\tskills?: string[];\n\t\t\tprompts?: string[];\n\t\t\tthemes?: string[];\n\t };\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" | \"ultra\";\n\ttransport?: TransportSetting; // default: \"auto\"\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\tbranchSummary?: BranchSummarySettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tquietStartup?: boolean;\n\tshellCommandPrefix?: string; // Prefix prepended to every bash command (e.g., \"shopt -s expand_aliases\" for alias support)\n\tnpmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., [\"mise\", \"exec\", \"node@20\", \"--\", \"npm\"])\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\tenableInstallTelemetry?: boolean; // default: true - anonymous version/update ping after changelog-detected updates\n\tpackages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)\n\textensions?: string[]; // Array of local extension file paths or directories\n\tskills?: string[]; // Array of local skill file paths or directories\n\tprompts?: string[]; // Array of local prompt template paths or directories\n\tthemes?: string[]; // Array of local theme file paths or directories\n\tenableSkillCommands?: boolean; // default: true - register skills as /skill:name commands\n\tterminal?: TerminalSettings;\n\timages?: ImageSettings;\n\tenabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)\n\tdoubleEscapeAction?: \"fork\" | \"tree\" | \"none\"; // Action for double-escape with empty editor (default: \"tree\")\n\ttreeFilterMode?: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"; // Default filter when opening /tree\n\tthinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels\n\treasoningRouterLearning?: ReasoningRouterLearningSettings; // Opt-in v4 learning bias (default off; global-only, see SettingsManager getters)\n\teditorPaddingX?: number; // Horizontal padding for input editor (default: 0)\n\tautocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)\n\tshowHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME\n\tmarkdown?: MarkdownSettings;\n\twarnings?: WarningSettings;\n\tsessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)\n\thttpIdleTimeoutMs?: number; // HTTP header/body idle timeout in milliseconds; 0 disables it\n\twebsocketConnectTimeoutMs?: number; // WebSocket connect/open handshake timeout in milliseconds; 0 disables it\n}\n\n/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */\nfunction deepMergeSettings(base: Settings, overrides: Settings): Settings {\n\tconst result: Settings = { ...base };\n\n\tfor (const key of Object.keys(overrides) as (keyof Settings)[]) {\n\t\tconst overrideValue = overrides[key];\n\t\tconst baseValue = base[key];\n\n\t\tif (overrideValue === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// For nested objects, merge recursively\n\t\tif (\n\t\t\ttypeof overrideValue === \"object\" &&\n\t\t\toverrideValue !== null &&\n\t\t\t!Array.isArray(overrideValue) &&\n\t\t\ttypeof baseValue === \"object\" &&\n\t\t\tbaseValue !== null &&\n\t\t\t!Array.isArray(baseValue)\n\t\t) {\n\t\t\t(result as Record<string, unknown>)[key] = { ...baseValue, ...overrideValue };\n\t\t} else {\n\t\t\t// For primitives and arrays, override value wins\n\t\t\t(result as Record<string, unknown>)[key] = overrideValue;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction parseTimeoutSetting(value: unknown, settingName: string): number | undefined {\n\tconst timeoutMs = parseHttpIdleTimeoutMs(value);\n\tif (timeoutMs !== undefined) {\n\t\treturn timeoutMs;\n\t}\n\tif (value !== undefined) {\n\t\tthrow new Error(`Invalid ${settingName} setting: ${String(value)}`);\n\t}\n\treturn undefined;\n}\n\nexport type SettingsScope = \"global\" | \"project\";\n\nexport interface SettingsStorage {\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void;\n}\n\nexport interface SettingsError {\n\tscope: SettingsScope;\n\terror: Error;\n}\n\nexport class FileSettingsStorage implements SettingsStorage {\n\tprivate globalSettingsPath: string;\n\tprivate projectSettingsPath: string;\n\n\tconstructor(cwd: string, agentDir: string) {\n\t\tconst resolvedCwd = resolvePath(cwd);\n\t\tconst resolvedAgentDir = resolvePath(agentDir);\n\t\tthis.globalSettingsPath = join(resolvedAgentDir, \"settings.json\");\n\t\tthis.projectSettingsPath = join(resolvedCwd, CONFIG_DIR_NAME, \"settings.json\");\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire settings lock\");\n\t}\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst path = scope === \"global\" ? this.globalSettingsPath : this.projectSettingsPath;\n\t\tconst dir = dirname(path);\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\t// Only create directory and lock if file exists or we need to write\n\t\t\tconst fileExists = existsSync(path);\n\t\t\tif (fileExists) {\n\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t}\n\t\t\tconst current = fileExists ? readFileSync(path, \"utf-8\") : undefined;\n\t\t\tconst next = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\t// Only create directory when we actually need to write\n\t\t\t\tif (!existsSync(dir)) {\n\t\t\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\t\t}\n\t\t\t\tif (!release) {\n\t\t\t\t\trelease = this.acquireLockSyncWithRetry(path);\n\t\t\t\t}\n\t\t\t\twriteFileSync(path, next, \"utf-8\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemorySettingsStorage implements SettingsStorage {\n\tprivate global: string | undefined;\n\tprivate project: string | undefined;\n\n\twithLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void {\n\t\tconst current = scope === \"global\" ? this.global : this.project;\n\t\tconst next = fn(current);\n\t\tif (next !== undefined) {\n\t\t\tif (scope === \"global\") {\n\t\t\t\tthis.global = next;\n\t\t\t} else {\n\t\t\t\tthis.project = next;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class SettingsManager {\n\tprivate storage: SettingsStorage;\n\tprivate globalSettings: Settings;\n\tprivate projectSettings: Settings;\n\tprivate settings: Settings;\n\tprivate modifiedFields = new Set<keyof Settings>(); // Track global fields modified during session\n\tprivate modifiedNestedFields = new Map<keyof Settings, Set<string>>(); // Track global nested field modifications\n\tprivate modifiedProjectFields = new Set<keyof Settings>(); // Track project fields modified during session\n\tprivate modifiedProjectNestedFields = new Map<keyof Settings, Set<string>>(); // Track project nested field modifications\n\tprivate globalSettingsLoadError: Error | null = null; // Track if global settings file had parse errors\n\tprivate projectSettingsLoadError: Error | null = null; // Track if project settings file had parse errors\n\tprivate writeQueue: Promise<void> = Promise.resolve();\n\tprivate errors: SettingsError[];\n\n\tprivate constructor(\n\t\tstorage: SettingsStorage,\n\t\tinitialGlobal: Settings,\n\t\tinitialProject: Settings,\n\t\tglobalLoadError: Error | null = null,\n\t\tprojectLoadError: Error | null = null,\n\t\tinitialErrors: SettingsError[] = [],\n\t) {\n\t\tthis.storage = storage;\n\t\tthis.globalSettings = initialGlobal;\n\t\tthis.projectSettings = initialProject;\n\t\tthis.globalSettingsLoadError = globalLoadError;\n\t\tthis.projectSettingsLoadError = projectLoadError;\n\t\tthis.errors = [...initialErrors];\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Create a SettingsManager that loads from files */\n\tstatic create(cwd: string, agentDir: string = getAgentDir()): SettingsManager {\n\t\tconst storage = new FileSettingsStorage(cwd, agentDir);\n\t\treturn SettingsManager.fromStorage(storage);\n\t}\n\n\t/** Create a SettingsManager from an arbitrary storage backend */\n\tstatic fromStorage(storage: SettingsStorage): SettingsManager {\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(storage, \"global\");\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(storage, \"project\");\n\t\tconst initialErrors: SettingsError[] = [];\n\t\tif (globalLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"global\", error: globalLoad.error });\n\t\t}\n\t\tif (projectLoad.error) {\n\t\t\tinitialErrors.push({ scope: \"project\", error: projectLoad.error });\n\t\t}\n\n\t\treturn new SettingsManager(\n\t\t\tstorage,\n\t\t\tglobalLoad.settings,\n\t\t\tprojectLoad.settings,\n\t\t\tglobalLoad.error,\n\t\t\tprojectLoad.error,\n\t\t\tinitialErrors,\n\t\t);\n\t}\n\n\t/** Create an in-memory SettingsManager (no file I/O) */\n\tstatic inMemory(settings: Partial<Settings> = {}): SettingsManager {\n\t\tconst storage = new InMemorySettingsStorage();\n\t\tconst initialSettings = SettingsManager.migrateSettings(structuredClone(settings) as Record<string, unknown>);\n\t\tstorage.withLock(\"global\", () => JSON.stringify(initialSettings, null, 2));\n\t\treturn SettingsManager.fromStorage(storage);\n\t}\n\n\tprivate static loadFromStorage(storage: SettingsStorage, scope: SettingsScope): Settings {\n\t\tlet content: string | undefined;\n\t\tstorage.withLock(scope, (current) => {\n\t\t\tcontent = current;\n\t\t\treturn undefined;\n\t\t});\n\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\tconst settings = JSON.parse(content);\n\t\treturn SettingsManager.migrateSettings(settings);\n\t}\n\n\tprivate static tryLoadFromStorage(\n\t\tstorage: SettingsStorage,\n\t\tscope: SettingsScope,\n\t): { settings: Settings; error: Error | null } {\n\t\ttry {\n\t\t\treturn { settings: SettingsManager.loadFromStorage(storage, scope), error: null };\n\t\t} catch (error) {\n\t\t\treturn { settings: {}, error: error as Error };\n\t\t}\n\t}\n\n\t/** Migrate old settings format to new format */\n\tprivate static migrateSettings(settings: Record<string, unknown>): Settings {\n\t\t// Migrate queueMode -> steeringMode\n\t\tif (\"queueMode\" in settings && !(\"steeringMode\" in settings)) {\n\t\t\tsettings.steeringMode = settings.queueMode;\n\t\t\tdelete settings.queueMode;\n\t\t}\n\n\t\t// Migrate legacy websockets boolean -> transport enum\n\t\tif (!(\"transport\" in settings) && typeof settings.websockets === \"boolean\") {\n\t\t\tsettings.transport = settings.websockets ? \"websocket\" : \"sse\";\n\t\t\tdelete settings.websockets;\n\t\t}\n\n\t\t// Migrate old skills object format to new array format\n\t\tif (\n\t\t\t\"skills\" in settings &&\n\t\t\ttypeof settings.skills === \"object\" &&\n\t\t\tsettings.skills !== null &&\n\t\t\t!Array.isArray(settings.skills)\n\t\t) {\n\t\t\tconst skillsSettings = settings.skills as {\n\t\t\t\tenableSkillCommands?: boolean;\n\t\t\t\tcustomDirectories?: unknown;\n\t\t\t};\n\t\t\tif (skillsSettings.enableSkillCommands !== undefined && settings.enableSkillCommands === undefined) {\n\t\t\t\tsettings.enableSkillCommands = skillsSettings.enableSkillCommands;\n\t\t\t}\n\t\t\tif (Array.isArray(skillsSettings.customDirectories) && skillsSettings.customDirectories.length > 0) {\n\t\t\t\tsettings.skills = skillsSettings.customDirectories;\n\t\t\t} else {\n\t\t\t\tdelete settings.skills;\n\t\t\t}\n\t\t}\n\n\t\t// Migrate retry.maxDelayMs -> retry.provider.maxRetryDelayMs\n\t\tif (\n\t\t\t\"retry\" in settings &&\n\t\t\ttypeof settings.retry === \"object\" &&\n\t\t\tsettings.retry !== null &&\n\t\t\t!Array.isArray(settings.retry)\n\t\t) {\n\t\t\tconst retrySettings = settings.retry as Record<string, unknown>;\n\t\t\tconst providerSettings =\n\t\t\t\ttypeof retrySettings.provider === \"object\" && retrySettings.provider !== null\n\t\t\t\t\t? (retrySettings.provider as Record<string, unknown>)\n\t\t\t\t\t: undefined;\n\t\t\tif (\n\t\t\t\ttypeof retrySettings.maxDelayMs === \"number\" &&\n\t\t\t\t(providerSettings?.maxRetryDelayMs === undefined || providerSettings?.maxRetryDelayMs === null)\n\t\t\t) {\n\t\t\t\tretrySettings.provider = {\n\t\t\t\t\t...(providerSettings ?? {}),\n\t\t\t\t\tmaxRetryDelayMs: retrySettings.maxDelayMs,\n\t\t\t\t};\n\t\t\t}\n\t\t\tdelete retrySettings.maxDelayMs;\n\t\t}\n\n\t\treturn settings as Settings;\n\t}\n\n\tgetGlobalSettings(): Settings {\n\t\treturn structuredClone(this.globalSettings);\n\t}\n\n\tgetProjectSettings(): Settings {\n\t\treturn structuredClone(this.projectSettings);\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait this.writeQueue;\n\t\tconst globalLoad = SettingsManager.tryLoadFromStorage(this.storage, \"global\");\n\t\tif (!globalLoad.error) {\n\t\t\tthis.globalSettings = globalLoad.settings;\n\t\t\tthis.globalSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.globalSettingsLoadError = globalLoad.error;\n\t\t\tthis.recordError(\"global\", globalLoad.error);\n\t\t}\n\n\t\tthis.modifiedFields.clear();\n\t\tthis.modifiedNestedFields.clear();\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\n\t\tconst projectLoad = SettingsManager.tryLoadFromStorage(this.storage, \"project\");\n\t\tif (!projectLoad.error) {\n\t\t\tthis.projectSettings = projectLoad.settings;\n\t\t\tthis.projectSettingsLoadError = null;\n\t\t} else {\n\t\t\tthis.projectSettingsLoadError = projectLoad.error;\n\t\t\tthis.recordError(\"project\", projectLoad.error);\n\t\t}\n\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\t}\n\n\t/** Apply additional overrides on top of current settings */\n\tapplyOverrides(overrides: Partial<Settings>): void {\n\t\tthis.settings = deepMergeSettings(this.settings, overrides);\n\t}\n\n\t/** Mark a global field as modified during this session */\n\tprivate markModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedNestedFields.has(field)) {\n\t\t\t\tthis.modifiedNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\t/** Mark a project field as modified during this session */\n\tprivate markProjectModified(field: keyof Settings, nestedKey?: string): void {\n\t\tthis.modifiedProjectFields.add(field);\n\t\tif (nestedKey) {\n\t\t\tif (!this.modifiedProjectNestedFields.has(field)) {\n\t\t\t\tthis.modifiedProjectNestedFields.set(field, new Set());\n\t\t\t}\n\t\t\tthis.modifiedProjectNestedFields.get(field)!.add(nestedKey);\n\t\t}\n\t}\n\n\tprivate recordError(scope: SettingsScope, error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push({ scope, error: normalizedError });\n\t}\n\n\tprivate clearModifiedScope(scope: SettingsScope): void {\n\t\tif (scope === \"global\") {\n\t\t\tthis.modifiedFields.clear();\n\t\t\tthis.modifiedNestedFields.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.modifiedProjectFields.clear();\n\t\tthis.modifiedProjectNestedFields.clear();\n\t}\n\n\tprivate enqueueWrite(scope: SettingsScope, task: () => void): void {\n\t\tthis.writeQueue = this.writeQueue\n\t\t\t.then(() => {\n\t\t\t\ttask();\n\t\t\t\tthis.clearModifiedScope(scope);\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.recordError(scope, error);\n\t\t\t});\n\t}\n\n\tprivate cloneModifiedNestedFields(source: Map<keyof Settings, Set<string>>): Map<keyof Settings, Set<string>> {\n\t\tconst snapshot = new Map<keyof Settings, Set<string>>();\n\t\tfor (const [key, value] of source.entries()) {\n\t\t\tsnapshot.set(key, new Set(value));\n\t\t}\n\t\treturn snapshot;\n\t}\n\n\tprivate persistScopedSettings(\n\t\tscope: SettingsScope,\n\t\tsnapshotSettings: Settings,\n\t\tmodifiedFields: Set<keyof Settings>,\n\t\tmodifiedNestedFields: Map<keyof Settings, Set<string>>,\n\t): void {\n\t\tthis.storage.withLock(scope, (current) => {\n\t\t\tconst currentFileSettings = current\n\t\t\t\t? SettingsManager.migrateSettings(JSON.parse(current) as Record<string, unknown>)\n\t\t\t\t: {};\n\t\t\tconst mergedSettings: Settings = { ...currentFileSettings };\n\t\t\tfor (const field of modifiedFields) {\n\t\t\t\tconst value = snapshotSettings[field];\n\t\t\t\tif (modifiedNestedFields.has(field) && typeof value === \"object\" && value !== null) {\n\t\t\t\t\tconst nestedModified = modifiedNestedFields.get(field)!;\n\t\t\t\t\tconst baseNested = (currentFileSettings[field] as Record<string, unknown>) ?? {};\n\t\t\t\t\tconst inMemoryNested = value as Record<string, unknown>;\n\t\t\t\t\tconst mergedNested = { ...baseNested };\n\t\t\t\t\tfor (const nestedKey of nestedModified) {\n\t\t\t\t\t\tmergedNested[nestedKey] = inMemoryNested[nestedKey];\n\t\t\t\t\t}\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = mergedNested;\n\t\t\t\t} else {\n\t\t\t\t\t(mergedSettings as Record<string, unknown>)[field] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn JSON.stringify(mergedSettings, null, 2);\n\t\t});\n\t}\n\n\tprivate save(): void {\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.globalSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotGlobalSettings = structuredClone(this.globalSettings);\n\t\tconst modifiedFields = new Set(this.modifiedFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedNestedFields);\n\n\t\tthis.enqueueWrite(\"global\", () => {\n\t\t\tthis.persistScopedSettings(\"global\", snapshotGlobalSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tprivate saveProjectSettings(settings: Settings): void {\n\t\tthis.projectSettings = structuredClone(settings);\n\t\tthis.settings = deepMergeSettings(this.globalSettings, this.projectSettings);\n\n\t\tif (this.projectSettingsLoadError) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst snapshotProjectSettings = structuredClone(this.projectSettings);\n\t\tconst modifiedFields = new Set(this.modifiedProjectFields);\n\t\tconst modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);\n\t\tthis.enqueueWrite(\"project\", () => {\n\t\t\tthis.persistScopedSettings(\"project\", snapshotProjectSettings, modifiedFields, modifiedNestedFields);\n\t\t});\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.writeQueue;\n\t}\n\n\tdrainErrors(): SettingsError[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\tgetLastChangelogVersion(): string | undefined {\n\t\treturn this.settings.lastChangelogVersion;\n\t}\n\n\tsetLastChangelogVersion(version: string): void {\n\t\tthis.globalSettings.lastChangelogVersion = version;\n\t\tthis.markModified(\"lastChangelogVersion\");\n\t\tthis.save();\n\t}\n\n\tgetSessionDir(): string | undefined {\n\t\tconst sessionDir = this.settings.sessionDir;\n\t\treturn sessionDir ? normalizePath(sessionDir) : sessionDir;\n\t}\n\n\tgetDefaultProvider(): string | undefined {\n\t\treturn this.settings.defaultProvider;\n\t}\n\n\tgetDefaultModel(): string | undefined {\n\t\treturn this.settings.defaultModel;\n\t}\n\n\tsetDefaultProvider(provider: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModel(modelId: string): void {\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tsetDefaultModelAndProvider(provider: string, modelId: string): void {\n\t\tthis.globalSettings.defaultProvider = provider;\n\t\tthis.globalSettings.defaultModel = modelId;\n\t\tthis.markModified(\"defaultProvider\");\n\t\tthis.markModified(\"defaultModel\");\n\t\tthis.save();\n\t}\n\n\tgetSteeringMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.steeringMode || \"one-at-a-time\";\n\t}\n\n\tsetSteeringMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.steeringMode = mode;\n\t\tthis.markModified(\"steeringMode\");\n\t\tthis.save();\n\t}\n\n\tgetFollowUpMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.settings.followUpMode || \"one-at-a-time\";\n\t}\n\n\tsetFollowUpMode(mode: \"all\" | \"one-at-a-time\"): void {\n\t\tthis.globalSettings.followUpMode = mode;\n\t\tthis.markModified(\"followUpMode\");\n\t\tthis.save();\n\t}\n\n\tgetTheme(): string | undefined {\n\t\treturn this.settings.theme;\n\t}\n\n\tsetTheme(theme: string): void {\n\t\tthis.globalSettings.theme = theme;\n\t\tthis.markModified(\"theme\");\n\t\tthis.save();\n\t}\n\n\tgetDefaultThinkingLevel(): \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" | \"ultra\" | undefined {\n\t\treturn this.settings.defaultThinkingLevel;\n\t}\n\n\tsetDefaultThinkingLevel(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" | \"ultra\"): void {\n\t\tthis.globalSettings.defaultThinkingLevel = level;\n\t\tthis.markModified(\"defaultThinkingLevel\");\n\t\tthis.save();\n\t}\n\n\tgetTransport(): TransportSetting {\n\t\treturn this.settings.transport ?? \"auto\";\n\t}\n\n\tsetTransport(transport: TransportSetting): void {\n\t\tthis.globalSettings.transport = transport;\n\t\tthis.markModified(\"transport\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionEnabled(): boolean {\n\t\treturn this.settings.compaction?.enabled ?? true;\n\t}\n\n\tsetCompactionEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.compaction) {\n\t\t\tthis.globalSettings.compaction = {};\n\t\t}\n\t\tthis.globalSettings.compaction.enabled = enabled;\n\t\tthis.markModified(\"compaction\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetCompactionReserveTokens(): number {\n\t\treturn this.settings.compaction?.reserveTokens ?? 16384;\n\t}\n\n\tgetCompactionKeepRecentTokens(): number {\n\t\treturn this.settings.compaction?.keepRecentTokens ?? 20000;\n\t}\n\n\tgetCompactionMaxUsageRatio(): number {\n\t\treturn this.settings.compaction?.maxUsageRatio ?? 0.9;\n\t}\n\n\tgetCompactionSettings(): {\n\t\tenabled: boolean;\n\t\treserveTokens: number;\n\t\tkeepRecentTokens: number;\n\t\tmaxUsageRatio: number;\n\t} {\n\t\treturn {\n\t\t\tenabled: this.getCompactionEnabled(),\n\t\t\treserveTokens: this.getCompactionReserveTokens(),\n\t\t\tkeepRecentTokens: this.getCompactionKeepRecentTokens(),\n\t\t\tmaxUsageRatio: this.getCompactionMaxUsageRatio(),\n\t\t};\n\t}\n\n\tgetBranchSummarySettings(): { reserveTokens: number; skipPrompt: boolean } {\n\t\treturn {\n\t\t\treserveTokens: this.settings.branchSummary?.reserveTokens ?? 16384,\n\t\t\tskipPrompt: this.settings.branchSummary?.skipPrompt ?? false,\n\t\t};\n\t}\n\n\tgetBranchSummarySkipPrompt(): boolean {\n\t\treturn this.settings.branchSummary?.skipPrompt ?? false;\n\t}\n\n\tgetRetryEnabled(): boolean {\n\t\treturn this.settings.retry?.enabled ?? true;\n\t}\n\n\tsetRetryEnabled(enabled: boolean): void {\n\t\tif (!this.globalSettings.retry) {\n\t\t\tthis.globalSettings.retry = {};\n\t\t}\n\t\tthis.globalSettings.retry.enabled = enabled;\n\t\tthis.markModified(\"retry\", \"enabled\");\n\t\tthis.save();\n\t}\n\n\tgetRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {\n\t\treturn {\n\t\t\tenabled: this.getRetryEnabled(),\n\t\t\tmaxRetries: this.settings.retry?.maxRetries ?? 3,\n\t\t\tbaseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,\n\t\t};\n\t}\n\n\tgetHttpIdleTimeoutMs(): number {\n\t\treturn parseTimeoutSetting(this.settings.httpIdleTimeoutMs, \"httpIdleTimeoutMs\") ?? DEFAULT_HTTP_IDLE_TIMEOUT_MS;\n\t}\n\n\tsetHttpIdleTimeoutMs(timeoutMs: number): void {\n\t\tif (!Number.isFinite(timeoutMs) || timeoutMs < 0) {\n\t\t\tthrow new Error(`Invalid httpIdleTimeoutMs setting: ${String(timeoutMs)}`);\n\t\t}\n\t\tthis.globalSettings.httpIdleTimeoutMs = Math.floor(timeoutMs);\n\t\tthis.markModified(\"httpIdleTimeoutMs\");\n\t\tthis.save();\n\t}\n\n\tgetProviderRetrySettings(): { timeoutMs?: number; maxRetries?: number; maxRetryDelayMs: number } {\n\t\treturn {\n\t\t\ttimeoutMs: this.settings.retry?.provider?.timeoutMs,\n\t\t\tmaxRetries: this.settings.retry?.provider?.maxRetries,\n\t\t\tmaxRetryDelayMs: this.settings.retry?.provider?.maxRetryDelayMs ?? 60000,\n\t\t};\n\t}\n\n\tgetWebSocketConnectTimeoutMs(): number | undefined {\n\t\treturn parseTimeoutSetting(this.settings.websocketConnectTimeoutMs, \"websocketConnectTimeoutMs\");\n\t}\n\n\tgetHideThinkingBlock(): boolean {\n\t\treturn this.settings.hideThinkingBlock ?? false;\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.globalSettings.hideThinkingBlock = hide;\n\t\tthis.markModified(\"hideThinkingBlock\");\n\t\tthis.save();\n\t}\n\n\tgetShellPath(): string | undefined {\n\t\treturn this.settings.shellPath;\n\t}\n\n\tsetShellPath(path: string | undefined): void {\n\t\tthis.globalSettings.shellPath = path;\n\t\tthis.markModified(\"shellPath\");\n\t\tthis.save();\n\t}\n\n\tgetQuietStartup(): boolean {\n\t\treturn this.settings.quietStartup ?? false;\n\t}\n\n\tsetQuietStartup(quiet: boolean): void {\n\t\tthis.globalSettings.quietStartup = quiet;\n\t\tthis.markModified(\"quietStartup\");\n\t\tthis.save();\n\t}\n\n\tgetShellCommandPrefix(): string | undefined {\n\t\treturn this.settings.shellCommandPrefix;\n\t}\n\n\tsetShellCommandPrefix(prefix: string | undefined): void {\n\t\tthis.globalSettings.shellCommandPrefix = prefix;\n\t\tthis.markModified(\"shellCommandPrefix\");\n\t\tthis.save();\n\t}\n\n\tgetNpmCommand(): string[] | undefined {\n\t\treturn this.settings.npmCommand ? [...this.settings.npmCommand] : undefined;\n\t}\n\n\tsetNpmCommand(command: string[] | undefined): void {\n\t\tthis.globalSettings.npmCommand = command ? [...command] : undefined;\n\t\tthis.markModified(\"npmCommand\");\n\t\tthis.save();\n\t}\n\n\tgetCollapseChangelog(): boolean {\n\t\treturn this.settings.collapseChangelog ?? false;\n\t}\n\n\tsetCollapseChangelog(collapse: boolean): void {\n\t\tthis.globalSettings.collapseChangelog = collapse;\n\t\tthis.markModified(\"collapseChangelog\");\n\t\tthis.save();\n\t}\n\n\tgetEnableInstallTelemetry(): boolean {\n\t\treturn this.settings.enableInstallTelemetry ?? true;\n\t}\n\n\tsetEnableInstallTelemetry(enabled: boolean): void {\n\t\tthis.globalSettings.enableInstallTelemetry = enabled;\n\t\tthis.markModified(\"enableInstallTelemetry\");\n\t\tthis.save();\n\t}\n\n\tgetPackages(): PackageSource[] {\n\t\treturn [...(this.settings.packages ?? [])];\n\t}\n\n\tsetPackages(packages: PackageSource[]): void {\n\t\tthis.globalSettings.packages = packages;\n\t\tthis.markModified(\"packages\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPackages(packages: PackageSource[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.packages = packages;\n\t\tthis.markProjectModified(\"packages\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetExtensionPaths(): string[] {\n\t\treturn [...(this.settings.extensions ?? [])];\n\t}\n\n\tsetExtensionPaths(paths: string[]): void {\n\t\tthis.globalSettings.extensions = paths;\n\t\tthis.markModified(\"extensions\");\n\t\tthis.save();\n\t}\n\n\tsetProjectExtensionPaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.extensions = paths;\n\t\tthis.markProjectModified(\"extensions\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetSkillPaths(): string[] {\n\t\treturn [...(this.settings.skills ?? [])];\n\t}\n\n\tsetSkillPaths(paths: string[]): void {\n\t\tthis.globalSettings.skills = paths;\n\t\tthis.markModified(\"skills\");\n\t\tthis.save();\n\t}\n\n\tsetProjectSkillPaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.skills = paths;\n\t\tthis.markProjectModified(\"skills\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetPromptTemplatePaths(): string[] {\n\t\treturn [...(this.settings.prompts ?? [])];\n\t}\n\n\tsetPromptTemplatePaths(paths: string[]): void {\n\t\tthis.globalSettings.prompts = paths;\n\t\tthis.markModified(\"prompts\");\n\t\tthis.save();\n\t}\n\n\tsetProjectPromptTemplatePaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.prompts = paths;\n\t\tthis.markProjectModified(\"prompts\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetThemePaths(): string[] {\n\t\treturn [...(this.settings.themes ?? [])];\n\t}\n\n\tsetThemePaths(paths: string[]): void {\n\t\tthis.globalSettings.themes = paths;\n\t\tthis.markModified(\"themes\");\n\t\tthis.save();\n\t}\n\n\tsetProjectThemePaths(paths: string[]): void {\n\t\tconst projectSettings = structuredClone(this.projectSettings);\n\t\tprojectSettings.themes = paths;\n\t\tthis.markProjectModified(\"themes\");\n\t\tthis.saveProjectSettings(projectSettings);\n\t}\n\n\tgetEnableSkillCommands(): boolean {\n\t\treturn this.settings.enableSkillCommands ?? true;\n\t}\n\n\tsetEnableSkillCommands(enabled: boolean): void {\n\t\tthis.globalSettings.enableSkillCommands = enabled;\n\t\tthis.markModified(\"enableSkillCommands\");\n\t\tthis.save();\n\t}\n\n\tgetThinkingBudgets(): ThinkingBudgetsSettings | undefined {\n\t\treturn this.settings.thinkingBudgets;\n\t}\n\n\t/**\n\t * Reasoning-router learning opt-in (Goal 010 Lane I). Default off. Read\n\t * directly from `globalSettings`, never the merged `settings` view, so a\n\t * project-scope `.omk/settings.json` value can never turn this on.\n\t */\n\tgetReasoningRouterLearningEnabled(): boolean {\n\t\treturn this.globalSettings.reasoningRouterLearning?.enabled === true;\n\t}\n\n\t/** Global-only override path for the compiled reasoning-router bias snapshot; undefined uses the default. */\n\tgetReasoningRouterLearningBiasSnapshotPath(): string | undefined {\n\t\treturn this.globalSettings.reasoningRouterLearning?.biasSnapshotPath;\n\t}\n\n\t/** Global-only override path for the reasoning-router feedback ledger; undefined uses the default. */\n\tgetReasoningRouterLearningFeedbackLedgerPath(): string | undefined {\n\t\treturn this.globalSettings.reasoningRouterLearning?.feedbackLedgerPath;\n\t}\n\n\tgetShowImages(): boolean {\n\t\treturn this.settings.terminal?.showImages ?? true;\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showImages = show;\n\t\tthis.markModified(\"terminal\", \"showImages\");\n\t\tthis.save();\n\t}\n\n\tgetImageWidthCells(): number {\n\t\tconst width = this.settings.terminal?.imageWidthCells;\n\t\tif (typeof width !== \"number\" || !Number.isFinite(width)) {\n\t\t\treturn 60;\n\t\t}\n\t\treturn Math.max(1, Math.floor(width));\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.markModified(\"terminal\", \"imageWidthCells\");\n\t\tthis.save();\n\t}\n\n\tgetClearOnShrink(): boolean {\n\t\t// Settings takes precedence, then env var, then default false\n\t\tif (this.settings.terminal?.clearOnShrink !== undefined) {\n\t\t\treturn this.settings.terminal.clearOnShrink;\n\t\t}\n\t\treturn process.env.OMK_CLEAR_ON_SHRINK === \"1\";\n\t}\n\n\tsetClearOnShrink(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.clearOnShrink = enabled;\n\t\tthis.markModified(\"terminal\", \"clearOnShrink\");\n\t\tthis.save();\n\t}\n\n\tgetShowTerminalProgress(): boolean {\n\t\treturn this.settings.terminal?.showTerminalProgress ?? false;\n\t}\n\n\tsetShowTerminalProgress(enabled: boolean): void {\n\t\tif (!this.globalSettings.terminal) {\n\t\t\tthis.globalSettings.terminal = {};\n\t\t}\n\t\tthis.globalSettings.terminal.showTerminalProgress = enabled;\n\t\tthis.markModified(\"terminal\", \"showTerminalProgress\");\n\t\tthis.save();\n\t}\n\n\tgetImageAutoResize(): boolean {\n\t\treturn this.settings.images?.autoResize ?? true;\n\t}\n\n\tsetImageAutoResize(enabled: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.autoResize = enabled;\n\t\tthis.markModified(\"images\", \"autoResize\");\n\t\tthis.save();\n\t}\n\n\tgetBlockImages(): boolean {\n\t\treturn this.settings.images?.blockImages ?? false;\n\t}\n\n\tsetBlockImages(blocked: boolean): void {\n\t\tif (!this.globalSettings.images) {\n\t\t\tthis.globalSettings.images = {};\n\t\t}\n\t\tthis.globalSettings.images.blockImages = blocked;\n\t\tthis.markModified(\"images\", \"blockImages\");\n\t\tthis.save();\n\t}\n\n\tgetEnabledModels(): string[] | undefined {\n\t\treturn this.settings.enabledModels;\n\t}\n\n\tsetEnabledModels(patterns: string[] | undefined): void {\n\t\tthis.globalSettings.enabledModels = patterns;\n\t\tthis.markModified(\"enabledModels\");\n\t\tthis.save();\n\t}\n\n\tgetDoubleEscapeAction(): \"fork\" | \"tree\" | \"none\" {\n\t\treturn this.settings.doubleEscapeAction ?? \"tree\";\n\t}\n\n\tsetDoubleEscapeAction(action: \"fork\" | \"tree\" | \"none\"): void {\n\t\tthis.globalSettings.doubleEscapeAction = action;\n\t\tthis.markModified(\"doubleEscapeAction\");\n\t\tthis.save();\n\t}\n\n\tgetTreeFilterMode(): \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\" {\n\t\tconst mode = this.settings.treeFilterMode;\n\t\tconst valid = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n\t\treturn mode && valid.includes(mode) ? mode : \"default\";\n\t}\n\n\tsetTreeFilterMode(mode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"): void {\n\t\tthis.globalSettings.treeFilterMode = mode;\n\t\tthis.markModified(\"treeFilterMode\");\n\t\tthis.save();\n\t}\n\n\tgetShowHardwareCursor(): boolean {\n\t\treturn this.settings.showHardwareCursor ?? process.env.OMK_HARDWARE_CURSOR === \"1\";\n\t}\n\n\tsetShowHardwareCursor(enabled: boolean): void {\n\t\tthis.globalSettings.showHardwareCursor = enabled;\n\t\tthis.markModified(\"showHardwareCursor\");\n\t\tthis.save();\n\t}\n\n\tgetEditorPaddingX(): number {\n\t\treturn this.settings.editorPaddingX ?? 0;\n\t}\n\n\tsetEditorPaddingX(padding: number): void {\n\t\tthis.globalSettings.editorPaddingX = Math.max(0, Math.min(3, Math.floor(padding)));\n\t\tthis.markModified(\"editorPaddingX\");\n\t\tthis.save();\n\t}\n\n\tgetAutocompleteMaxVisible(): number {\n\t\treturn this.settings.autocompleteMaxVisible ?? 5;\n\t}\n\n\tsetAutocompleteMaxVisible(maxVisible: number): void {\n\t\tthis.globalSettings.autocompleteMaxVisible = Math.max(3, Math.min(20, Math.floor(maxVisible)));\n\t\tthis.markModified(\"autocompleteMaxVisible\");\n\t\tthis.save();\n\t}\n\n\tgetCodeBlockIndent(): string {\n\t\treturn this.settings.markdown?.codeBlockIndent ?? \" \";\n\t}\n\n\tgetWarnings(): WarningSettings {\n\t\treturn { ...(this.settings.warnings ?? {}) };\n\t}\n\n\tsetWarnings(warnings: WarningSettings): void {\n\t\tthis.globalSettings.warnings = { ...warnings };\n\t\tthis.markModified(\"warnings\");\n\t\tthis.save();\n\t}\n}\n"]}
|