import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { AgentRuntime, DEFAULT_ALLOWED_TOOLS, LocalSandbox, createCommandToolDefinition, createDefaultRuntimePolicy, createDefaultToolRegistry, createMcpToolDefinition, resolveWorkspaceStorageRoot, } from "@best-agent/engine";
import { loadExtensionRegistry, resolveInstalledExtensionSkills, } from "@best-agent/extensions";
const PROVIDER_KIND_BY_DIMSDK_ID = {
    aihubmix: "aihubmix",
    "aihubmix-responses": "aihubmix-responses",
    anthropic: "anthropic",
    custom: "customProvider",
    deepseek: "deepseek",
    google: "google",
    moonshot: "moonshotai",
    "moonshot-ai": "moonshotai",
    "next-api-oauth": "customProvider",
    openai: "openai",
    "openai-responses": "openai-responses",
    xai: "xai",
    "xai-responses": "xai-responses",
    zenmux: "zenmux",
};
const DIMSDK_ID_BY_PROVIDER_KIND = {
    aihubmix: "aihubmix",
    "aihubmix-responses": "aihubmix-responses",
    anthropic: "anthropic",
    customProvider: "custom",
    deepseek: "deepseek",
    google: "google",
    moonshotai: "moonshot-ai",
    openai: "openai",
    "openai-responses": "openai-responses",
    xai: "xai",
    "xai-responses": "xai-responses",
    zenmux: "zenmux",
};
function resolveRuntimeContextTokenBudget() {
    const raw = process.env.BEST_AGENT_CONTEXT_TOKEN_BUDGET ?? process.env.DIMCODE_CONTEXT_WINDOW;
    if (!raw) {
        return undefined;
    }
    const parsed = Number(raw);
    return Number.isFinite(parsed) && parsed >= 256 ? Math.floor(parsed) : undefined;
}
export async function createCliRuntime(options) {
    const extensionRegistry = loadExtensionRegistry(options.extensionsRoot ?? process.env.BEST_AGENT_EXTENSIONS_ROOT);
    const commandTools = loadCommandTools(extensionRegistry);
    const mcpTools = loadMcpTools(extensionRegistry);
    const extensionSkills = await loadSkills(extensionRegistry);
    const storageRoot = resolveCliStorageRoot(options);
    const persistedState = readCliPersistedState(storageRoot);
    const providerConfig = options.providerConfig ?? persistedState?.providerConfig;
    const contextTokenBudget = resolveRuntimeContextTokenBudget();
    return new AgentRuntime({
        ...options,
        providerConfig,
        storageRoot,
        ...(contextTokenBudget ? { memory: { contextTokenBudget } } : {}),
        agentProfiles: loadAgentProfiles(extensionRegistry),
        policy: createDefaultRuntimePolicy({
            allowedTools: [
                ...DEFAULT_ALLOWED_TOOLS,
                ...commandTools.map((tool) => tool.name),
                ...mcpTools.map((tool) => tool.name),
            ],
            cwd: options.cwd,
            writableRoots: [`${storageRoot}/threads`],
        }),
        skills: extensionSkills,
        tools: createDefaultToolRegistry([...commandTools, ...mcpTools]),
    });
}
export function readCliPersistedState(storageRoot) {
    const filePath = cliStatePath(storageRoot);
    if (!existsSync(filePath)) {
        return undefined;
    }
    try {
        const parsed = JSON.parse(readFileSync(filePath, "utf8"));
        if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
            return parsed;
        }
    }
    catch { }
    return undefined;
}
export function writeCliPersistedState(storageRoot, state) {
    const filePath = cliStatePath(storageRoot);
    mkdirSync(dirname(filePath), { recursive: true });
    writeFileSync(filePath, JSON.stringify(state, null, 2));
}
export function resolveCliStorageRoot(options) {
    return (options.storageRoot
        ?? process.env.BEST_AGENT_STORAGE_ROOT
        ?? resolveWorkspaceStorageRoot(options.cwd ?? process.cwd()));
}
export function hydrateDimSdkProviderSelection(state, input) {
    const nextProviderState = input.persistedProviderState
        ? cloneJson(input.persistedProviderState)
        : input.providerConfig
            ? providerStateFromProviderConfig(input.providerConfig)
            : undefined;
    if (!nextProviderState) {
        return;
    }
    replaceObjectContents(state.provider, nextProviderState);
    const activeId = normalizeText(state.provider.activeId);
    const activeModelByProvider = asRecord(state.provider.activeModelByProvider);
    const nextModel = (activeId ? normalizeText(activeModelByProvider[activeId]) : undefined) ?? input.providerConfig?.model;
    if (nextModel) {
        state.config.model = nextModel;
    }
}
export function resolveProviderConfigFromDimSdkState(state, fallback) {
    const providerState = asRecord(state.provider);
    const activeId = normalizeText(providerState.activeId);
    const activeModelByProvider = asRecord(providerState.activeModelByProvider);
    const model = normalizeText(state.config?.model)
        ?? (activeId ? normalizeText(activeModelByProvider[activeId]) : undefined)
        ?? normalizeText(fallback?.model);
    if (!model) {
        return undefined;
    }
    const customProviders = Array.isArray(providerState.customProviders)
        ? providerState.customProviders
        : [];
    const customProvider = activeId?.startsWith("cp_")
        ? customProviders.find((candidate) => normalizeText(candidate?.id) === activeId)
        : undefined;
    const customConfig = asRecord(customProvider);
    const legacyCustom = asRecord(providerState.custom);
    const connections = asRecord(providerState.connections);
    const connection = (activeId === "custom"
        ? legacyCustom
        : activeId
            ? asRecord(connections[activeId])
            : {});
    const adapter = normalizeText(customConfig.adapter);
    const kind = resolveProviderKind(activeId, adapter, fallback?.kind);
    if (!kind) {
        return fallback ? { ...fallback, model } : undefined;
    }
    const baseURL = normalizeText(customConfig.baseUrl)
        ?? normalizeText(connection.baseUrl)
        ?? normalizeText(legacyCustom.baseUrl)
        ?? normalizeText(fallback?.baseURL);
    const apiKey = normalizeText(customConfig.apiKey)
        ?? normalizeText(connection.apiKey)
        ?? normalizeText(legacyCustom.apiKey)
        ?? normalizeText(fallback?.apiKey);
    const nextConfig = {
        compatibilityMode: fallback?.compatibilityMode,
        kind,
        model,
        systemPrompt: fallback?.systemPrompt,
        timeoutMs: fallback?.timeoutMs,
    };
    if (apiKey) {
        nextConfig.apiKey = apiKey;
    }
    if (baseURL) {
        nextConfig.baseURL = baseURL;
    }
    return nextConfig;
}
function providerStateFromProviderConfig(providerConfig) {
    const providerId = DIMSDK_ID_BY_PROVIDER_KIND[providerConfig.kind];
    const activeModelByProvider = providerId ? { [providerId]: providerConfig.model } : {};
    if (providerConfig.kind === "customProvider") {
        return {
            activeId: "custom",
            activeModelByProvider,
            connections: {},
            custom: {
                apiKey: providerConfig.apiKey,
                baseUrl: providerConfig.baseURL,
                models: providerConfig.model ? [{ id: providerConfig.model }] : [],
            },
            customProviders: [],
        };
    }
    return {
        activeId: providerId,
        activeModelByProvider,
        connections: providerId
            ? {
                [providerId]: {
                    apiKey: providerConfig.apiKey,
                    baseUrl: providerConfig.baseURL,
                },
            }
            : {},
        custom: {
            apiKey: undefined,
            baseUrl: undefined,
            models: [],
        },
        customProviders: [],
    };
}
function resolveProviderKind(providerId, adapter, fallback) {
    if (providerId?.startsWith("cp_")) {
        return PROVIDER_KIND_BY_DIMSDK_ID[adapter ?? ""] ?? fallback ?? "customProvider";
    }
    return (PROVIDER_KIND_BY_DIMSDK_ID[providerId ?? ""]
        ?? PROVIDER_KIND_BY_DIMSDK_ID[adapter ?? ""]
        ?? fallback);
}
function replaceObjectContents(target, source) {
    for (const key of Object.keys(target)) {
        delete target[key];
    }
    Object.assign(target, source);
}
function asRecord(value) {
    if (!value || typeof value !== "object" || Array.isArray(value)) {
        return {};
    }
    return value;
}
function normalizeText(value) {
    const normalized = String(value ?? "").trim();
    return normalized || undefined;
}
function cloneJson(value) {
    return JSON.parse(JSON.stringify(value ?? null));
}
function loadAgentProfiles(registry) {
    return registry.getAgentProfiles().map((profile) => ({
        allowedTools: profile.allowedTools ?? [],
        defaultSkills: (profile.defaultSkills ?? []).map((skillName) => `skill:${profile.sourceExtension}:${skillName}`),
        description: profile.description,
        name: profile.name,
        source: "extension",
        systemPrompt: profile.systemPrompt,
    }));
}
async function loadSkills(registry) {
    return (await resolveInstalledExtensionSkills(registry, async ({ args, command, cwd }) => new LocalSandbox().runCommand([command, ...args], cwd))).map((skill) => ({
        allowedTools: skill.allowedTools,
        content: skill.content,
        contextMode: skill.contextMode,
        description: skill.description,
        effort: skill.effort,
        executionMode: skill.executionMode,
        id: `skill:${skill.sourceExtension}:${skill.name}`,
        model: skill.model,
        name: skill.name,
        pathScope: skill.pathScope,
        source: "extension",
        sourceExtension: skill.sourceExtension,
        whenToUse: skill.whenToUse,
    }));
}
function loadMcpTools(registry) {
    return registry.listMcpServers().flatMap((server) => server.tools.map((tool) => createMcpToolDefinition({
        args: server.args,
        command: server.command,
        description: tool.description,
        sourceExtension: server.sourceExtension,
        serverName: server.name,
        toolName: tool.name,
    })));
}
function loadCommandTools(registry) {
    return registry.getCommandTools().map((tool) => createCommandToolDefinition({
        args: tool.args,
        command: tool.command,
        description: tool.description,
        extensionName: tool.sourceExtension,
        toolName: tool.name,
    }));
}
function cliStatePath(storageRoot) {
    return join(storageRoot, "cli-state.json");
}
//# sourceMappingURL=runtime.js.map