// src/application/mcp/common.ts
import { PresentationRegistry } from "@contractspec/lib.contracts-spec/presentations";
import { createMcpServer } from "@contractspec/lib.contracts-runtime-server-mcp/provider-mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
import { Elysia } from "elysia";
import { randomUUID } from "node:crypto";
var baseCtx = {
  actor: "anonymous",
  decide: async () => ({ effect: "allow" })
};
function createJsonRpcErrorResponse(status, code, message, data) {
  return new Response(JSON.stringify({
    jsonrpc: "2.0",
    error: {
      code,
      message,
      ...data ? { data } : {}
    },
    id: null
  }), {
    status,
    headers: {
      "content-type": "application/json"
    }
  });
}
function createSessionState({
  logger,
  serverName,
  ops,
  resources,
  prompts,
  presentations,
  stateful
}) {
  const server = new McpServer({
    name: serverName,
    version: "1.0.0"
  }, {
    capabilities: {
      tools: {},
      resources: {},
      prompts: {},
      logging: {}
    }
  });
  logger.info("Setting up MCP server...");
  createMcpServer(server, ops, resources, prompts, {
    logger,
    toolCtx: () => baseCtx,
    promptCtx: () => ({ locale: "en" }),
    resourceCtx: () => ({ locale: "en" }),
    presentations: new PresentationRegistry(presentations)
  });
  const transport = new WebStandardStreamableHTTPServerTransport({
    sessionIdGenerator: stateful ? () => randomUUID() : undefined,
    enableJsonResponse: true
  });
  return server.connect(transport).then(() => ({ server, transport }));
}
async function closeSessionState(state) {
  await Promise.allSettled([state.transport.close(), state.server.close()]);
}
function toErrorMessage(error) {
  return error instanceof Error ? error.stack ?? error.message : String(error);
}
function createMcpElysiaHandler({
  logger,
  path,
  serverName,
  ops,
  resources,
  prompts,
  presentations,
  validateAuth,
  requiredAuthMethods
}) {
  logger.info("Setting up MCP handler...", {
    requiredAuthMethods: requiredAuthMethods ?? []
  });
  const isStateful = process.env.CONTRACTSPEC_MCP_STATEFUL === "1";
  const sessions = new Map;
  async function handleStateless(request) {
    const state = await createSessionState({
      logger,
      path,
      serverName,
      ops,
      resources,
      prompts,
      presentations,
      stateful: false
    });
    try {
      return await state.transport.handleRequest(request);
    } finally {
      await closeSessionState(state);
    }
  }
  async function closeSession(sessionId) {
    const state = sessions.get(sessionId);
    if (!state)
      return;
    sessions.delete(sessionId);
    await closeSessionState(state);
  }
  async function handleStateful(request) {
    const requestedSessionId = request.headers.get("mcp-session-id");
    let state;
    let createdState = false;
    if (requestedSessionId) {
      const existing = sessions.get(requestedSessionId);
      if (!existing) {
        return createJsonRpcErrorResponse(404, -32001, "Session not found");
      }
      state = existing;
    } else {
      state = await createSessionState({
        logger,
        path,
        serverName,
        ops,
        resources,
        prompts,
        presentations,
        stateful: true
      });
      createdState = true;
    }
    try {
      const response = await state.transport.handleRequest(request);
      const activeSessionId = state.transport.sessionId;
      if (activeSessionId && !sessions.has(activeSessionId)) {
        sessions.set(activeSessionId, state);
      }
      if (request.method === "DELETE" && activeSessionId) {
        await closeSession(activeSessionId);
      } else if (!activeSessionId && createdState) {
        await closeSessionState(state);
      }
      return response;
    } catch (error) {
      if (createdState) {
        await closeSessionState(state);
      }
      throw error;
    }
  }
  return new Elysia({ name: `mcp-${serverName}` }).all(path, async ({ request }) => {
    try {
      if (validateAuth) {
        const authResult = await validateAuth(request);
        if (!authResult.valid) {
          return createJsonRpcErrorResponse(401, -32002, "Authentication failed", authResult.reason);
        }
      }
      if (isStateful) {
        return await handleStateful(request);
      }
      return await handleStateless(request);
    } catch (error) {
      logger.error("Error handling MCP request", {
        path,
        method: request.method,
        error: toErrorMessage(error)
      });
      return createJsonRpcErrorResponse(500, -32000, "Internal error");
    }
  });
}

// src/infrastructure/elysia/logger.ts
import { Logger, LogLevel } from "@contractspec/lib.logger";
var createAppLogger = () => new Logger({
  level: LogLevel.INFO,
  environment: "production",
  enableTracing: true,
  enableTiming: true,
  enableContext: true,
  enableColors: false
});
var appLogger = createAppLogger();
var dbLogger = new Logger({
  level: LogLevel.WARN,
  environment: "production",
  enableTracing: true,
  enableTiming: true,
  enableContext: true,
  enableColors: false
});
var authLogger = new Logger({
  level: LogLevel.INFO,
  environment: "production",
  enableTracing: true,
  enableTiming: true,
  enableContext: true,
  enableColors: false
});
// src/application/mcp/cliMcp.ts
import fs from "node:fs/promises";
import path from "path";
import {
  defineCommand,
  definePrompt,
  defineResourceTemplate,
  installOp,
  OperationSpecRegistry,
  PromptRegistry,
  ResourceRegistry
} from "@contractspec/lib.contracts-spec";
import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
import z from "zod";
var __dirname = "/home/runner/work/contractspec/contractspec/packages/bundles/library/src/application/mcp";
var CLI_DOC_PATHS = {
  quickstart: "packages/apps/cli-contractspec/QUICK_START.md",
  reference: "packages/apps/cli-contractspec/QUICK_REFERENCE.md",
  readme: "packages/apps/cli-contractspec/README.md"
};
var CLI_DOC_FALLBACK = {
  quickstart: `# ContractSpec CLI quickstart

contractspec create
contractspec build <spec>
contractspec validate <spec>`,
  reference: `# ContractSpec CLI reference

Key commands: create, build, validate. See README for full options.`,
  readme: `# ContractSpec CLI

Stabilize AI-generated code across API, DB, UI, events. Use create/build/validate commands.`
};
var CLI_DOC_TAGS = ["cli", "mcp"];
var CLI_OWNERS = ["@contractspec"];
var candidateRoots = (() => {
  const roots = new Set([
    process.cwd(),
    path.resolve(process.cwd(), ".."),
    path.resolve(process.cwd(), "../.."),
    path.resolve(process.cwd(), "../../..")
  ]);
  if (typeof __dirname === "string") {
    roots.add(path.resolve(__dirname, "../../../../.."));
  }
  return [...roots];
})();
var docCache = new Map;
async function loadCliDoc(key) {
  if (docCache.has(key)) {
    return docCache.get(key);
  }
  const relative = CLI_DOC_PATHS[key];
  for (const root of candidateRoots) {
    const candidate = path.resolve(root, relative);
    try {
      const data = await fs.readFile(candidate, "utf8");
      docCache.set(key, data);
      return data;
    } catch {}
  }
  const fallback = CLI_DOC_FALLBACK[key];
  docCache.set(key, fallback);
  return fallback;
}
function buildCliResources() {
  const resources = new ResourceRegistry;
  resources.register(defineResourceTemplate({
    meta: {
      uriTemplate: "cli://doc/{slug}",
      title: "CLI documentation",
      description: "Quickstart, reference, and README for the CLI.",
      mimeType: "text/markdown",
      tags: CLI_DOC_TAGS
    },
    input: z.object({
      slug: z.enum(["quickstart", "reference", "readme"])
    }),
    resolve: async ({ slug }) => {
      const data = await loadCliDoc(slug);
      return {
        uri: `cli://doc/${slug}`,
        mimeType: "text/markdown",
        data
      };
    }
  }));
  resources.register(defineResourceTemplate({
    meta: {
      uriTemplate: "cli://commands",
      title: "CLI commands summary",
      description: "Key ContractSpec CLI commands and when to use them.",
      mimeType: "application/json",
      tags: CLI_DOC_TAGS
    },
    input: z.object({}),
    resolve: async () => {
      const commands = [
        {
          command: "contractspec create",
          summary: "Interactive wizard to author specs (with optional AI).",
          doc: "cli://doc/quickstart"
        },
        {
          command: "contractspec build <specPath>",
          summary: "Generate implementation code from a ContractSpec (agents + templates).",
          doc: "cli://doc/reference"
        },
        {
          command: "contractspec validate <specPath>",
          summary: "Validate specs and optionally check implementations against them.",
          doc: "cli://doc/reference"
        }
      ];
      return {
        uri: "cli://commands",
        mimeType: "application/json",
        data: JSON.stringify(commands, null, 2)
      };
    }
  }));
  return resources;
}
function buildCliPrompts() {
  const prompts = new PromptRegistry;
  prompts.register(definePrompt({
    meta: {
      key: "cli.usage",
      version: "1.0.0",
      title: "Use ContractSpec CLI safely",
      description: "Remind agents to read CLI docs and pick commands from the canonical list.",
      tags: CLI_DOC_TAGS,
      stability: "beta",
      owners: CLI_OWNERS
    },
    args: [
      {
        name: "goal",
        description: "Task the user wants to achieve.",
        required: false,
        schema: z.string().optional()
      }
    ],
    input: z.object({ goal: z.string().optional() }),
    render: async ({ goal }) => [
      {
        type: "text",
        text: `Use CLI commands only from cli://commands. Prefer quickstart for newcomers and reference for options.${goal ? ` Goal: ${goal}.` : ""}`
      },
      { type: "resource", uri: "cli://commands", title: "Commands" },
      {
        type: "resource",
        uri: "cli://doc/quickstart",
        title: "Quickstart"
      }
    ]
  }));
  return prompts;
}
function buildCliOps() {
  const registry = new OperationSpecRegistry;
  const CliSuggestInput = defineSchemaModel({
    name: "CliSuggestInput",
    fields: {
      goal: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
      prefersAi: { type: ScalarTypeEnum.Boolean(), isOptional: true }
    }
  });
  const CliSuggestOutput = defineSchemaModel({
    name: "CliSuggestOutput",
    fields: {
      command: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
      docUri: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
      reason: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
    }
  });
  const suggestSpec = defineCommand({
    meta: {
      key: "cli.suggestCommand",
      version: "1.0.0",
      stability: "stable",
      owners: CLI_OWNERS,
      tags: CLI_DOC_TAGS,
      description: "Recommend a CLI command for the requested goal.",
      goal: "Help AI agents choose the correct CLI entrypoint quickly.",
      context: "Used inside the CLI MCP server."
    },
    io: {
      input: CliSuggestInput,
      output: CliSuggestOutput
    },
    policy: {
      auth: "anonymous"
    }
  });
  installOp(registry, suggestSpec, async ({ goal, prefersAi }) => {
    const lower = goal.toLowerCase();
    if (lower.includes("create") || lower.includes("new")) {
      return {
        command: prefersAi ? "contractspec create --ai" : "contractspec create",
        docUri: "cli://doc/quickstart",
        reason: "Creates a new ContractSpec interactively (optionally with AI)."
      };
    }
    if (lower.includes("build") || lower.includes("generate")) {
      return {
        command: "contractspec build <path-to-spec>",
        docUri: "cli://doc/reference",
        reason: "Builds implementation code from a spec using agents + templates."
      };
    }
    if (lower.includes("validate") || lower.includes("check")) {
      return {
        command: "contractspec validate <path-to-spec>",
        docUri: "cli://doc/reference",
        reason: "Validates a spec and optionally checks its implementation for drift."
      };
    }
    return {
      command: "contractspec --help",
      docUri: "cli://doc/readme",
      reason: "Fallback when the goal is unclear; read README for options."
    };
  });
  return registry;
}
function createCliMcpHandler(path2 = "/api/mcp/cli") {
  return createMcpElysiaHandler({
    logger: appLogger,
    path: path2,
    serverName: "contractspec-cli-mcp",
    ops: buildCliOps(),
    resources: buildCliResources(),
    prompts: buildCliPrompts()
  });
}
export {
  createCliMcpHandler
};
