/**
 * Settings manager — two-tier (global + project) JSON settings with file locking.
 *
 * Global settings live at ~/.shortcut/agent/settings.json.
 * Project settings live at <cwd>/.shortcut/settings.json and override globals.
 * Both are deep-merged at read time; writes go to the appropriate scope.
 *
 * Tracks which fields were modified in-session so saves only touch those
 * keys, preserving hand-edits in unrelated parts of the file.
 */
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import { homedir } from 'os';
import { dirname, join } from 'path';
import { CONFIG_DIR_NAME, DEFAULT_SANDBOX_NETWORK, getAgentDir } from '../config.js';
import { lockSyncWithRetries } from '../shared/files/lock-utils.js';
import { addPermissioningFilesystemApproval, createDefaultRuntimePermissioningSettings, getDangerouslySkipRuntimePermissionsFromPermissioning, getWorkspaceRootsFromPermissioning, mergeRuntimePermissioningSettings, migrateRuntimePermissioningSettings, removePermissioningFilesystemApproval, setPermissioningDangerouslySkipRuntimePermissions, setPermissioningSpreadsheetAutoApproveDefault, setPermissioningWorkspaceRoots } from './permissions/settings.js';
/** Display labels for the approval mode (footer + /settings). */
export const APPROVAL_MODE = {
    ASK: 'Ask before spreadsheet changes',
    AUTO: 'Auto-approve spreadsheet changes'
};
/** Concrete sandbox defaults — always called at runtime so paths resolve correctly. */
export function getDefaultSandboxSettings() {
    return {
        mode: 'disabled',
        readPaths: [homedir()],
        writePaths: [homedir(), getAgentDir()],
        network: DEFAULT_SANDBOX_NETWORK,
        allowedDomains: [
            // Package registries
            '*.pypi.org',
            '*.pythonhosted.org',
            'registry.npmjs.org',
            // GitHub (clone, API, releases)
            '*.github.com',
            '*.githubusercontent.com'
        ]
    };
}
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
function deepMergeSettings(base, overrides) {
    const result = { ...base };
    for (const key of Object.keys(overrides)) {
        const overrideValue = overrides[key];
        const baseValue = base[key];
        if (overrideValue === undefined) {
            continue;
        }
        // For nested objects, merge recursively
        if (typeof overrideValue === 'object' &&
            overrideValue !== null &&
            !Array.isArray(overrideValue) &&
            typeof baseValue === 'object' &&
            baseValue !== null &&
            !Array.isArray(baseValue)) {
            result[key] = { ...baseValue, ...overrideValue };
        }
        else {
            // For primitives and arrays, override value wins
            result[key] = overrideValue;
        }
    }
    result.permissioning =
        mergeRuntimePermissioningSettings(base.permissioning, overrides.permissioning) ??
            result.permissioning;
    return result;
}
function dedupeStrings(values) {
    return [...new Set(values)];
}
function dedupeFilesystemApprovals(approvals) {
    const seen = new Set();
    const unique = [];
    for (const approval of approvals) {
        const key = `${approval.path}\u0000${approval.access}\u0000${approval.scope}`;
        if (seen.has(key)) {
            continue;
        }
        seen.add(key);
        unique.push(approval);
    }
    return unique;
}
function mergePermissioningIntoGlobal(globalPermissioning, projectPermissioning) {
    const merged = mergeRuntimePermissioningSettings(createDefaultRuntimePermissioningSettings(), globalPermissioning) ?? createDefaultRuntimePermissioningSettings();
    if (!projectPermissioning) {
        return merged;
    }
    return {
        ...merged,
        filesystem: {
            ...(merged.filesystem ?? {}),
            workspaceRoots: dedupeStrings([
                ...(merged.filesystem?.workspaceRoots ?? []),
                ...(projectPermissioning.filesystem?.workspaceRoots ?? [])
            ]),
            persistentApprovals: dedupeFilesystemApprovals([
                ...(merged.filesystem?.persistentApprovals ?? []),
                ...(projectPermissioning.filesystem?.persistentApprovals ?? [])
            ])
        },
        spreadsheet: {
            ...(merged.spreadsheet ?? {}),
            autoApproveDefault: merged.spreadsheet?.autoApproveDefault ??
                projectPermissioning.spreadsheet?.autoApproveDefault ??
                false
        },
        shell: {
            ...(merged.shell ?? {}),
            ...(projectPermissioning.shell ?? {})
        },
        subagents: {
            ...(merged.subagents ?? {}),
            ...(projectPermissioning.subagents ?? {})
        }
    };
}
/** File-backed settings storage with proper-lockfile concurrency control. */
export class FileSettingsStorage {
    globalSettingsPath;
    projectSettingsPath;
    constructor(cwd = process.cwd(), agentDir = getAgentDir()) {
        this.globalSettingsPath = join(agentDir, 'settings.json');
        this.projectSettingsPath = join(cwd, CONFIG_DIR_NAME, 'settings.json');
    }
    withLock(scope, fn) {
        const path = scope === 'global' ? this.globalSettingsPath : this.projectSettingsPath;
        const dir = dirname(path);
        let release;
        try {
            // Only create directory and lock if file exists or we need to write
            const fileExists = existsSync(path);
            if (fileExists) {
                release = lockSyncWithRetries(path);
            }
            const current = fileExists ? readFileSync(path, 'utf-8') : undefined;
            const next = fn(current);
            if (next !== undefined) {
                // Only create directory when we actually need to write
                if (!existsSync(dir)) {
                    mkdirSync(dir, { recursive: true });
                }
                if (!release) {
                    release = lockSyncWithRetries(path);
                }
                writeFileSync(path, next, 'utf-8');
            }
        }
        finally {
            if (release) {
                release();
            }
        }
    }
}
/** In-memory settings storage for tests — no file I/O. */
export class InMemorySettingsStorage {
    global;
    project;
    withLock(scope, fn) {
        const current = scope === 'global' ? this.global : this.project;
        const next = fn(current);
        if (next !== undefined) {
            if (scope === 'global') {
                this.global = next;
            }
            else {
                this.project = next;
            }
        }
    }
}
/**
 * Manages merged global + project settings with scoped persistence.
 *
 * Read accessors return the deep-merged view. Write accessors update the
 * appropriate scope (global or project), mark the field dirty, and enqueue
 * a file-locked write that only touches modified keys.
 */
export class SettingsManager {
    storage;
    globalSettings;
    projectSettings;
    settings;
    dangerouslySkipRuntimePermissionsOverride;
    dangerouslySkipSpreadsheetPermissionsOverride;
    modifiedFields = new Set(); // Track global fields modified during session
    modifiedNestedFields = new Map(); // Track global nested field modifications
    modifiedProjectFields = new Set(); // Track project fields modified during session
    modifiedProjectNestedFields = new Map(); // Track project nested field modifications
    globalSettingsLoadError = null; // Track if global settings file had parse errors
    projectSettingsLoadError = null; // Track if project settings file had parse errors
    writeQueue = Promise.resolve();
    errors;
    constructor(storage, initialGlobal, initialProject, globalLoadError = null, projectLoadError = null, initialErrors = []) {
        this.storage = storage;
        this.globalSettings = SettingsManager.migrateSettings(structuredClone(initialGlobal), 'global').settings;
        this.projectSettings = SettingsManager.migrateSettings(structuredClone(initialProject), 'project').settings;
        this.globalSettingsLoadError = globalLoadError;
        this.projectSettingsLoadError = projectLoadError;
        this.errors = [...initialErrors];
        this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
    }
    /** Create a SettingsManager that loads from files */
    static create(cwd = process.cwd(), agentDir = getAgentDir()) {
        const storage = new FileSettingsStorage(cwd, agentDir);
        return SettingsManager.fromStorage(storage);
    }
    /** Create a SettingsManager from an arbitrary storage backend */
    static fromStorage(storage) {
        const globalLoad = SettingsManager.tryLoadFromStorage(storage, 'global');
        const projectLoad = SettingsManager.tryLoadFromStorage(storage, 'project');
        const initialErrors = [];
        if (globalLoad.error) {
            initialErrors.push({ scope: 'global', error: globalLoad.error });
        }
        if (projectLoad.error) {
            initialErrors.push({ scope: 'project', error: projectLoad.error });
        }
        // Seed sandbox defaults into global settings so they're always persisted
        const needsSandboxSeed = !globalLoad.error && !globalLoad.settings.sandbox;
        if (needsSandboxSeed) {
            globalLoad.settings.sandbox = { ...getDefaultSandboxSettings() };
        }
        const consolidatedGlobalPermissioning = mergePermissioningIntoGlobal(globalLoad.settings.permissioning, projectLoad.settings.permissioning);
        const hadProjectPermissioning = projectLoad.settings.permissioning !== undefined ||
            projectLoad.settings.workspaces !== undefined ||
            projectLoad.settings.filesystemApprovals !== undefined ||
            projectLoad.settings.autoApprove !== undefined;
        const globalPermissioningChanged = JSON.stringify(globalLoad.settings.permissioning ?? null) !==
            JSON.stringify(consolidatedGlobalPermissioning);
        if (globalPermissioningChanged) {
            globalLoad.settings.permissioning = consolidatedGlobalPermissioning;
        }
        if (hadProjectPermissioning) {
            delete projectLoad.settings.permissioning;
            delete projectLoad.settings.workspaces;
            delete projectLoad.settings.filesystemApprovals;
            delete projectLoad.settings.autoApprove;
        }
        const manager = new SettingsManager(storage, globalLoad.settings, projectLoad.settings, globalLoad.error, projectLoad.error, initialErrors);
        if (needsSandboxSeed) {
            manager.markModified('sandbox');
            manager.save();
        }
        if (!globalLoad.error && (globalLoad.migrated || globalPermissioningChanged)) {
            manager.markModified('permissioning');
            manager.markModified('autoApprove');
            manager.markModified('workspaces');
            manager.markModified('filesystemApprovals');
            manager.save();
        }
        if (!projectLoad.error && (projectLoad.migrated || hadProjectPermissioning)) {
            manager.markProjectModified('permissioning');
            manager.markProjectModified('autoApprove');
            manager.markProjectModified('workspaces');
            manager.markProjectModified('filesystemApprovals');
            manager.saveProjectSettings(manager.projectSettings);
        }
        return manager;
    }
    /** Create an in-memory SettingsManager (no file I/O) */
    static inMemory(settings = {}) {
        const storage = new InMemorySettingsStorage();
        return new SettingsManager(storage, settings, {});
    }
    static loadFromStorage(storage, scope) {
        let content;
        storage.withLock(scope, (current) => {
            content = current;
            return undefined;
        });
        if (!content) {
            return SettingsManager.migrateSettings({}, scope);
        }
        const settings = JSON.parse(content);
        return SettingsManager.migrateSettings(settings, scope);
    }
    static tryLoadFromStorage(storage, scope) {
        try {
            return { ...SettingsManager.loadFromStorage(storage, scope), error: null };
        }
        catch (error) {
            return { settings: {}, migrated: false, error: error };
        }
    }
    /** Migrate old settings format to new format */
    static migrateSettings(settings, scope) {
        let migrated = false;
        // Migrate queueMode -> steeringMode
        if ('queueMode' in settings && !('steeringMode' in settings)) {
            settings.steeringMode = settings.queueMode;
            delete settings.queueMode;
            migrated = true;
        }
        // Migrate legacy websockets boolean -> transport enum
        if (!('transport' in settings) && typeof settings.websockets === 'boolean') {
            settings.transport = settings.websockets ? 'websocket' : 'sse';
            delete settings.websockets;
            migrated = true;
        }
        // Migrate old skills object format to new array format
        if ('skills' in settings &&
            typeof settings.skills === 'object' &&
            settings.skills !== null &&
            !Array.isArray(settings.skills)) {
            const skillsSettings = settings.skills;
            if (skillsSettings.enableSkillCommands !== undefined &&
                settings.enableSkillCommands === undefined) {
                settings.enableSkillCommands = skillsSettings.enableSkillCommands;
            }
            if (Array.isArray(skillsSettings.customDirectories) &&
                skillsSettings.customDirectories.length > 0) {
                settings.skills = skillsSettings.customDirectories;
            }
            else {
                delete settings.skills;
            }
            migrated = true;
        }
        const permissioningMigration = migrateRuntimePermissioningSettings(settings, scope);
        migrated = migrated || permissioningMigration.changed;
        return { settings: settings, migrated };
    }
    getEffectivePermissioningSettings() {
        const effectivePermissioning = mergeRuntimePermissioningSettings(createDefaultRuntimePermissioningSettings(), this.globalSettings.permissioning) ?? createDefaultRuntimePermissioningSettings();
        if (this.dangerouslySkipRuntimePermissionsOverride === undefined) {
            return effectivePermissioning;
        }
        return {
            ...effectivePermissioning,
            runtime: {
                ...(effectivePermissioning.runtime ?? {}),
                dangerouslySkipPermissions: this.dangerouslySkipRuntimePermissionsOverride
            }
        };
    }
    getGlobalSettings() {
        return structuredClone(this.globalSettings);
    }
    getProjectSettings() {
        return structuredClone(this.projectSettings);
    }
    reload() {
        const globalLoad = SettingsManager.tryLoadFromStorage(this.storage, 'global');
        if (!globalLoad.error) {
            this.globalSettings = globalLoad.settings;
            this.globalSettingsLoadError = null;
        }
        else {
            this.globalSettingsLoadError = globalLoad.error;
            this.recordError('global', globalLoad.error);
        }
        this.modifiedFields.clear();
        this.modifiedNestedFields.clear();
        this.modifiedProjectFields.clear();
        this.modifiedProjectNestedFields.clear();
        const projectLoad = SettingsManager.tryLoadFromStorage(this.storage, 'project');
        if (!projectLoad.error) {
            this.projectSettings = projectLoad.settings;
            this.projectSettingsLoadError = null;
        }
        else {
            this.projectSettingsLoadError = projectLoad.error;
            this.recordError('project', projectLoad.error);
        }
        const consolidatedGlobalPermissioning = mergePermissioningIntoGlobal(this.globalSettings.permissioning, this.projectSettings.permissioning);
        const hadProjectPermissioning = this.projectSettings.permissioning !== undefined ||
            this.projectSettings.workspaces !== undefined ||
            this.projectSettings.filesystemApprovals !== undefined ||
            this.projectSettings.autoApprove !== undefined;
        const globalPermissioningChanged = JSON.stringify(this.globalSettings.permissioning ?? null) !==
            JSON.stringify(consolidatedGlobalPermissioning);
        if (globalPermissioningChanged) {
            this.globalSettings.permissioning = consolidatedGlobalPermissioning;
        }
        if (hadProjectPermissioning) {
            delete this.projectSettings.permissioning;
            delete this.projectSettings.workspaces;
            delete this.projectSettings.filesystemApprovals;
            delete this.projectSettings.autoApprove;
        }
        this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
        if (!this.globalSettingsLoadError && globalPermissioningChanged) {
            this.markModified('permissioning');
            this.markModified('autoApprove');
            this.markModified('workspaces');
            this.markModified('filesystemApprovals');
            this.save();
        }
        if (!this.projectSettingsLoadError && hadProjectPermissioning) {
            this.markProjectModified('permissioning');
            this.markProjectModified('autoApprove');
            this.markProjectModified('workspaces');
            this.markProjectModified('filesystemApprovals');
            this.saveProjectSettings(this.projectSettings);
        }
    }
    /** Apply additional overrides on top of current settings */
    applyOverrides(overrides) {
        this.settings = deepMergeSettings(this.settings, overrides);
    }
    /** Mark a global field as modified during this session */
    markModified(field, nestedKey) {
        this.modifiedFields.add(field);
        if (nestedKey) {
            if (!this.modifiedNestedFields.has(field)) {
                this.modifiedNestedFields.set(field, new Set());
            }
            this.modifiedNestedFields.get(field).add(nestedKey);
        }
    }
    /** Mark a project field as modified during this session */
    markProjectModified(field, nestedKey) {
        this.modifiedProjectFields.add(field);
        if (nestedKey) {
            if (!this.modifiedProjectNestedFields.has(field)) {
                this.modifiedProjectNestedFields.set(field, new Set());
            }
            this.modifiedProjectNestedFields.get(field).add(nestedKey);
        }
    }
    recordError(scope, error) {
        const normalizedError = error instanceof Error ? error : new Error(String(error));
        this.errors.push({ scope, error: normalizedError });
    }
    clearModifiedScope(scope) {
        if (scope === 'global') {
            this.modifiedFields.clear();
            this.modifiedNestedFields.clear();
            return;
        }
        this.modifiedProjectFields.clear();
        this.modifiedProjectNestedFields.clear();
    }
    enqueueWrite(scope, task) {
        this.writeQueue = this.writeQueue
            .then(() => {
            task();
            this.clearModifiedScope(scope);
        })
            .catch((error) => {
            this.recordError(scope, error);
        });
    }
    cloneModifiedNestedFields(source) {
        const snapshot = new Map();
        for (const [key, value] of source.entries()) {
            snapshot.set(key, new Set(value));
        }
        return snapshot;
    }
    persistScopedSettings(scope, snapshotSettings, modifiedFields, modifiedNestedFields) {
        this.storage.withLock(scope, (current) => {
            const currentFileSettings = current
                ? SettingsManager.migrateSettings(JSON.parse(current), scope)
                    .settings
                : {};
            const mergedSettings = { ...currentFileSettings };
            for (const field of modifiedFields) {
                const value = snapshotSettings[field];
                if (modifiedNestedFields.has(field) && typeof value === 'object' && value !== null) {
                    const nestedModified = modifiedNestedFields.get(field);
                    const baseNested = currentFileSettings[field] ?? {};
                    const inMemoryNested = value;
                    const mergedNested = { ...baseNested };
                    for (const nestedKey of nestedModified) {
                        mergedNested[nestedKey] = inMemoryNested[nestedKey];
                    }
                    mergedSettings[field] = mergedNested;
                }
                else {
                    mergedSettings[field] = value;
                }
            }
            return JSON.stringify(mergedSettings, null, 2);
        });
    }
    save() {
        this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
        if (this.globalSettingsLoadError) {
            return;
        }
        const snapshotGlobalSettings = structuredClone(this.globalSettings);
        const modifiedFields = new Set(this.modifiedFields);
        const modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedNestedFields);
        this.enqueueWrite('global', () => {
            this.persistScopedSettings('global', snapshotGlobalSettings, modifiedFields, modifiedNestedFields);
        });
    }
    saveProjectSettings(settings) {
        this.projectSettings = structuredClone(settings);
        this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
        if (this.projectSettingsLoadError) {
            return;
        }
        const snapshotProjectSettings = structuredClone(this.projectSettings);
        const modifiedFields = new Set(this.modifiedProjectFields);
        const modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);
        this.enqueueWrite('project', () => {
            this.persistScopedSettings('project', snapshotProjectSettings, modifiedFields, modifiedNestedFields);
        });
    }
    async flush() {
        await this.writeQueue;
    }
    drainErrors() {
        const drained = [...this.errors];
        this.errors = [];
        return drained;
    }
    getLastChangelogVersion() {
        return this.settings.lastChangelogVersion;
    }
    setLastChangelogVersion(version) {
        this.globalSettings.lastChangelogVersion = version;
        this.markModified('lastChangelogVersion');
        this.save();
    }
    getDefaultProvider() {
        return this.settings.defaultProvider;
    }
    getDefaultModel() {
        return this.settings.defaultModel;
    }
    setDefaultProvider(provider) {
        this.globalSettings.defaultProvider = provider;
        this.markModified('defaultProvider');
        this.save();
    }
    setDefaultModel(modelId) {
        this.globalSettings.defaultModel = modelId;
        this.markModified('defaultModel');
        this.save();
    }
    setDefaultModelAndProvider(provider, modelId) {
        this.globalSettings.defaultProvider = provider;
        this.globalSettings.defaultModel = modelId;
        this.markModified('defaultProvider');
        this.markModified('defaultModel');
        this.save();
    }
    getSteeringMode() {
        return 'one-at-a-time';
    }
    getFollowUpMode() {
        return 'one-at-a-time';
    }
    getTheme() {
        return this.settings.theme;
    }
    setTheme(theme) {
        this.globalSettings.theme = theme;
        this.markModified('theme');
        this.save();
    }
    getDefaultThinkingLevel() {
        return this.settings.defaultThinkingLevel;
    }
    setDefaultThinkingLevel(level) {
        this.globalSettings.defaultThinkingLevel = level;
        this.markModified('defaultThinkingLevel');
        this.save();
    }
    getTransport() {
        return 'sse';
    }
    getRetryEnabled() {
        return this.settings.retry?.enabled ?? true;
    }
    setRetryEnabled(enabled) {
        if (!this.globalSettings.retry) {
            this.globalSettings.retry = {};
        }
        this.globalSettings.retry.enabled = enabled;
        this.markModified('retry', 'enabled');
        this.save();
    }
    getRetrySettings() {
        return {
            enabled: this.getRetryEnabled(),
            maxRetries: this.settings.retry?.maxRetries ?? 3,
            baseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,
            maxDelayMs: this.settings.retry?.maxDelayMs ?? 60000
        };
    }
    getErrorRecoverySettings() {
        const fb = this.settings.modelFallback;
        return {
            enabled: this.getRetryEnabled(),
            modelFallback: fb?.enabled && fb?.fallbackModel
                ? {
                    enabled: true,
                    fallbackModel: fb.fallbackModel,
                    stripThinking: fb.stripThinking ?? false
                }
                : undefined
        };
    }
    getBudgetContinuationSettings() {
        return {
            enabled: this.settings.budgetContinuation?.enabled ?? false,
            budgetTokens: this.settings.budgetContinuation?.budgetTokens ?? 0,
            windDownPct: this.settings.budgetContinuation?.windDownPct ?? 95,
            minTokensPerContinuation: this.settings.budgetContinuation?.minTokensPerContinuation ?? 500,
            stuckWindow: this.settings.budgetContinuation?.stuckWindow ?? 3,
            maxTurns: this.settings.budgetContinuation?.maxTurns ?? 0,
            maxToolUses: this.settings.budgetContinuation?.maxToolUses ?? 0
        };
    }
    getHideThinkingBlock() {
        return this.settings.hideThinkingBlock ?? true;
    }
    setHideThinkingBlock(hide) {
        this.globalSettings.hideThinkingBlock = hide;
        this.markModified('hideThinkingBlock');
        this.save();
    }
    getShellPath() {
        return this.settings.shellPath;
    }
    setShellPath(path) {
        this.globalSettings.shellPath = path;
        this.markModified('shellPath');
        this.save();
    }
    getQuietStartup() {
        return this.settings.quietStartup ?? false;
    }
    setQuietStartup(quiet) {
        this.globalSettings.quietStartup = quiet;
        this.markModified('quietStartup');
        this.save();
    }
    getShellCommandPrefix() {
        return this.settings.shellCommandPrefix;
    }
    setShellCommandPrefix(prefix) {
        this.globalSettings.shellCommandPrefix = prefix;
        this.markModified('shellCommandPrefix');
        this.save();
    }
    getCollapseChangelog() {
        return this.settings.collapseChangelog ?? false;
    }
    setCollapseChangelog(collapse) {
        this.globalSettings.collapseChangelog = collapse;
        this.markModified('collapseChangelog');
        this.save();
    }
    getPackages() {
        return [...(this.settings.packages ?? [])];
    }
    setPackages(packages) {
        this.globalSettings.packages = packages;
        this.markModified('packages');
        this.save();
    }
    setProjectPackages(packages) {
        const projectSettings = structuredClone(this.projectSettings);
        projectSettings.packages = packages;
        this.markProjectModified('packages');
        this.saveProjectSettings(projectSettings);
    }
    getExtensionPaths() {
        return [...(this.settings.extensions ?? [])];
    }
    setExtensionPaths(paths) {
        this.globalSettings.extensions = paths;
        this.markModified('extensions');
        this.save();
    }
    setProjectExtensionPaths(paths) {
        const projectSettings = structuredClone(this.projectSettings);
        projectSettings.extensions = paths;
        this.markProjectModified('extensions');
        this.saveProjectSettings(projectSettings);
    }
    getSkillPaths() {
        return [...(this.settings.skills ?? [])];
    }
    setSkillPaths(paths) {
        this.globalSettings.skills = paths;
        this.markModified('skills');
        this.save();
    }
    setProjectSkillPaths(paths) {
        const projectSettings = structuredClone(this.projectSettings);
        projectSettings.skills = paths;
        this.markProjectModified('skills');
        this.saveProjectSettings(projectSettings);
    }
    getDisabledSkills() {
        return [...new Set(this.settings.disabledSkills ?? [])].sort();
    }
    setDisabledSkills(names) {
        this.globalSettings.disabledSkills = [
            ...new Set(names.map((name) => name.trim()).filter(Boolean))
        ].sort();
        this.markModified('disabledSkills');
        this.save();
    }
    isSkillDisabled(name) {
        return this.getDisabledSkills().includes(name);
    }
    disableSkill(name) {
        const trimmed = name.trim();
        if (!trimmed)
            return;
        const next = new Set(this.settings.disabledSkills ?? []);
        next.add(trimmed);
        this.setDisabledSkills([...next]);
    }
    enableSkill(name) {
        const trimmed = name.trim();
        if (!trimmed)
            return;
        const next = new Set(this.settings.disabledSkills ?? []);
        next.delete(trimmed);
        this.setDisabledSkills([...next]);
    }
    getPromptTemplatePaths() {
        return [...(this.settings.prompts ?? [])];
    }
    setPromptTemplatePaths(paths) {
        this.globalSettings.prompts = paths;
        this.markModified('prompts');
        this.save();
    }
    setProjectPromptTemplatePaths(paths) {
        const projectSettings = structuredClone(this.projectSettings);
        projectSettings.prompts = paths;
        this.markProjectModified('prompts');
        this.saveProjectSettings(projectSettings);
    }
    getThemePaths() {
        return [...(this.settings.themes ?? [])];
    }
    setThemePaths(paths) {
        this.globalSettings.themes = paths;
        this.markModified('themes');
        this.save();
    }
    setProjectThemePaths(paths) {
        const projectSettings = structuredClone(this.projectSettings);
        projectSettings.themes = paths;
        this.markProjectModified('themes');
        this.saveProjectSettings(projectSettings);
    }
    getEnableSkillCommands() {
        return true;
    }
    getShowImages() {
        return this.settings.terminal?.showImages ?? true;
    }
    setShowImages(show) {
        if (!this.globalSettings.terminal) {
            this.globalSettings.terminal = {};
        }
        this.globalSettings.terminal.showImages = show;
        this.markModified('terminal', 'showImages');
        this.save();
    }
    getClearOnShrink() {
        return false;
    }
    getImageAutoResize() {
        return true;
    }
    getBlockImages() {
        return false;
    }
    getDoubleEscapeAction() {
        return 'tree';
    }
    getShowHardwareCursor() {
        return false;
    }
    getEditorPaddingX() {
        return 0;
    }
    getAutocompleteMaxVisible() {
        return 10;
    }
    getCodeBlockIndent() {
        return this.settings.markdown?.codeBlockIndent ?? '  ';
    }
    getNewSheet() {
        return this.settings.newSheet === true;
    }
    setNewSheet(enabled) {
        this.globalSettings.newSheet = enabled;
        this.markModified('newSheet');
        this.save();
    }
    getSandboxSettings() {
        return this.settings.sandbox ?? {};
    }
    getWorkspaceRoots() {
        return getWorkspaceRootsFromPermissioning(this.getEffectivePermissioningSettings());
    }
    setWorkspaceRoots(paths) {
        this.globalSettings.permissioning = setPermissioningWorkspaceRoots(this.globalSettings.permissioning, paths);
        this.globalSettings.workspaces = undefined;
        this.markModified('permissioning', 'filesystem');
        this.markModified('workspaces');
        this.save();
    }
    getFilesystemApprovals() {
        return [...(this.getEffectivePermissioningSettings().filesystem?.persistentApprovals ?? [])];
    }
    addFilesystemApproval(grant) {
        const nextPermissioning = addPermissioningFilesystemApproval(this.globalSettings.permissioning, grant);
        const current = this.globalSettings.permissioning?.filesystem?.persistentApprovals ?? [];
        const next = nextPermissioning.filesystem?.persistentApprovals ?? [];
        if (current.length === next.length) {
            return;
        }
        this.globalSettings.permissioning = nextPermissioning;
        this.globalSettings.filesystemApprovals = undefined;
        this.markModified('permissioning', 'filesystem');
        this.markModified('filesystemApprovals');
        this.save();
    }
    removeFilesystemApproval(grant) {
        const nextPermissioning = removePermissioningFilesystemApproval(this.globalSettings.permissioning, grant);
        const current = this.globalSettings.permissioning?.filesystem?.persistentApprovals ?? [];
        const next = nextPermissioning.filesystem?.persistentApprovals ?? [];
        if (current.length === next.length) {
            return;
        }
        this.globalSettings.permissioning = nextPermissioning;
        this.globalSettings.filesystemApprovals = undefined;
        this.markModified('permissioning', 'filesystem');
        this.markModified('filesystemApprovals');
        this.save();
    }
    getSandboxMode() {
        return this.settings.sandbox?.mode ?? 'disabled';
    }
    /** Ensure globalSettings.sandbox exists with full defaults. */
    ensureSandboxDefaults() {
        if (!this.globalSettings.sandbox) {
            this.globalSettings.sandbox = { ...getDefaultSandboxSettings() };
            this.markModified('sandbox');
        }
        return this.globalSettings.sandbox;
    }
    setSandboxMode(mode) {
        this.ensureSandboxDefaults().mode = mode;
        this.markModified('sandbox', 'mode');
        this.save();
    }
    getSandboxNetworkMode() {
        return this.settings.sandbox?.network ?? DEFAULT_SANDBOX_NETWORK;
    }
    setSandboxNetworkMode(mode) {
        this.ensureSandboxDefaults().network = mode;
        this.markModified('sandbox', 'network');
        this.save();
    }
    getSandboxAllowedDomains() {
        return this.settings.sandbox?.allowedDomains ?? [];
    }
    setSandboxAllowedDomains(domains) {
        this.ensureSandboxDefaults().allowedDomains = domains;
        this.markModified('sandbox', 'allowedDomains');
        this.save();
    }
    addSandboxAllowedDomain(domain) {
        const sandbox = this.ensureSandboxDefaults();
        const domains = [...(sandbox.allowedDomains ?? [])];
        if (!domains.includes(domain)) {
            domains.push(domain);
            sandbox.allowedDomains = domains;
            this.markModified('sandbox', 'allowedDomains');
            this.save();
        }
    }
    setSandboxReadPaths(paths) {
        this.ensureSandboxDefaults().readPaths = paths;
        this.markModified('sandbox', 'readPaths');
        this.save();
    }
    setSandboxWritePaths(paths) {
        this.ensureSandboxDefaults().writePaths = paths;
        this.markModified('sandbox', 'writePaths');
        this.save();
    }
    resetSandboxToDefaults() {
        const mode = this.globalSettings.sandbox?.mode ?? 'disabled';
        this.globalSettings.sandbox = { ...getDefaultSandboxSettings(), mode };
        this.markModified('sandbox');
        this.save();
    }
    /** Get the persistent default (what new sessions start with). */
    getAutoApproveDefault() {
        return this.getEffectivePermissioningSettings().spreadsheet?.autoApproveDefault ?? false;
    }
    /** Get the session-start default after applying non-persistent CLI overrides. */
    getSessionAutoApproveDefault() {
        if (this.dangerouslySkipSpreadsheetPermissionsOverride === true) {
            return true;
        }
        return this.getAutoApproveDefault();
    }
    getDangerouslySkipRuntimePermissions() {
        return getDangerouslySkipRuntimePermissionsFromPermissioning(this.getEffectivePermissioningSettings());
    }
    getDangerouslySkipSpreadsheetPermissions() {
        return this.dangerouslySkipSpreadsheetPermissionsOverride ?? false;
    }
    setDangerouslySkipRuntimePermissionsOverride(enabled) {
        this.dangerouslySkipRuntimePermissionsOverride = enabled;
    }
    setDangerouslySkipSpreadsheetPermissionsOverride(enabled) {
        this.dangerouslySkipSpreadsheetPermissionsOverride = enabled;
    }
    setDangerouslySkipRuntimePermissions(enabled) {
        this.dangerouslySkipRuntimePermissionsOverride = undefined;
        this.globalSettings.permissioning = setPermissioningDangerouslySkipRuntimePermissions(this.globalSettings.permissioning, enabled);
        this.markModified('permissioning', 'runtime');
        this.save();
    }
    /** Persist the default used to initialize new session approval state. */
    setAutoApproveDefault(autoApprove) {
        this.globalSettings.permissioning = setPermissioningSpreadsheetAutoApproveDefault(this.globalSettings.permissioning, autoApprove);
        this.globalSettings.autoApprove = undefined;
        this.markModified('permissioning', 'spreadsheet');
        this.markModified('autoApprove');
        this.save();
    }
    /** Whether session traces and ClickHouse logs are uploaded. Default: true. */
    getTelemetry() {
        return this.settings.telemetry ?? true;
    }
    setTelemetry(enabled) {
        this.globalSettings.telemetry = enabled;
        this.markModified('telemetry');
        this.save();
    }
    /** Whether dev mode is enabled (AGENTS.md, dev resources, verbose logging). Default: false. */
    getDevMode() {
        return this.settings.devMode ?? false;
    }
    setDevMode(enabled) {
        this.globalSettings.devMode = enabled;
        this.markModified('devMode');
        this.save();
    }
    // ---------------------------------------------------------------------------
    // Connections
    // ---------------------------------------------------------------------------
    /** Get all connection metadata (names, types, field names — no secrets). */
    getConnections() {
        return this.settings.connections ?? {};
    }
    /** Get metadata for a single connection. */
    getConnection(name) {
        return this.settings.connections?.[name];
    }
    /** Get all connection names. */
    getConnectionNames() {
        return Object.keys(this.settings.connections ?? {});
    }
    /** Set metadata for a connection (secrets go to OS keychain, not here). */
    setConnection(name, metadata) {
        if (!this.globalSettings.connections) {
            this.globalSettings.connections = {};
        }
        this.globalSettings.connections[name] = metadata;
        this.markModified('connections');
        this.save();
    }
    /** Whether to show cache read/write tokens (R/W) in footer. Default: false. */
    getShowCacheTokens() {
        return this.settings.showCacheTokens ?? false;
    }
    setShowCacheTokens(enabled) {
        this.globalSettings.showCacheTokens = enabled;
        this.markModified('showCacheTokens');
        this.save();
    }
    getToolSummariesEnabled() {
        return this.settings.toolSummaries?.enabled ?? true;
    }
    setToolSummariesEnabled(enabled) {
        if (!this.globalSettings.toolSummaries) {
            this.globalSettings.toolSummaries = {};
        }
        this.globalSettings.toolSummaries.enabled = enabled;
        this.markModified('toolSummaries', 'enabled');
        this.save();
    }
    getDurableMemoryEnabled() {
        return this.settings.durableMemory?.enabled ?? true;
    }
    getRemoteControlEnabled() {
        return this.settings.remoteControl?.enabled ?? false;
    }
    getRemoteControlProvider() {
        return this.settings.remoteControl?.provider;
    }
    getMcpOAuthSettings() {
        return {
            credentialsStoreMode: this.settings.mcpOAuth?.credentialsStoreMode ?? 'auto',
            callbackPort: this.settings.mcpOAuth?.callbackPort ?? 0,
            callbackUrl: this.settings.mcpOAuth?.callbackUrl ?? ''
        };
    }
    setMcpOAuthSettings(settings) {
        this.globalSettings.mcpOAuth = {
            credentialsStoreMode: settings.credentialsStoreMode ?? 'auto',
            callbackPort: settings.callbackPort ?? 0,
            callbackUrl: settings.callbackUrl ?? ''
        };
        this.markModified('mcpOAuth');
        this.save();
    }
    setRemoteControl(config) {
        this.globalSettings.remoteControl = {
            enabled: config.enabled ?? false,
            provider: config.provider
        };
        this.markModified('remoteControl');
        this.save();
    }
    setDurableMemoryEnabled(enabled) {
        if (!this.globalSettings.durableMemory) {
            this.globalSettings.durableMemory = {};
        }
        this.globalSettings.durableMemory.enabled = enabled;
        this.markModified('durableMemory', 'enabled');
        this.save();
    }
    /** Remove a connection's metadata. */
    removeConnection(name) {
        if (this.globalSettings.connections) {
            delete this.globalSettings.connections[name];
            this.markModified('connections');
            this.save();
        }
    }
}
//# sourceMappingURL=settings-manager.js.map