
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1e85d434-192d-5fd0-b8c7-6512d5a31963")}catch(e){}}();
import { readFile } from "node:fs/promises";
import { createServer } from "node:http";
import { join } from "node:path";
import { createHTTPHandler } from "@trpc/server/adapters/standalone";
import { handleClineMcpOauthCallback } from "../cline-sdk/cline-mcp-runtime-service.js";
import { createInMemoryClineTaskSessionService, } from "../cline-sdk/cline-task-session-service.js";
import { buildKanbanRuntimeUrl, getKanbanRuntimeHost, getKanbanRuntimeOrigin, getKanbanRuntimePort, } from "../core/runtime-endpoint.js";
import { loadWorkspaceContextById } from "../state/workspace-state.js";
import { createTerminalWebSocketBridge } from "../terminal/ws-server.js";
import { runtimeAppRouter } from "../trpc/app-router.js";
import { createHooksApi } from "../trpc/hooks-api.js";
import { createProjectsApi } from "../trpc/projects-api.js";
import { createRuntimeApi } from "../trpc/runtime-api.js";
import { createWorkspaceApi } from "../trpc/workspace-api.js";
import { getWebUiDir, normalizeRequestPath, readAsset } from "./assets.js";
function readWorkspaceIdFromRequest(request, requestUrl) {
    const headerValue = request.headers["x-kanban-workspace-id"];
    const headerWorkspaceId = Array.isArray(headerValue) ? headerValue[0] : headerValue;
    if (typeof headerWorkspaceId === "string") {
        const normalized = headerWorkspaceId.trim();
        if (normalized) {
            return normalized;
        }
    }
    const queryWorkspaceId = requestUrl.searchParams.get("workspaceId");
    if (typeof queryWorkspaceId === "string") {
        const normalized = queryWorkspaceId.trim();
        if (normalized) {
            return normalized;
        }
    }
    return null;
}
export async function createRuntimeServer(deps) {
    const webUiDir = getWebUiDir();
    try {
        await readFile(join(webUiDir, "index.html"));
    }
    catch {
        throw new Error("Could not find web UI assets. Run `npm run build` to generate and package the web UI.");
    }
    const resolveWorkspaceScopeFromRequest = async (request, requestUrl) => {
        const requestedWorkspaceId = readWorkspaceIdFromRequest(request, requestUrl);
        if (!requestedWorkspaceId) {
            return {
                requestedWorkspaceId: null,
                workspaceScope: null,
            };
        }
        const requestedWorkspaceContext = await loadWorkspaceContextById(requestedWorkspaceId);
        if (!requestedWorkspaceContext) {
            return {
                requestedWorkspaceId,
                workspaceScope: null,
            };
        }
        return {
            requestedWorkspaceId,
            workspaceScope: {
                workspaceId: requestedWorkspaceContext.workspaceId,
                workspacePath: requestedWorkspaceContext.repoPath,
            },
        };
    };
    const getScopedTerminalManager = async (scope) => await deps.ensureTerminalManagerForWorkspace(scope.workspaceId, scope.workspacePath);
    const clineTaskSessionServiceByWorkspaceId = new Map();
    const getScopedClineTaskSessionService = async (scope) => {
        let service = clineTaskSessionServiceByWorkspaceId.get(scope.workspaceId);
        if (!service) {
            service = createInMemoryClineTaskSessionService();
            clineTaskSessionServiceByWorkspaceId.set(scope.workspaceId, service);
            deps.runtimeStateHub.trackClineTaskSessionService(scope.workspaceId, scope.workspacePath, service);
        }
        return service;
    };
    const disposeClineTaskSessionServiceAsync = async (workspaceId) => {
        const service = clineTaskSessionServiceByWorkspaceId.get(workspaceId);
        if (!service) {
            return;
        }
        clineTaskSessionServiceByWorkspaceId.delete(workspaceId);
        await service.dispose();
    };
    const disposeClineTaskSessionService = (workspaceId) => {
        void disposeClineTaskSessionServiceAsync(workspaceId);
    };
    const prepareForStateReset = async () => {
        const workspaceIds = new Set();
        for (const { workspaceId } of deps.workspaceRegistry.listManagedWorkspaces()) {
            workspaceIds.add(workspaceId);
        }
        for (const workspaceId of clineTaskSessionServiceByWorkspaceId.keys()) {
            workspaceIds.add(workspaceId);
        }
        const activeWorkspaceId = deps.workspaceRegistry.getActiveWorkspaceId();
        if (activeWorkspaceId) {
            workspaceIds.add(activeWorkspaceId);
        }
        for (const workspaceId of workspaceIds) {
            await disposeClineTaskSessionServiceAsync(workspaceId);
            deps.disposeWorkspace(workspaceId, {
                stopTerminalSessions: true,
            });
        }
        deps.workspaceRegistry.clearActiveWorkspace();
    };
    const createTrpcContext = async (req) => {
        const requestUrl = new URL(req.url ?? "/", "http://localhost");
        const scope = await resolveWorkspaceScopeFromRequest(req, requestUrl);
        return {
            requestedWorkspaceId: scope.requestedWorkspaceId,
            workspaceScope: scope.workspaceScope,
            runtimeApi: createRuntimeApi({
                getActiveWorkspaceId: deps.workspaceRegistry.getActiveWorkspaceId,
                getActiveRuntimeConfig: deps.workspaceRegistry.getActiveRuntimeConfig,
                loadScopedRuntimeConfig: deps.workspaceRegistry.loadScopedRuntimeConfig,
                setActiveRuntimeConfig: deps.workspaceRegistry.setActiveRuntimeConfig,
                getScopedTerminalManager,
                getScopedClineTaskSessionService,
                resolveInteractiveShellCommand: deps.resolveInteractiveShellCommand,
                runCommand: deps.runCommand,
                broadcastClineMcpAuthStatusesUpdated: deps.runtimeStateHub.broadcastClineMcpAuthStatusesUpdated,
                bumpClineSessionContextVersion: deps.runtimeStateHub.bumpClineSessionContextVersion,
                prepareForStateReset,
            }),
            workspaceApi: createWorkspaceApi({
                ensureTerminalManagerForWorkspace: deps.ensureTerminalManagerForWorkspace,
                getScopedClineTaskSessionService,
                broadcastRuntimeWorkspaceStateUpdated: deps.runtimeStateHub.broadcastRuntimeWorkspaceStateUpdated,
                broadcastRuntimeProjectsUpdated: deps.runtimeStateHub.broadcastRuntimeProjectsUpdated,
                buildWorkspaceStateSnapshot: deps.workspaceRegistry.buildWorkspaceStateSnapshot,
            }),
            projectsApi: createProjectsApi({
                getActiveWorkspacePath: deps.workspaceRegistry.getActiveWorkspacePath,
                getActiveWorkspaceId: deps.workspaceRegistry.getActiveWorkspaceId,
                rememberWorkspace: deps.workspaceRegistry.rememberWorkspace,
                setActiveWorkspace: deps.workspaceRegistry.setActiveWorkspace,
                clearActiveWorkspace: deps.workspaceRegistry.clearActiveWorkspace,
                resolveProjectInputPath: deps.resolveProjectInputPath,
                assertPathIsDirectory: deps.assertPathIsDirectory,
                hasGitRepository: deps.hasGitRepository,
                summarizeProjectTaskCounts: deps.workspaceRegistry.summarizeProjectTaskCounts,
                createProjectSummary: deps.workspaceRegistry.createProjectSummary,
                broadcastRuntimeProjectsUpdated: deps.runtimeStateHub.broadcastRuntimeProjectsUpdated,
                getTerminalManagerForWorkspace: deps.workspaceRegistry.getTerminalManagerForWorkspace,
                disposeWorkspace: (workspaceId, options) => {
                    disposeClineTaskSessionService(workspaceId);
                    return deps.disposeWorkspace(workspaceId, options);
                },
                collectProjectWorktreeTaskIdsForRemoval: deps.collectProjectWorktreeTaskIdsForRemoval,
                warn: deps.warn,
                buildProjectsPayload: deps.workspaceRegistry.buildProjectsPayload,
                pickDirectoryPathFromSystemDialog: deps.pickDirectoryPathFromSystemDialog,
            }),
            hooksApi: createHooksApi({
                getWorkspacePathById: deps.workspaceRegistry.getWorkspacePathById,
                ensureTerminalManagerForWorkspace: deps.ensureTerminalManagerForWorkspace,
                broadcastRuntimeWorkspaceStateUpdated: deps.runtimeStateHub.broadcastRuntimeWorkspaceStateUpdated,
                broadcastTaskReadyForReview: deps.runtimeStateHub.broadcastTaskReadyForReview,
            }),
        };
    };
    const trpcHttpHandler = createHTTPHandler({
        basePath: "/api/trpc/",
        router: runtimeAppRouter,
        createContext: async ({ req }) => await createTrpcContext(req),
    });
    const server = createServer(async (req, res) => {
        try {
            const requestUrl = new URL(req.url ?? "/", "http://localhost");
            const pathname = normalizeRequestPath(requestUrl.pathname);
            const oauthCallbackResponse = await handleClineMcpOauthCallback(requestUrl);
            if (oauthCallbackResponse) {
                res.writeHead(oauthCallbackResponse.statusCode, {
                    "Content-Type": "text/html; charset=utf-8",
                    "Cache-Control": "no-store",
                });
                res.end(oauthCallbackResponse.body);
                return;
            }
            if (pathname.startsWith("/api/trpc")) {
                await trpcHttpHandler(req, res);
                return;
            }
            if (pathname.startsWith("/api/")) {
                res.writeHead(404, { "Content-Type": "application/json; charset=utf-8" });
                res.end('{"error":"Not found"}');
                return;
            }
            const asset = await readAsset(webUiDir, pathname);
            res.writeHead(200, {
                "Content-Type": asset.contentType,
                "Cache-Control": "no-store",
            });
            res.end(asset.content);
        }
        catch {
            res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
            res.end("Not Found");
        }
    });
    server.on("upgrade", (request, socket, head) => {
        let requestUrl;
        try {
            requestUrl = new URL(request.url ?? "/", getKanbanRuntimeOrigin());
        }
        catch {
            socket.destroy();
            return;
        }
        if (normalizeRequestPath(requestUrl.pathname) !== "/api/runtime/ws") {
            return;
        }
        request.__kanbanUpgradeHandled = true;
        const requestedWorkspaceId = requestUrl.searchParams.get("workspaceId")?.trim() || null;
        deps.runtimeStateHub.handleUpgrade(request, socket, head, { requestedWorkspaceId });
    });
    const terminalWebSocketBridge = createTerminalWebSocketBridge({
        server,
        resolveTerminalManager: (workspaceId) => deps.workspaceRegistry.getTerminalManagerForWorkspace(workspaceId),
        isTerminalIoWebSocketPath: (pathname) => normalizeRequestPath(pathname) === "/api/terminal/io",
        isTerminalControlWebSocketPath: (pathname) => normalizeRequestPath(pathname) === "/api/terminal/control",
    });
    server.on("upgrade", (request, socket) => {
        const handled = request.__kanbanUpgradeHandled;
        if (handled) {
            return;
        }
        socket.destroy();
    });
    await new Promise((resolveListen, rejectListen) => {
        server.once("error", rejectListen);
        server.listen(getKanbanRuntimePort(), getKanbanRuntimeHost(), () => {
            server.off("error", rejectListen);
            resolveListen();
        });
    });
    const address = server.address();
    if (!address || typeof address === "string") {
        throw new Error("Failed to start local server.");
    }
    const activeWorkspaceId = deps.workspaceRegistry.getActiveWorkspaceId();
    const url = activeWorkspaceId
        ? buildKanbanRuntimeUrl(`/${encodeURIComponent(activeWorkspaceId)}`)
        : getKanbanRuntimeOrigin();
    return {
        url,
        close: async () => {
            await Promise.all(Array.from(clineTaskSessionServiceByWorkspaceId.values()).map(async (service) => {
                await service.dispose();
            }));
            clineTaskSessionServiceByWorkspaceId.clear();
            await deps.runtimeStateHub.close();
            await terminalWebSocketBridge.close();
            await new Promise((resolveClose, rejectClose) => {
                server.close((error) => {
                    if (error) {
                        rejectClose(error);
                        return;
                    }
                    resolveClose();
                });
            });
        },
    };
}
//# sourceMappingURL=runtime-server.js.map
//# debugId=1e85d434-192d-5fd0-b8c7-6512d5a31963
