/**
 * ExtensionLifecycle — owns extension runner creation, binding, reload,
 * and tool-registry refresh.
 *
 * Extracted from AgentSession to isolate extension lifecycle orchestration
 * behind a clean boundary. No behavior changes — pure refactoring.
 */
import { ExtensionRunner } from '../extensions/runner.js';
import { buildExtensionResourcePaths } from './extension-resources.js';
// ============================================================================
// ExtensionLifecycle
// ============================================================================
export class ExtensionLifecycle {
    _extensionRunner = undefined;
    _extensionRunnerRef;
    _extensionUIContext;
    _extensionCommandContextActions;
    _extensionShutdownHandler;
    _extensionErrorListener;
    _extensionErrorUnsubscriber;
    _runtimeTools;
    _reloadTools;
    // Stable references to other subsystems
    _resourceLoader;
    _cwd;
    _sessionManager;
    _modelRegistry;
    _sessionState;
    _settingsManager;
    _tools;
    _callbacks;
    constructor(config, callbacks) {
        this._resourceLoader = config.resourceLoader;
        this._cwd = config.cwd;
        this._extensionRunnerRef = config.extensionRunnerRef;
        this._runtimeTools = config.runtimeTools;
        this._reloadTools = config.reloadTools;
        this._sessionManager = config.sessionManager;
        this._modelRegistry = config.modelRegistry;
        this._sessionState = config.sessionState;
        this._settingsManager = config.settingsManager;
        this._tools = config.tools;
        this._callbacks = callbacks;
    }
    // =========================================================================
    // Getters
    // =========================================================================
    get extensionRunner() {
        return this._extensionRunner;
    }
    get runtimeTools() {
        return this._runtimeTools;
    }
    // =========================================================================
    // Public methods
    // =========================================================================
    /**
     * Build the extension runtime: create the ExtensionRunner, bind core
     * actions, apply UI bindings, and refresh the tool registry.
     */
    buildRuntime(options) {
        const extensionsResult = this._resourceLoader.getExtensions();
        const hasExtensions = extensionsResult.extensions.length > 0;
        const hasRuntimeTools = this._runtimeTools.length > 0;
        this._extensionRunner =
            hasExtensions || hasRuntimeTools
                ? new ExtensionRunner(extensionsResult.extensions, extensionsResult.runtime, this._cwd, this._sessionManager, this._modelRegistry, this._sessionState)
                : undefined;
        if (this._extensionRunnerRef) {
            this._extensionRunnerRef.current = this._extensionRunner;
        }
        if (this._extensionRunner) {
            this._bindExtensionCore(this._extensionRunner);
            this._applyExtensionBindings(this._extensionRunner);
        }
        this.refreshToolRegistry({
            toolNames: options.toolNames,
            modeName: options.modeName
        });
    }
    /**
     * Apply extension bindings (UI context, command context, shutdown, error),
     * emit session_start, and discover extension resources.
     */
    async bindExtensions(bindings) {
        if (bindings.uiContext !== undefined) {
            this._extensionUIContext = bindings.uiContext;
        }
        if (bindings.commandContextActions !== undefined) {
            this._extensionCommandContextActions = bindings.commandContextActions;
        }
        if (bindings.shutdownHandler !== undefined) {
            this._extensionShutdownHandler = bindings.shutdownHandler;
        }
        if (bindings.onError !== undefined) {
            this._extensionErrorListener = bindings.onError;
        }
        if (this._extensionRunner) {
            this._applyExtensionBindings(this._extensionRunner);
            await this._extensionRunner.emit({ type: 'session_start' });
            await this._extendResourcesFromExtensions('startup');
        }
    }
    /**
     * Reload extensions, settings, model registry, resource loader, and tools.
     * Returns warnings from the reload process.
     */
    async reload() {
        const warnings = [];
        await this._extensionRunner?.emit({ type: 'session_shutdown' });
        this._settingsManager.reload();
        // Use modelRegistry.refresh() instead of bare resetApiProviders() so that
        // dynamically registered providers (e.g. Shortcut) are re-applied after the
        // global API registry is cleared.
        this._modelRegistry.refresh();
        await this._resourceLoader.reload();
        if (this._reloadTools) {
            const result = await this._reloadTools();
            this._runtimeTools = result.tools;
            warnings.push(...result.warnings);
        }
        this.buildRuntime({});
        const hasBindings = this._extensionUIContext ||
            this._extensionCommandContextActions ||
            this._extensionShutdownHandler ||
            this._extensionErrorListener;
        if (this._extensionRunner && hasBindings) {
            await this._extensionRunner.emit({ type: 'session_start' });
            await this._extendResourcesFromExtensions('reload');
        }
        return { warnings };
    }
    /**
     * Refresh the tool registry with the current extension runner and tools.
     */
    refreshToolRegistry(options) {
        this._tools.refresh({
            extensionRunner: this._extensionRunner,
            tools: this._runtimeTools,
            toolNames: options?.toolNames,
            modeName: options?.modeName
        });
    }
    // =========================================================================
    // Private helpers
    // =========================================================================
    async _extendResourcesFromExtensions(reason) {
        if (!this._extensionRunner?.hasHandlers('resources_discover')) {
            return;
        }
        const { skillPaths, promptPaths } = await this._extensionRunner.emitResourcesDiscover(this._cwd, reason);
        if (skillPaths.length === 0 && promptPaths.length === 0) {
            return;
        }
        const extensionPaths = {
            skillPaths: buildExtensionResourcePaths(skillPaths),
            promptPaths: buildExtensionResourcePaths(promptPaths)
        };
        this._resourceLoader.extendResources(extensionPaths);
        const prompt = this._tools.rebuildSystemPrompt();
        this._tools.overrideBaseSystemPrompt(prompt);
    }
    _applyExtensionBindings(runner) {
        runner.setUIContext(this._extensionUIContext);
        runner.bindCommandContext(this._extensionCommandContextActions);
        this._extensionErrorUnsubscriber?.();
        this._extensionErrorUnsubscriber = this._extensionErrorListener
            ? runner.onError(this._extensionErrorListener)
            : undefined;
    }
    _bindExtensionCore(runner) {
        runner.bindCore({
            appendEntry: (customType, data) => {
                this._sessionManager.appendCustomEntry(customType, data);
            },
            refreshTools: () => this.refreshToolRegistry()
        }, {
            getModel: () => this._callbacks.getModel(),
            isIdle: () => this._callbacks.isIdle(),
            abort: () => this._callbacks.abort(),
            hasPendingMessages: () => this._callbacks.hasPendingMessages(),
            shutdown: () => this._callbacks.shutdown(),
            getContextUsage: () => this._callbacks.getContextUsage(),
            compact: (options) => this._callbacks.compact(options),
            getSystemPrompt: () => this._callbacks.getSystemPrompt(),
            deductChildUsage: (usage) => this._callbacks.deductChildUsage(usage),
            getMessages: () => this._callbacks.getMessages(),
            getTools: () => this._callbacks.getTools(),
            getPermissionPolicy: () => this._callbacks.getPermissionPolicy()
        });
    }
}
//# sourceMappingURL=extension-lifecycle.js.map