/** Public API snapshot — fail loud on unintended changes to the npm package's export surface. */

import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";

const INDEX = readFileSync(join(process.cwd(), "src/index.ts"), "utf8");

function extractExportedNames(source: string): string[] {
  const names = new Set<string>();
  // Strip block comments + line comments so commented-out exports don't count.
  const cleaned = source
    .replace(/\/\*[\s\S]*?\*\//g, "")
    .split("\n")
    .map((l) => l.replace(/\/\/.*$/, ""))
    .join("\n");

  // `export { a, b as c, type D, type E as F } from "..."` — including bare `export { ... }` with no `from`.
  const namedBlock = /export(?:\s+type)?\s*\{([^}]+)\}\s*(?:from\s+["'][^"']+["'])?\s*;?/g;
  for (const m of cleaned.matchAll(namedBlock)) {
    const inner = m[1] ?? "";
    for (const raw of inner.split(",")) {
      const trimmed = raw.trim().replace(/^type\s+/, "");
      if (!trimmed) continue;
      const aliasMatch = trimmed.match(/(?:.+\s+as\s+)?(\w+)\s*$/);
      if (aliasMatch?.[1]) names.add(aliasMatch[1]);
    }
  }

  // `export const X`, `export function X`, `export class X`, `export type X`, `export interface X`, `export enum X`.
  const decl =
    /export\s+(?:async\s+)?(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/g;
  for (const m of cleaned.matchAll(decl)) {
    if (m[1]) names.add(m[1]);
  }

  return [...names].sort();
}

const PUBLIC_API: readonly string[] = [
  "AT_MENTION_PATTERN",
  "AT_PICKER_PREFIX",
  "AggregateOptions",
  "AppendOnlyLog",
  "AppendUsageInput",
  "ApplyResult",
  "ApplyStatus",
  "AtMentionExpansion",
  "AtMentionOptions",
  "BridgeOptions",
  "BridgeResult",
  "CODE_SYSTEM_PROMPT",
  "CacheFirstLoop",
  "CacheFirstLoopOptions",
  "CallToolResult",
  "CarbonCodeConfig",
  "ChatMessage",
  "ChatResponse",
  "ChoiceOption",
  "ChoiceRequestedError",
  "ChoiceToolOptions",
  "CodeSystemPromptOptions",
  "DEFAULT_AT_DIR_MAX_ENTRIES",
  "DEFAULT_AT_MENTION_MAX_BYTES",
  "DEFAULT_MAX_RESULT_CHARS",
  "DEFAULT_MAX_RESULT_TOKENS",
  "DEFAULT_PICKER_IGNORE_DIRS",
  "DEFAULT_SPAWN_STORM_THRESHOLD",
  "DeepSeekClient",
  "DeepSeekClientOptions",
  "DiffRenderOptions",
  "DiffReport",
  "DiffSide",
  "DirEntry",
  "EditBlock",
  "EditSnapshot",
  "EventRole",
  "FileWithStats",
  "FilesystemToolsOptions",
  "FlattenDecision",
  "FlattenOptions",
  "GetLatestVersionOptions",
  "GetPromptResult",
  "HOOK_EVENTS",
  "HOOK_SETTINGS_DIRNAME",
  "HOOK_SETTINGS_FILENAME",
  "HookConfig",
  "HookEvent",
  "HookOutcome",
  "HookPayload",
  "HookReport",
  "HookScope",
  "HookSettings",
  "HookSpawnInput",
  "HookSpawnResult",
  "HookSpawner",
  "ImmutablePrefix",
  "ImmutablePrefixOptions",
  "InitializeResult",
  "InspectionReport",
  "InstallSource",
  "JSONSchema",
  "JsonRpcMessage",
  "JsonRpcRequest",
  "JsonRpcResponse",
  "LATEST_CACHE_TTL_MS",
  "LATEST_FETCH_TIMEOUT_MS",
  "ListDirectoryOptions",
  "ListFilesOptions",
  "ListPromptsResult",
  "ListResourcesResult",
  "ListToolsResult",
  "LoadHookSettingsOptions",
  "LoopEvent",
  "MCP_PROTOCOL_VERSION",
  "MEMORY_INDEX_FILE",
  "MEMORY_INDEX_MAX_CHARS",
  "McpClient",
  "McpClientOptions",
  "McpContentBlock",
  "McpProgressHandler",
  "McpProgressInfo",
  "McpPrompt",
  "McpPromptArgument",
  "McpPromptMessage",
  "McpPromptResourceBlock",
  "McpResource",
  "McpResourceContents",
  "McpResourceContentsBlob",
  "McpResourceContentsText",
  "McpSpec",
  "McpTool",
  "McpToolSchema",
  "McpTransport",
  "MemoryEntry",
  "MemoryScope",
  "MemoryStore",
  "MemoryStoreOptions",
  "MemoryToolsOptions",
  "MemoryType",
  "MemoryWriteInput",
  "NeedsConfirmationError",
  "PROJECT_MEMORY_FILE",
  "PROJECT_MEMORY_FILES",
  "PROJECT_MEMORY_MAX_CHARS",
  "PageContent",
  "ParsedAtQuery",
  "PickerCandidate",
  "PlanProposedError",
  "PlanRevisionProposedError",
  "PlanStep",
  "PlanStepRisk",
  "PlanToolOptions",
  "ProgressNotificationParams",
  "ProjectMemory",
  "RankPickerOptions",
  "ReadResourceResult",
  "ReadTranscriptResult",
  "ReasonixConfig",
  "ReconfigurableOptions",
  "RepairReport",
  "ReplayStats",
  "ResolvedHook",
  "RetryInfo",
  "RetryOptions",
  "Role",
  "RunCommandResult",
  "RunHooksOptions",
  "ScavengeOptions",
  "ScavengeResult",
  "SearchResult",
  "SectionResult",
  "SessionInfo",
  "SessionStats",
  "SessionSummary",
  "ShellToolsOptions",
  "SpawnDistillation",
  "SseMcpSpec",
  "SseTransport",
  "SseTransportOptions",
  "StdioMcpSpec",
  "StdioTransport",
  "StdioTransportOptions",
  "StepCompletion",
  "StormBreaker",
  "StreamChunk",
  "StreamWalkOptions",
  "StreamableHttpMcpSpec",
  "StreamableHttpTransport",
  "StreamableHttpTransportOptions",
  "SubagentEvent",
  "SubagentResult",
  "SubagentResultLike",
  "SubagentSessionSummary",
  "SubagentSink",
  "SubagentTelemetry",
  "SubagentToolOptions",
  "TodoItem",
  "TodoStatus",
  "TodoToolOptions",
  "ToolCall",
  "ToolCallContext",
  "ToolCallRepair",
  "ToolCallRepairOptions",
  "ToolDefinition",
  "ToolFunctionSpec",
  "ToolRegistry",
  "ToolSpec",
  "TranscriptMeta",
  "TranscriptRecord",
  "TruncationRepairResult",
  "TurnPair",
  "TurnStats",
  "USER_MEMORY_DIR",
  "Usage",
  "UsageAggregate",
  "UsageBucket",
  "UsageRecord",
  "VERSION",
  "VolatileScratch",
  "WebFetchOptions",
  "WebSearchOptions",
  "WebToolsOptions",
  "aggregateUsage",
  "analyzeSchema",
  "appendSessionMessage",
  "appendUsage",
  "applyEditBlock",
  "applyEditBlocks",
  "applyMemoryStack",
  "applyProjectMemory",
  "applyUserMemory",
  "bridgeMcpTools",
  "bucketCacheHitRatio",
  "bucketSavingsFraction",
  "claudeEquivalentCost",
  "codeSystemPrompt",
  "compareVersions",
  "computeReplayStats",
  "computeSpawnDistillation",
  "costUsd",
  "countSpawnStorms",
  "decideOutcome",
  "defaultConfigPath",
  "defaultUsageLogPath",
  "deleteSession",
  "detectAtPicker",
  "detectInstallSource",
  "detectNpmInstallPrefix",
  "detectShellOperator",
  "diffTranscripts",
  "expandAtMentions",
  "fetchWithRetry",
  "findProjectMemoryPath",
  "fixToolCallPairing",
  "flattenMcpResult",
  "flattenSchema",
  "forkRegistryExcluding",
  "formatCommandResult",
  "formatHookOutcomeMessage",
  "formatLogSize",
  "formatLoopError",
  "formatSearchResults",
  "getLatestVersion",
  "globalSettingsPath",
  "healLoadedMessages",
  "healLoadedMessagesByTokens",
  "htmlToText",
  "injectPowerShellUtf8",
  "inputCostUsd",
  "inspectMcpServer",
  "isAllowed",
  "isJsonRpcError",
  "isNpxInstall",
  "isPlausibleKey",
  "listDirectory",
  "listFilesSync",
  "listFilesWithStatsAsync",
  "listFilesWithStatsSync",
  "listSessions",
  "loadApiKey",
  "loadBaseUrl",
  "loadDotenv",
  "loadHooks",
  "loadMetasoApiKey",
  "loadSessionMessages",
  "matchesTool",
  "memoryEnabled",
  "nestArguments",
  "openTranscriptFile",
  "outputCostUsd",
  "parseAtQuery",
  "parseEditBlocks",
  "parseMcpSpec",
  "parseMojeekResults",
  "parseSearxngHtmlResults",
  "parseTranscript",
  "prepareSpawn",
  "projectHash",
  "projectSettingsPath",
  "quoteForCmdExe",
  "rankPickerCandidates",
  "readConfig",
  "readProjectMemory",
  "readTranscript",
  "readUsageLog",
  "recordFromLoopEvent",
  "redactKey",
  "registerChoiceTool",
  "registerFilesystemTools",
  "registerMemoryTools",
  "registerPlanTool",
  "registerShellTools",
  "registerSubagentTool",
  "registerTodoTool",
  "registerWebTools",
  "renderDiffMarkdown",
  "renderDiffSummary",
  "repairTruncatedJson",
  "replayFromFile",
  "resolveExecutable",
  "resolveProjectMemoryWritePath",
  "restoreSnapshots",
  "runCommand",
  "runHooks",
  "sanitizeMemoryName",
  "sanitizeSessionName",
  "saveApiKey",
  "saveBaseUrl",
  "scavengeToolCalls",
  "sessionPath",
  "sessionsDir",
  "similarity",
  "snapshotBeforeEdits",
  "stripHallucinatedToolMarkup",
  "summarizeSubagentSession",
  "tokenizeCommand",
  "truncateForModel",
  "truncateForModelByTokens",
  "walkFilesStream",
  "webFetch",
  "webSearch",
  "withUtf8Codepage",
  "writeConfig",
  "writeMeta",
  "writeRecord",
];

describe("public API surface", () => {
  it("brands the library entry point as Carbon Code", () => {
    expect(INDEX).toContain("Carbon Code — DeepSeek-native coding agent framework");
    expect(INDEX).not.toContain("Reasonix — DeepSeek-native agent framework");
  });

  it("matches the recorded snapshot — update PUBLIC_API in this file when intentionally changing exports", () => {
    const actual = extractExportedNames(INDEX);
    expect(actual).toEqual([...PUBLIC_API]);
  });

  it("snapshot is sorted + unique (sanity check on the snapshot itself)", () => {
    const sorted = [...PUBLIC_API].sort();
    expect([...PUBLIC_API]).toEqual(sorted);
    expect(new Set(PUBLIC_API).size).toBe(PUBLIC_API.length);
  });
});
