@clarify-labs/cli 0.11.2 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/output/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../source/core/runtime/log.ts","../source/core/runtime/vite-config.ts","../source/cli/commands/build.ts","../source/cli/commands/check.ts","../source/cli/commands/dev.ts","../source/cli/spawn.ts","../source/cli/commands/init.ts","../source/cli/mcp/orama-loader.ts","../source/cli/mcp/search-server.ts","../source/cli/commands/mcp.ts","../source/cli/options.ts","../source/cli/program.ts","../source/cli/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\nconst LOG_FILE_NAME = '.clarify.log'\nconst DEFAULT_LOG_ENTRIES = 50\nconst ENTRY_SEPARATOR = '\\n\\n---\\n\\n'\n\nfunction getMaxLogEntries(): number {\n const envValue = process.env.CLARIFY_LOG_MAX_ENTRIES\n if (!envValue) return DEFAULT_LOG_ENTRIES\n const parsed = Number(envValue)\n return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_LOG_ENTRIES\n}\n\nfunction normalizeErrorMessage(error: unknown): string {\n if (error === undefined) return 'undefined'\n if (error === null) return 'null'\n if (error instanceof Error) return error.message\n if (typeof error === 'object') {\n if ('message' in error && typeof (error as { message?: unknown }).message === 'string') {\n return (error as { message: string }).message\n }\n try {\n return JSON.stringify(error)\n } catch {\n return String(error)\n }\n }\n return String(error)\n}\n\nfunction normalizeErrorStack(error: unknown): string | undefined {\n if (error instanceof Error) {\n return error.stack\n }\n return undefined\n}\n\nfunction formatLogEntry(root: string, error: unknown): string {\n const timestamp = new Date().toISOString()\n const message = normalizeErrorMessage(error)\n const stack = normalizeErrorStack(error)\n\n return [`=== Clarify build error ===`, `Timestamp: ${timestamp}`, `Project root: ${root}`, `Error: ${message}`, stack ? `Stack:\\n${stack}` : undefined]\n .filter(Boolean)\n .join('\\n')\n}\n\ntype LogEntryReader = (logPath: string) => Promise<string> | string\ntype LogEntryWriter = (logPath: string, content: string) => Promise<void> | void\n\nfunction collectLogEntries(entries: string[], entry: string, max: number): string[] {\n const next = [...entries, entry]\n return next.length > max ? next.slice(-max) : next\n}\n\nfunction readExistingEntries(content: string): string[] {\n return content\n .split(ENTRY_SEPARATOR)\n .map((item) => item.trim())\n .filter(Boolean)\n}\n\nasync function writeLogEntry(root: string, error: unknown, maxEntries: number | undefined, read: LogEntryReader, write: LogEntryWriter): Promise<void> {\n const logPath = join(root, LOG_FILE_NAME)\n const entry = formatLogEntry(root, error)\n const max = maxEntries ?? getMaxLogEntries()\n\n let entries: string[] = []\n if (existsSync(logPath)) {\n try {\n entries = readExistingEntries(await read(logPath))\n } catch {\n entries = []\n }\n }\n\n entries = collectLogEntries(entries, entry, max)\n\n mkdirSync(dirname(logPath), { recursive: true })\n await write(logPath, entries.join(ENTRY_SEPARATOR) + '\\n')\n}\n\nexport async function logBuildError(root: string, error: unknown, maxEntries?: number): Promise<void> {\n await writeLogEntry(root, error, maxEntries, (path) => readFile(path, 'utf8'), (path, content) => writeFile(path, content, 'utf8'))\n}\n\nexport function logBuildErrorSync(root: string, error: unknown, maxEntries?: number): void {\n void writeLogEntry(root, error, maxEntries, (path) => readFileSync(path, 'utf8'), (path, content) => writeFileSync(path, content, 'utf8'))\n}\n","import { existsSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport { createLogger } from 'vite'\nimport type { ConfigEnv, InlineConfig, Plugin, LogLevel, Logger, LogOptions, LogErrorOptions, LogType } from 'vite'\n\nimport { createViteAdapter } from '../adapters.js'\nimport type { ClarifyEngine } from '../engine/engine.js'\nimport { createClarifyTempDir } from '../project/temp-dir.js'\n\nimport { logBuildErrorSync } from './log.js'\nimport { createClarifyRuntimeAliases } from './runtime-deps.js'\n\nexport type ClarifyViteConfigOptions = {\n root: string\n content: string\n output: string\n host?: string | boolean\n port?: number\n open?: boolean | string\n}\n\nconst DEFAULT_HTML = '<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><title>Clarify</title></head><body><div id=\"root\"></div></body></html>'\n\nfunction ensureHtmlEntry(root: string): string {\n const projectHtmlPath = resolve(root, 'index.html')\n if (existsSync(projectHtmlPath)) return projectHtmlPath\n\n const generatedHtmlPath = resolve(createClarifyTempDir('html'), 'index.html')\n writeFileSync(generatedHtmlPath, DEFAULT_HTML, 'utf-8')\n return generatedHtmlPath\n}\n\nfunction createClarifyLogger(root: string, env: ConfigEnv, level: LogLevel): Logger | undefined {\n if (env.command !== 'build') return undefined\n\n const baseLogger = createLogger(level, { allowClearScreen: true })\n\n return {\n info(msg: string, options?: LogOptions) {\n baseLogger.info(msg, options)\n },\n warn(msg: string, options?: LogOptions) {\n baseLogger.warn(msg, options)\n },\n warnOnce(msg: string, options?: LogOptions) {\n baseLogger.warnOnce(msg, options)\n },\n error(msg: string, options?: LogErrorOptions) {\n baseLogger.error(msg, options)\n if (options?.error) {\n logBuildErrorSync(root, options.error)\n } else {\n logBuildErrorSync(root, typeof msg === 'string' ? new Error(msg) : msg)\n }\n },\n clearScreen(type: LogType) {\n baseLogger.clearScreen(type)\n },\n hasErrorLogged(error: Error | unknown) {\n return baseLogger.hasErrorLogged(error as Error)\n },\n get hasWarned() {\n return baseLogger.hasWarned\n },\n }\n}\n\nfunction createHtmlFallbackPlugin(): Plugin {\n return {\n name: 'clarify:cli-html-fallback',\n configureServer(server) {\n server.middlewares.use(async (req, res, next) => {\n const requestPath = req.url?.split('?')[0] ?? '/'\n const acceptsHtml = req.headers.accept?.includes('text/html') ?? false\n const hasFileExtension = /\\.[^/]+$/.test(requestPath)\n if (!acceptsHtml || hasFileExtension) {\n next()\n return\n }\n\n try {\n const html = await server.transformIndexHtml(requestPath, DEFAULT_HTML)\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n res.end(html)\n } catch (error) {\n next(error)\n }\n })\n },\n }\n}\n\nexport async function createViteConfig(options: ClarifyViteConfigOptions, env: ConfigEnv, engine: ClarifyEngine): Promise<InlineConfig> {\n const entryHtmlPath = ensureHtmlEntry(options.root)\n\n return {\n root: options.root,\n configFile: false,\n appType: 'custom',\n resolve: {\n alias: createClarifyRuntimeAliases(),\n },\n customLogger: createClarifyLogger(options.root, env, 'info'),\n plugins: [\n createViteAdapter(engine),\n createHtmlFallbackPlugin(),\n ],\n server: {\n host: options.host,\n port: options.port,\n open: options.open,\n },\n build: {\n outDir: options.output,\n rolldownOptions: {\n input: {\n index: entryHtmlPath,\n },\n checks: {\n pluginTimings: false,\n },\n output: {\n codeSplitting: {\n groups: [\n {\n name: 'react-vendor',\n test: /node_modules[\\\\/](react|react-dom|react-router|react-router-dom)[\\\\/]/,\n priority: 40,\n },\n {\n name: 'icons-vendor',\n test: /node_modules[\\\\/]lucide-react[\\\\/]/,\n priority: 35,\n },\n {\n name: 'ui-vendor',\n test: /node_modules[\\\\/](@headlessui|framer-motion)[\\\\/]/,\n priority: 30,\n },\n {\n name: 'mermaid-viewer-vendor',\n test: /node_modules[\\\\/]react-zoom-pan-pinch[\\\\/]/,\n priority: 25,\n },\n {\n // Keep mermaid and its heavy diagram/render dependencies out of\n // the eager `vendor` chunk so they stay lazily loaded only on\n // pages that actually render a diagram.\n name: 'mermaid-vendor',\n test: /node_modules[\\\\/](mermaid|@mermaid-js|cytoscape|cytoscape-[^\\\\/]+|dagre-d3-es|@dagrejs|dagre|graphlib|elkjs|katex|d3|d3-[^\\\\/]+|internmap|delaunator|robust-predicates|roughjs|points-on-curve|points-on-path|path-data-parser|@braintree[\\\\/]sanitize-url|dompurify|khroma|ts-dedent|stylis|cose-base|layout-base)[\\\\/]/,\n priority: 20,\n },\n {\n name: 'vendor',\n test: /node_modules[\\\\/]/,\n priority: 10\n },\n ],\n },\n },\n },\n },\n }\n}\n","import { build as viteBuild } from 'vite'\n\nimport { createClarifyEngine } from '../../core/engine/engine.js'\nimport { logBuildError } from '../../core/runtime/log.js'\nimport { createViteConfig } from '../../core/runtime/vite-config.js'\nimport type { ResolvedCliOptions } from '../options.js'\n\nexport async function runBuild(options: ResolvedCliOptions): Promise<void> {\n const env = { command: 'build' as const, mode: 'production' }\n const engine = createClarifyEngine({\n projectRoot: options.root,\n rootDirectory: options.content,\n outputDirectory: options.output,\n })\n try {\n await engine.prepare(env)\n await viteBuild(await createViteConfig(options, env, engine))\n } catch (error) {\n await logBuildError(options.root, error)\n throw error\n }\n}\n","import { lstat, stat } from 'node:fs/promises'\nimport { dirname, extname, isAbsolute, join, normalize, relative, resolve } from 'node:path'\n\nimport { createClarifyEngine } from '../../core/engine/engine.js'\nimport type { ContentRoute } from '../../types.js'\nimport type { CliOptions } from '../options.js'\n\nexport type CheckCommandOptions = CliOptions & {\n strict?: boolean\n format?: 'text' | 'json' | string\n}\n\ntype CheckLevel = 'error' | 'warning'\n\ntype CheckDiagnostic = {\n level: CheckLevel\n code: string\n message: string\n filePath?: string\n routePath?: string\n}\n\ntype CheckResult = {\n errors: CheckDiagnostic[]\n warnings: CheckDiagnostic[]\n}\n\nconst LOCAL_LINK_PATTERN = /(?<!!)(?:\\[[^\\]]*\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)|<a\\s+[^>]*href=[\"']([^\"']+)[\"'])/gi\nconst ROUTE_EXTENSIONS = new Set(['.md', '.mdx'])\nconst IGNORED_SCHEMES = /^[a-z][a-z0-9+.-]*:/i\n\nfunction addDiagnostic(result: CheckResult, diagnostic: CheckDiagnostic): void {\n if (diagnostic.level === 'error') result.errors.push(diagnostic)\n else result.warnings.push(diagnostic)\n}\n\nfunction normalizeRoutePath(path: string): string {\n const [withoutHash] = path.split('#')\n const clean = withoutHash.replace(/\\/index$/, '') || '/'\n return clean.startsWith('/') ? clean : `/${clean}`\n}\n\nfunction routePathCandidates(href: string, route: ContentRoute): string[] {\n const [withoutHashOrQuery] = href.split(/[?#]/)\n if (!withoutHashOrQuery || withoutHashOrQuery.startsWith('#')) return []\n if (withoutHashOrQuery.startsWith('/')) return [normalizeRoutePath(withoutHashOrQuery)]\n\n const routeDir = dirname(route.path)\n const joined = normalize(join(routeDir, withoutHashOrQuery)).replaceAll('\\\\', '/')\n const extension = extname(joined)\n const base = ROUTE_EXTENSIONS.has(extension) ? joined.slice(0, -extension.length) : joined\n return [normalizeRoutePath(base)]\n}\n\nasync function pathExists(filePath: string): Promise<boolean> {\n try {\n await stat(filePath)\n return true\n } catch {\n return false\n }\n}\n\nfunction isLocalHref(href: string): boolean {\n return Boolean(href) && !href.startsWith('#') && !href.startsWith('//') && !IGNORED_SCHEMES.test(href)\n}\n\nasync function resolveLocalFileLink(href: string, route: ContentRoute, contentRoot: string): Promise<boolean> {\n const [withoutHashOrQuery] = href.split(/[?#]/)\n if (!withoutHashOrQuery || withoutHashOrQuery.startsWith('/')) return false\n\n const target = resolve(dirname(route.source.filePath), withoutHashOrQuery)\n const relativeTarget = relative(contentRoot, target)\n if (relativeTarget.startsWith('..') || isAbsolute(relativeTarget)) return false\n if (await pathExists(target)) return true\n\n if (!extname(target)) {\n return pathExists(`${target}.md`) || pathExists(`${target}.mdx`) || pathExists(join(target, 'index.md')) || pathExists(join(target, 'index.mdx'))\n }\n return false\n}\n\nasync function checkContentDirectory(contentRoot: string, result: CheckResult): Promise<void> {\n try {\n const stats = await lstat(contentRoot)\n if (!stats.isDirectory()) {\n addDiagnostic(result, {\n level: 'error',\n code: 'content-not-directory',\n message: `Content path is not a directory: ${contentRoot}`,\n filePath: contentRoot,\n })\n }\n } catch {\n addDiagnostic(result, {\n level: 'error',\n code: 'content-missing',\n message: `Content directory does not exist: ${contentRoot}`,\n filePath: contentRoot,\n })\n }\n}\n\nfunction checkDuplicateRoutes(routes: ContentRoute[], result: CheckResult): void {\n const byPath = new Map<string, ContentRoute[]>()\n for (const route of routes) {\n const key = `${route.locale ?? ''}:${route.path}`\n byPath.set(key, [...(byPath.get(key) ?? []), route])\n }\n\n for (const duplicated of byPath.values()) {\n if (duplicated.length < 2) continue\n for (const route of duplicated) {\n addDiagnostic(result, {\n level: 'error',\n code: 'duplicate-route',\n message: `Route \"${route.path}\" is defined by multiple files: ${duplicated.map(route => relative(process.cwd(), route.source.filePath)).join(', ')}`,\n filePath: route.source.filePath,\n routePath: route.path,\n })\n }\n }\n}\n\nfunction checkFallbackRoutes(routes: ContentRoute[], result: CheckResult): void {\n for (const route of routes) {\n if (!route.isFallback) continue\n addDiagnostic(result, {\n level: 'warning',\n code: 'i18n-fallback-route',\n message: `Route \"${route.path}\" falls back to ${route.locale ?? 'default'} content from ${relative(process.cwd(), route.source.filePath)}`,\n filePath: route.source.filePath,\n routePath: route.path,\n })\n }\n}\n\nasync function checkLocalLinks(routes: ContentRoute[], contentRoot: string, result: CheckResult): Promise<void> {\n const routePaths = new Set(routes.map(route => route.path))\n\n for (const route of routes) {\n if (route.kind !== 'mdx' || !route.source.content) continue\n for (const match of route.source.content.matchAll(LOCAL_LINK_PATTERN)) {\n const href = match[1] ?? match[2]\n if (!href || !isLocalHref(href)) continue\n const candidates = routePathCandidates(href, route)\n if (candidates.some(candidate => routePaths.has(candidate))) continue\n if (await resolveLocalFileLink(href, route, contentRoot)) continue\n\n addDiagnostic(result, {\n level: 'error',\n code: 'broken-link',\n message: `Broken local link \"${href}\" in route \"${route.path}\"`,\n filePath: route.source.filePath,\n routePath: route.path,\n })\n }\n }\n}\n\nfunction printTextResult(result: CheckResult, strict: boolean): void {\n const diagnostics = [...result.errors, ...result.warnings]\n if (diagnostics.length === 0) {\n console.log('✓ Clarify check passed')\n return\n }\n\n for (const diagnostic of diagnostics) {\n const location = diagnostic.filePath ? ` ${relative(process.cwd(), diagnostic.filePath)}` : ''\n const route = diagnostic.routePath ? ` (${diagnostic.routePath})` : ''\n console.log(`${diagnostic.level.toUpperCase()} ${diagnostic.code}${location}${route}`)\n console.log(` ${diagnostic.message}`)\n }\n\n const warningExit = strict && result.warnings.length > 0\n console.log(`\\n${result.errors.length} error(s), ${result.warnings.length} warning(s)${warningExit ? ' (--strict treats warnings as failures)' : ''}`)\n}\n\nexport async function runCheck(options: CheckCommandOptions = {}): Promise<void> {\n const root = resolve(options.root ?? process.cwd())\n const engine = createClarifyEngine({\n projectRoot: root,\n rootDirectory: options.content,\n outputDirectory: options.output,\n })\n await engine.prepare(undefined, undefined, { htmlShell: false, skipModules: true, skipHints: true })\n\n const result: CheckResult = { errors: [], warnings: [] }\n await checkContentDirectory(engine.contentRoot, result)\n checkDuplicateRoutes(engine.routes, result)\n checkFallbackRoutes(engine.routes, result)\n await checkLocalLinks(engine.routes, engine.contentRoot, result)\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2))\n } else {\n printTextResult(result, Boolean(options.strict))\n }\n\n if (result.errors.length > 0 || (options.strict && result.warnings.length > 0)) {\n process.exitCode = 1\n }\n}\n","import { createServer } from 'vite'\n\nimport { createClarifyEngine } from '../../core/engine/engine.js'\nimport { createViteConfig } from '../../core/runtime/vite-config.js'\nimport type { ResolvedCliOptions } from '../options.js'\n\nexport async function runDev(options: ResolvedCliOptions): Promise<void> {\n const env = { command: 'serve' as const, mode: 'development' }\n const engine = createClarifyEngine({\n projectRoot: options.root,\n rootDirectory: options.content,\n outputDirectory: options.output,\n })\n await engine.prepare(env)\n const server = await createServer(await createViteConfig(options, env, engine))\n await server.listen()\n server.printUrls()\n server.bindCLIShortcuts({ print: true })\n}\n","import { spawnSync as nodeSpawnSync, SpawnSyncOptions } from 'node:child_process'\n\ntype SpawnOptions = { cwd?: string; stdio?: 'inherit' | 'ignore' | Array<string> }\n\nexport function spawnSync(command: string, args: string[], options: SpawnOptions) {\n return nodeSpawnSync(command, args, options as SpawnSyncOptions)\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { copyTemplateDirectory, getTemplateDirectory, resolveTemplate } from '@clarify-labs/templates'\n\nimport type { ResolvedCliOptions } from '../options.js'\nimport { cliPackageVersionWithCaret } from '../package.js'\nimport { spawnSync } from '../spawn.js'\n\nconst require = createRequire(import.meta.url)\n\nfunction findTemplatesPackagePath(): string {\n try {\n return require.resolve('@clarify-labs/templates/package.json')\n } catch {\n const currentDirectory = dirname(fileURLToPath(import.meta.url))\n const workspacePackagePath = resolve(currentDirectory, '../../../../templates/package.json')\n if (existsSync(workspacePackagePath)) return workspacePackagePath\n throw new Error('[clarify] Templates package not found.')\n }\n}\n\nconst templatesPackagePath = findTemplatesPackagePath()\nconst templatesDirectory = dirname(templatesPackagePath)\n\nfunction commandExists(program: string): boolean {\n const result = spawnSync(program, ['--version'], { stdio: 'ignore' })\n return result.status === 0 && result.error === undefined\n}\n\ntype PackageManager = 'pnpm' | 'npm' | 'yarn'\n\nfunction detectPackageManager(): PackageManager {\n if (commandExists('pnpm')) return 'pnpm'\n if (commandExists('npm')) return 'npm'\n if (commandExists('yarn')) return 'yarn'\n return 'npm'\n}\n\nfunction installDependencies(root: string, command: PackageManager): void {\n const args = ['install']\n console.log(`[clarify] Installing dependencies with ${command}...`)\n const result = spawnSync(command, args, { cwd: root, stdio: 'inherit' })\n if (result.status !== 0) {\n throw new Error(`[clarify] Dependency install failed with ${command}`)\n }\n}\n\nfunction getSuggestedInstallCommand(packageManager: PackageManager): string {\n return `${packageManager} install`\n}\n\nfunction getSuggestedRunCommand(packageManager: PackageManager): string {\n if (packageManager === 'pnpm') return 'pnpm dev'\n if (packageManager === 'yarn') return 'yarn dev'\n return 'npm run dev'\n}\n\nfunction updatePackageJson(root: string, force: boolean): boolean {\n const packageJsonPath = resolve(root, 'package.json')\n const packageJson = existsSync(packageJsonPath)\n ? JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as Record<string, unknown>\n : { type: 'module' }\n\n const scripts = typeof packageJson.scripts === 'object' && packageJson.scripts !== null\n ? packageJson.scripts as Record<string, string>\n : {}\n\n if (force || !scripts.dev) scripts.dev = 'clarify dev'\n if (force || !scripts.build) scripts.build = 'clarify build'\n packageJson.scripts = scripts\n\n const devDependencies = typeof packageJson.devDependencies === 'object' && packageJson.devDependencies !== null\n ? packageJson.devDependencies as Record<string, string>\n : {}\n if (!devDependencies['@clarify-labs/cli']) devDependencies['@clarify-labs/cli'] = cliPackageVersionWithCaret\n packageJson.devDependencies = devDependencies\n\n writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\\n`, 'utf-8')\n return true\n}\n\nexport function runInit(options: ResolvedCliOptions, force: boolean, template?: string, install = false): void {\n const selectedTemplate = resolveTemplate(template)\n const templateDirectory = getTemplateDirectory(templatesDirectory, selectedTemplate)\n const { created } = copyTemplateDirectory(templateDirectory, options.root, {\n contentDir: options.content,\n force,\n })\n\n const packageJsonUpdated = updatePackageJson(options.root, force)\n if (packageJsonUpdated) created.push('package.json')\n\n console.log(`[clarify] Project scaffold created using the ${selectedTemplate} template.`)\n if (created.length > 0) {\n console.log(`[clarify] Created or updated ${created.length} ${created.length === 1 ? 'file' : 'files'}: ${created.join(', ')}`)\n }\n\n const packageManager = detectPackageManager()\n if (install) {\n installDependencies(options.root, packageManager)\n const suggestedRun = getSuggestedRunCommand(packageManager)\n console.log('[clarify] Dependencies installed successfully.')\n console.log(`[clarify] You can now run \\`${suggestedRun}\\` to start the local documentation server.`)\n return\n }\n\n const suggestedInstall = getSuggestedInstallCommand(packageManager)\n const suggestedRun = getSuggestedRunCommand(packageManager)\n console.log('[clarify] Next steps:')\n console.log(' 1. Change into your new project directory:')\n console.log(` cd ${options.root}`)\n console.log(' 2. Install dependencies:')\n console.log(` ${suggestedInstall}`)\n console.log(' 3. Start the local documentation server:')\n console.log(` ${suggestedRun}`)\n}\n","import { createHash } from 'node:crypto'\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nimport type { McpSiteConfig } from '../../plugins/mcp-search/mcp-config.js'\nimport type { McpSearchResult } from '../../plugins/mcp-search/orama-index.js'\nimport { deserializeSearchIndex, searchMcpIndex } from '../../plugins/mcp-search/orama-index.js'\n\n/**\n * A ready-to-search Orama index loaded for the MCP server.\n *\n * The underlying db is fully in-memory after load, so `search` is synchronous\n * to the index. `dispose` drops the reference so the buffer can be GC'd; it's\n * safe to call multiple times.\n */\nexport type LoadedSearchIndex = {\n /** Search the index. Locale filter is optional. */\n search: (params: { query: string; locale?: string; limit?: number }) => McpSearchResult\n /** Release the in-memory index. Safe to call multiple times. */\n dispose: () => void\n}\n\n/** Re-export so callers can name the result type without reaching into orama-index. */\nexport type { McpSearchResult as SearchResult } from '../../plugins/mcp-search/orama-index.js'\n\nexport type OramaLoaderOptions = {\n /**\n * Root directory for the on-disk cache. Defaults to `~/.clarify/mcp-cache`.\n * Each site gets a subdirectory keyed by a stable hash of its origin + path.\n */\n cacheDir?: string\n /**\n * Bypass the cache and always fetch fresh. Implies purging the cached copy\n * for this site on a successful refresh.\n */\n noCache?: boolean\n /** Optional fetch override (testing). */\n fetchImpl?: typeof fetch\n /** Optional logger (testing). Defaults to no-op. */\n log?: (message: string) => void\n}\n\nconst DEFAULT_CACHE_DIR = () => join(homedir(), '.clarify', 'mcp-cache')\nconst FETCH_TIMEOUT_MS = 60_000\n\n/** Stable per-site cache key. Two URLs with the same origin+path share a cache. */\nfunction siteCacheKey(siteUrl: string): string {\n let url: URL\n try {\n url = new URL(siteUrl)\n } catch {\n throw new Error(`[clarify] Invalid site URL: ${siteUrl}`)\n }\n // Origin + pathname, trailing slash normalized, query/hash ignored.\n // Query/hash are irrelevant for \"where does the site live\" and would\n // fragment the cache unnecessarily.\n const normalized = `${url.origin}${url.pathname.replace(/\\/+$/, '')}`\n return createHash('sha256').update(normalized).digest('hex').slice(0, 16)\n}\n\nasync function fetchBufferWithTimeout(url: string, fetchImpl: typeof fetch, log: (m: string) => void): Promise<Uint8Array> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n try {\n log(`Fetching ${url}`)\n const res = await fetchImpl(url, { signal: controller.signal, redirect: 'follow' })\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} ${res.statusText} fetching ${url}`)\n }\n const buf = await res.arrayBuffer()\n return new Uint8Array(buf)\n } finally {\n clearTimeout(timer)\n }\n}\n\n/**\n * Load the Orama binary index for a remote site and return a ready-to-search\n * handle.\n *\n * The `.msp` index is a single binary file (msgpack-serialized Orama `save()`\n * output). It is cached on disk so repeated MCP starts don't re-download.\n * Cache validity is keyed by `capabilities.search.indexHash` when available.\n * For older sites that do not emit `indexHash`, we fall back to document\n * count + locale fingerprint matching.\n *\n * The caller must supply the same `defaultLocale` recorded in `mcp.json` so\n * the tokenizer matches the one used at build time. A mismatch would not\n * corrupt data but would cause CJK query terms to be tokenized incorrectly.\n */\nexport async function loadSearchIndex(siteUrl: string, config: McpSiteConfig, options: OramaLoaderOptions = {}): Promise<LoadedSearchIndex> {\n const log = options.log ?? (() => {})\n const fetchImpl = options.fetchImpl ?? fetch\n const cacheDir = options.cacheDir ?? DEFAULT_CACHE_DIR()\n const cacheKey = siteCacheKey(siteUrl)\n const siteCacheDir = join(cacheDir, cacheKey)\n const indexCachePath = join(siteCacheDir, 'mcp-search.msp')\n const manifestPath = join(siteCacheDir, 'manifest.json')\n\n const base = new URL(siteUrl).href\n log(`Site base resolved to ${base}`)\n\n // The index path in mcp.json is root-relative (e.g. `/mcp-search.msp` or\n // `/docs/mcp-search.msp`). Resolve it against the site base.\n const search = config.capabilities.search\n if (!search) {\n throw new Error(`[clarify] mcp.json for ${siteUrl} has no search capability.`)\n }\n const indexUrl = new URL(search.indexPath, base).href\n\n // Cache validity: reuse the cached .msp only when the document count and\n // locale fingerprint recorded at last fetch match the caller-provided\n // config. These change whenever the index is rebuilt with different content.\n const fingerprint = localeFingerprint(config)\n const indexHash = search.indexHash\n let useCache = !options.noCache\n if (useCache) {\n try {\n const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as {\n documentCount?: number\n fingerprint?: string\n indexHash?: string\n }\n if (indexHash) {\n if (manifest.indexHash !== indexHash) {\n log('Cache stale (index hash changed); refetching')\n useCache = false\n }\n } else if (manifest.documentCount !== search.documentCount || manifest.fingerprint !== fingerprint) {\n log('Cache stale (document count or locales changed); refetching')\n useCache = false\n }\n } catch {\n useCache = false\n }\n }\n\n let buffer: Uint8Array | undefined\n if (useCache) {\n try {\n buffer = await readFile(indexCachePath)\n log('Using cached mcp-search.msp')\n } catch {\n // Cache file unreadable; fall through to fetch below.\n }\n }\n\n if (buffer === undefined) {\n const fetched = await fetchBufferWithTimeout(indexUrl, fetchImpl, log)\n buffer = fetched\n // Best-effort persist; failure to cache is non-fatal.\n try {\n await mkdir(siteCacheDir, { recursive: true })\n await writeFile(indexCachePath, fetched)\n await writeFile(\n manifestPath,\n JSON.stringify(\n {\n siteUrl: base,\n fetchedAt: new Date().toISOString(),\n documentCount: search.documentCount,\n fingerprint,\n indexHash,\n },\n null,\n 2,\n ),\n 'utf8',\n )\n log(`Cached mcp-search.msp to ${indexCachePath}`)\n } catch (err) {\n log(`Warning: failed to cache index: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n const defaultLocale = search.defaultLocale\n const db = deserializeSearchIndex(buffer, defaultLocale)\n let disposed = false\n\n return {\n search: ({ query, locale, limit }) => {\n if (disposed) throw new Error('[clarify] Search index already disposed.')\n return searchMcpIndex(db, { query, locale, limit })\n },\n dispose: () => {\n // Orama's in-memory index is plain JS data; dropping the reference is\n // enough for GC. Nothing to flush.\n disposed = true\n },\n }\n}\n\n/**\n * Build a stable fingerprint of the indexed locales so the cache can detect\n * locale-set changes even when the document count happens to stay the same.\n */\nfunction localeFingerprint(config: McpSiteConfig): string {\n return createHash('sha256').update((config.capabilities.search?.locales ?? []).slice().sort().join('|')).digest('hex').slice(0, 16)\n}\n\n/**\n * Remove the on-disk cache for a site. Useful for `--no-cache` cleanup or for\n * tests. No-op if the site has no cache directory.\n */\nexport async function purgeSiteCache(siteUrl: string, cacheDir?: string): Promise<void> {\n const dir = cacheDir ?? DEFAULT_CACHE_DIR()\n const key = siteCacheKey(siteUrl)\n await rm(join(dir, key), { recursive: true, force: true })\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { z } from 'zod'\n\nimport type { McpSiteConfig } from '../../plugins/mcp-search/mcp-config.js'\nimport type { McpSearchHit } from '../../plugins/mcp-search/orama-index.js'\n\nimport type { LoadedSearchIndex } from './orama-loader.js'\n\nexport type SearchServerOptions = {\n /** Optional logger routed to stderr (stdout is the JSON-RPC channel). */\n log?: (message: string) => void\n}\n\n/**\n * A site loaded for the MCP server: its descriptor, ready-to-search index,\n * and the origin URL the index was fetched from (used to resolve relative\n * result paths and to label results by source site).\n */\nexport type LoadedMcpSite = {\n siteUrl: string\n config: McpSiteConfig\n index: LoadedSearchIndex\n}\n\n/** A search hit annotated with the site it came from. */\ntype SourcedHit = McpSearchHit & { site: string }\n\n/**\n * Build the MCP server exposing site search over one or more Clarify sites.\n *\n * Tools registered:\n * - `search_docs`: full-text search across all loaded sites, with each\n * result annotated by its source site.\n *\n * Results are serialized to a compact, LLM-friendly shape: title, URL, site,\n * excerpt, score, and locale. Full page content is intentionally omitted to\n * keep responses within token budgets; clients can fetch the URL themselves.\n */\nexport function createMcpSearchServer(sites: LoadedMcpSite[], options: SearchServerOptions = {}): McpServer {\n const log = options.log ?? (() => {})\n const server = new McpServer({\n name: 'clarify-search',\n version: '1.0.0',\n })\n\n if (sites.length === 0) {\n throw new Error('[clarify] createMcpSearchServer requires at least one loaded site.')\n }\n\n // Aggregate metadata across all loaded sites for the tool description.\n const totalDocs = sites.reduce((sum, site) => sum + (site.config.capabilities.search?.documentCount ?? 0), 0)\n const localeSet = new Set<string>()\n for (const site of sites) {\n for (const locale of site.config.capabilities.search?.locales ?? []) localeSet.add(locale)\n }\n const localeList = [...localeSet]\n const siteTitles = sites\n .map(site => site.config.site.title ?? 'site')\n .filter((title, i, arr) => arr.indexOf(title) === i)\n const siteHint = siteTitles.length === 1\n ? `\"${siteTitles[0]}\"`\n : `${sites.length} sites (${siteTitles.join(', ')})`\n\n const localeHint = localeList.length > 0\n ? ` Available locales: ${localeList.join(', ')}.`\n : ''\n const defaultLocale = sites[0].config.capabilities.search?.defaultLocale\n const defaultLocaleHint = defaultLocale\n ? ` Defaults to \"${defaultLocale}\".`\n : ''\n\n server.registerTool(\n 'search_docs',\n {\n title: 'Search documentation',\n description: [\n `Full-text search over ${siteHint} documentation index.`,\n `Returns ranked results with excerpts, URLs, and source site. The index contains ${totalDocs} pages across ${localeList.length} locale(s).`,\n localeHint,\n defaultLocaleHint,\n 'Pass a `locale` filter to restrict results to a specific language.',\n ].filter(Boolean).join(' '),\n inputSchema: {\n query: z\n .string()\n .min(1)\n .describe('Search query. CJK text is word-segmented automatically; Latin text is split on whitespace/punctuation.'),\n locale: z\n .string()\n .optional()\n .describe(`Filter results to a single locale. One of: ${localeList.join(', ')}.`),\n limit: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe('Maximum results to return. Default 10, max 50.'),\n },\n },\n async ({ query, locale, limit }) => {\n log(`search_docs query=${JSON.stringify(query)} locale=${JSON.stringify(locale)} limit=${limit ?? 10}`)\n\n // Search every loaded site and merge hits. Each hit is annotated with\n // its source site so the caller can tell results apart when multiple\n // sites are loaded. Results are ranked globally by score.\n const allHits: SourcedHit[] = []\n let errorResult: { text: string } | undefined\n for (const site of sites) {\n try {\n const result = site.index.search({ query, locale, limit })\n for (const hit of result.hits) {\n allHits.push({ ...hit, site: site.siteUrl })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n log(`search failed for ${site.siteUrl}: ${message}`)\n errorResult = { text: `Search failed for ${site.siteUrl}: ${message}` }\n }\n }\n\n if (allHits.length === 0 && errorResult) {\n return {\n isError: true,\n content: [{ type: 'text', text: errorResult.text }],\n }\n }\n\n allHits.sort((a, b) => b.score - a.score)\n const capped = limit ? allHits.slice(0, limit) : allHits.slice(0, 10)\n\n const summary = [\n `Found ${allHits.length} result(s) across ${totalDocs} indexed pages from ${sites.length} site(s).`,\n `Showing top ${capped.length}.`,\n '',\n ].join('\\n')\n\n const text = [summary, ...capped.map((hit, i) => formatResultText(hit, i))].join('\\n---\\n')\n\n return {\n content: [{ type: 'text', text }],\n }\n },\n )\n\n return server\n}\n\n/**\n * Run the search server over stdio until the client disconnects or the process\n * is signaled. Resolves on clean shutdown.\n */\nexport async function runMcpSearchServer(sites: LoadedMcpSite[], options: SearchServerOptions = {}): Promise<void> {\n const log = options.log ?? (() => {})\n const server = createMcpSearchServer(sites, options)\n const transport = new StdioServerTransport()\n // Dispose every search index when the client disconnects. StdioServerTransport\n // calls onclose after stdin closes.\n transport.onclose = () => {\n log('MCP transport closed; disposing search indices')\n for (const site of sites) site.index.dispose()\n }\n await server.connect(transport)\n log(`MCP search server listening on stdio (${sites.length} site(s))`)\n}\n\nfunction formatResultText(hit: SourcedHit, index: number): string {\n const lines = [\n `## ${index + 1}. ${hit.title}`,\n `URL: ${hit.path}`,\n `Site: ${hit.site}`,\n `Score: ${hit.score}`,\n ]\n if (hit.locale) {\n lines.push(`Locale: ${hit.locale}`)\n }\n if (hit.excerpt) {\n lines.push('', hit.excerpt)\n }\n if (hit.description) {\n lines.push('', `Description: ${hit.description}`)\n }\n if (hit.keywords?.length > 0) {\n lines.push('', `Keywords: ${hit.keywords.join(', ')}`)\n }\n return lines.join('\\n')\n}\n","import type { McpSiteConfig } from '../../plugins/mcp-search/mcp-config.js'\nimport { loadSearchIndex } from '../mcp/orama-loader.js'\nimport type { LoadedMcpSite } from '../mcp/search-server.js'\nimport { runMcpSearchServer } from '../mcp/search-server.js'\n\nexport type McpCliOptions = {\n /** Skip the on-disk index cache; always fetch fresh. */\n noCache?: boolean\n /** Optional logger for diagnostics (defaults to stderr). */\n log?: (message: string) => void\n}\n\n/**\n * Start a local MCP server (stdio transport) that exposes full-text search\n * over one or more deployed Clarify sites' Orama indices.\n *\n * For each site:\n * 1. Fetch `<site>/mcp.json` to learn the index path, default locale, and\n * document count. This is a tiny file and avoids hardcoding any\n * assumptions about where the index lives on the site.\n * 2. Use the descriptor to fetch the binary `.msp` index (cached locally\n * keyed by site origin + document count + locale fingerprint) and\n * deserialize it into an in-memory Orama db with the correct tokenizer.\n *\n * Then register the `search_docs` tool, which searches across all loaded\n * sites and merges results (each hit annotated with its source site), and\n * serve over stdio.\n *\n * All logs go to stderr - stdout is reserved for the JSON-RPC protocol.\n */\nexport async function runMcp(siteUrls: string[], options: McpCliOptions = {}): Promise<void> {\n if (siteUrls.length === 0) {\n throw new Error('[clarify] At least one site URL is required. Usage: clarify mcp <site> [site...]')\n }\n\n const log = options.log ?? stderrLog\n const sites: LoadedMcpSite[] = []\n for (const siteUrl of siteUrls) {\n const config = await fetchMcpConfig(siteUrl, fetch, log)\n const search = config.capabilities.search\n if (!search) {\n throw new Error(`[clarify] mcp.json for ${siteUrl} has no search capability. Run a build with search enabled.`)\n }\n log(`Loaded mcp.json for ${siteUrl}: ${search.documentCount} doc(s), ${search.locales.length} locale(s)`)\n\n const index = await loadSearchIndex(siteUrl, config, {\n noCache: options.noCache,\n fetchImpl: fetch,\n log,\n })\n sites.push({ siteUrl, config, index })\n }\n\n await runMcpSearchServer(sites, { log })\n}\n\nfunction stderrLog(message: string): void {\n process.stderr.write(`[clarify] ${message}\\n`)\n}\n\nexport async function fetchMcpConfig(siteUrl: string, fetchImpl: typeof fetch, log: (m: string) => void): Promise<McpSiteConfig> {\n const configUrl = new URL('mcp.json', new URL(siteUrl).href).href\n log(`Fetching ${configUrl}`)\n const res = await fetchImpl(configUrl, { redirect: 'follow' })\n if (!res.ok) {\n throw new Error(\n `[clarify] Failed to fetch mcp.json from ${configUrl} (HTTP ${res.status}). ` +\n 'Ensure the site was built with a recent version of Clarify that emits mcp.json.',\n )\n }\n const config = (await res.json()) as McpSiteConfig\n if (config.version !== 3) {\n throw new Error(`[clarify] Unsupported mcp.json schema version ${config.version}. Please update the clarify CLI.`)\n }\n const search = config.capabilities.search\n if (!search || search.documentCount === 0) {\n throw new Error(`[clarify] mcp.json at ${configUrl} has no indexed documents. Run a build with search enabled.`)\n }\n if (!search.indexPath) {\n throw new Error(`[clarify] mcp.json at ${configUrl} is missing capabilities.search.indexPath.`)\n }\n if (search.indexHash !== undefined && (typeof search.indexHash !== 'string' || search.indexHash.length === 0)) {\n throw new Error(`[clarify] mcp.json at ${configUrl} has an invalid capabilities.search.indexHash.`)\n }\n return config\n}\n","import { resolve } from 'node:path'\n\nexport type CliOptions = {\n root?: string\n content?: string\n output?: string\n host?: string | boolean\n port?: string | number\n open?: boolean | string\n}\n\nexport type ResolvedCliOptions = {\n root: string\n content: string\n output: string\n host?: string | boolean\n port?: number\n open?: boolean | string\n}\n\nfunction resolvePort(port: CliOptions['port']): number | undefined {\n if (port === undefined) return undefined\n\n const parsedPort = typeof port === 'string' ? Number(port) : port\n if (!Number.isInteger(parsedPort) || parsedPort < 1 || parsedPort > 65535) {\n throw new Error('[clarify] --port must be an integer between 1 and 65535')\n }\n\n return parsedPort\n}\n\nexport function resolveCliOptions(options: CliOptions): ResolvedCliOptions {\n return {\n root: resolve(options.root ?? process.cwd()),\n content: options.content ?? 'source',\n output: options.output ?? 'output',\n host: options.host,\n port: resolvePort(options.port),\n open: options.open,\n }\n}\n","import { cac } from 'cac'\n\nimport { runBuild } from './commands/build.js'\nimport { runCheck, type CheckCommandOptions } from './commands/check.js'\nimport { runDev } from './commands/dev.js'\nimport { runInit } from './commands/init.js'\nimport { runMcp, type McpCliOptions } from './commands/mcp.js'\nimport { resolveCliOptions, type CliOptions } from './options.js'\nimport { cliPackageVersion } from './package.js'\n\ntype InitCommandOptions = CliOptions & {\n force?: boolean\n template?: string\n install?: boolean\n}\n\nfunction withBuildOptions(command: ReturnType<ReturnType<typeof cac>['command']>) {\n return command\n .option('--content <dir>', 'Content directory relative to root')\n}\n\nfunction withSharedOptions(command: ReturnType<ReturnType<typeof cac>['command']>) {\n return command\n .option('--root <dir>', 'Project root directory')\n .option('--content <dir>', 'Content directory relative to root')\n .option('--output <dir>', 'Build output directory relative to root')\n}\n\nfunction createCli() {\n const cli = cac('clarify')\n\n cli\n .version(cliPackageVersion)\n .help()\n\n withSharedOptions(cli.command('dev', 'Start the local documentation server'))\n .option('--host [host]', 'Dev server host')\n .option('--port <port>', 'Dev server port')\n .option('--open [path]', 'Open the dev server in a browser')\n .action(async (options: CliOptions) => {\n await runDev(resolveCliOptions(options))\n })\n\n withSharedOptions(cli.command('build', 'Build the static documentation site'))\n .action(async (options: CliOptions) => {\n await runBuild(resolveCliOptions(options))\n })\n\n withSharedOptions(cli.command('check', 'Validate the documentation project'))\n .option('--strict', 'Treat warnings as failures')\n .option('--format <format>', 'Output format: text or json')\n .action(async (options: CheckCommandOptions) => {\n await runCheck(options)\n })\n\n withBuildOptions(cli.command('init [directory]', 'Create a Clarify project scaffold'))\n .option('--force', 'Overwrite files created by init')\n .option('--template <name>', 'Template to use: minimal, standard, or complete')\n .option('--install', 'Install dependencies after init')\n .action((directory: string | undefined, options: InitCommandOptions) => {\n runInit(resolveCliOptions({ ...options, root: directory }), options.force === true, options.template, options.install === true)\n })\n\n cli\n .command('mcp <...site>', 'Start a local MCP server exposing full-text search over one or more deployed sites')\n .option('--no-cache', 'Skip the local search index cache and always fetch fresh')\n .action(async (sites: string[], options: McpCliOptions) => {\n await runMcp(sites, { noCache: options.noCache === true })\n })\n\n return cli\n}\n\nexport async function main(argv = process.argv): Promise<void> {\n const cli = createCli()\n const args = argv.slice(2)\n cli.parse(argv, { run: false })\n\n if (args.length === 0) {\n cli.outputHelp()\n return\n }\n\n await cli.runMatchedCommand()\n}\n","#!/usr/bin/env node\nimport { main } from './program.js'\n\nmain().catch(error => {\n console.error(error instanceof Error ? error.stack ?? error.message : String(error))\n process.exitCode = 1\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../source/core/runtime/log.ts","../source/core/runtime/vite-config.ts","../source/cli/commands/build.ts","../source/cli/commands/check.ts","../source/cli/commands/dev.ts","../source/cli/spawn.ts","../source/cli/commands/init.ts","../source/cli/mcp/orama-loader.ts","../source/cli/mcp/search-server.ts","../source/cli/commands/mcp.ts","../source/cli/options.ts","../source/cli/program.ts","../source/cli/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\nconst LOG_FILE_NAME = '.clarify.log'\nconst DEFAULT_LOG_ENTRIES = 50\nconst ENTRY_SEPARATOR = '\\n\\n---\\n\\n'\n\nfunction getMaxLogEntries(): number {\n const envValue = process.env.CLARIFY_LOG_MAX_ENTRIES\n if (!envValue) return DEFAULT_LOG_ENTRIES\n const parsed = Number(envValue)\n return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_LOG_ENTRIES\n}\n\nfunction normalizeErrorMessage(error: unknown): string {\n if (error === undefined) return 'undefined'\n if (error === null) return 'null'\n if (error instanceof Error) return error.message\n if (typeof error === 'object') {\n if ('message' in error && typeof (error as { message?: unknown }).message === 'string') {\n return (error as { message: string }).message\n }\n try {\n return JSON.stringify(error)\n } catch {\n return String(error)\n }\n }\n return String(error)\n}\n\nfunction normalizeErrorStack(error: unknown): string | undefined {\n if (error instanceof Error) {\n return error.stack\n }\n return undefined\n}\n\nfunction formatLogEntry(root: string, error: unknown): string {\n const timestamp = new Date().toISOString()\n const message = normalizeErrorMessage(error)\n const stack = normalizeErrorStack(error)\n\n return [`=== Clarify build error ===`, `Timestamp: ${timestamp}`, `Project root: ${root}`, `Error: ${message}`, stack ? `Stack:\\n${stack}` : undefined]\n .filter(Boolean)\n .join('\\n')\n}\n\ntype LogEntryReader = (logPath: string) => Promise<string> | string\ntype LogEntryWriter = (logPath: string, content: string) => Promise<void> | void\n\nfunction collectLogEntries(entries: string[], entry: string, max: number): string[] {\n const next = [...entries, entry]\n return next.length > max ? next.slice(-max) : next\n}\n\nfunction readExistingEntries(content: string): string[] {\n return content\n .split(ENTRY_SEPARATOR)\n .map((item) => item.trim())\n .filter(Boolean)\n}\n\nasync function writeLogEntry(root: string, error: unknown, maxEntries: number | undefined, read: LogEntryReader, write: LogEntryWriter): Promise<void> {\n const logPath = join(root, LOG_FILE_NAME)\n const entry = formatLogEntry(root, error)\n const max = maxEntries ?? getMaxLogEntries()\n\n let entries: string[] = []\n if (existsSync(logPath)) {\n try {\n entries = readExistingEntries(await read(logPath))\n } catch {\n entries = []\n }\n }\n\n entries = collectLogEntries(entries, entry, max)\n\n mkdirSync(dirname(logPath), { recursive: true })\n await write(logPath, entries.join(ENTRY_SEPARATOR) + '\\n')\n}\n\nexport async function logBuildError(root: string, error: unknown, maxEntries?: number): Promise<void> {\n await writeLogEntry(root, error, maxEntries, (path) => readFile(path, 'utf8'), (path, content) => writeFile(path, content, 'utf8'))\n}\n\nexport function logBuildErrorSync(root: string, error: unknown, maxEntries?: number): void {\n void writeLogEntry(root, error, maxEntries, (path) => readFileSync(path, 'utf8'), (path, content) => writeFileSync(path, content, 'utf8'))\n}\n","import { existsSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport { createLogger } from 'vite'\nimport type { ConfigEnv, InlineConfig, Plugin, LogLevel, Logger, LogOptions, LogErrorOptions, LogType } from 'vite'\n\nimport { createViteAdapter } from '../adapters.js'\nimport type { ClarifyEngine } from '../engine/engine.js'\nimport { createClarifyTempDir } from '../project/temp-dir.js'\n\nimport { logBuildErrorSync } from './log.js'\nimport { createClarifyRuntimeAliases } from './runtime-deps.js'\n\nexport type ClarifyViteConfigOptions = {\n root: string\n content: string\n output: string\n host?: string | boolean\n port?: number\n open?: boolean | string\n}\n\nconst DEFAULT_HTML = '<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><title>Clarify</title></head><body><div id=\"root\"></div></body></html>'\n\nfunction ensureHtmlEntry(root: string): string {\n const projectHtmlPath = resolve(root, 'index.html')\n if (existsSync(projectHtmlPath)) return projectHtmlPath\n\n const generatedHtmlPath = resolve(createClarifyTempDir('html'), 'index.html')\n writeFileSync(generatedHtmlPath, DEFAULT_HTML, 'utf-8')\n return generatedHtmlPath\n}\n\nfunction createClarifyLogger(root: string, env: ConfigEnv, level: LogLevel): Logger | undefined {\n if (env.command !== 'build') return undefined\n\n const baseLogger = createLogger(level, { allowClearScreen: true })\n\n return {\n info(msg: string, options?: LogOptions) {\n baseLogger.info(msg, options)\n },\n warn(msg: string, options?: LogOptions) {\n baseLogger.warn(msg, options)\n },\n warnOnce(msg: string, options?: LogOptions) {\n baseLogger.warnOnce(msg, options)\n },\n error(msg: string, options?: LogErrorOptions) {\n baseLogger.error(msg, options)\n if (options?.error) {\n logBuildErrorSync(root, options.error)\n } else {\n logBuildErrorSync(root, typeof msg === 'string' ? new Error(msg) : msg)\n }\n },\n clearScreen(type: LogType) {\n baseLogger.clearScreen(type)\n },\n hasErrorLogged(error: Error | unknown) {\n return baseLogger.hasErrorLogged(error as Error)\n },\n get hasWarned() {\n return baseLogger.hasWarned\n },\n }\n}\n\nfunction createHtmlFallbackPlugin(): Plugin {\n return {\n name: 'clarify:cli-html-fallback',\n configureServer(server) {\n server.middlewares.use(async (req, res, next) => {\n const requestPath = req.url?.split('?')[0] ?? '/'\n const acceptsHtml = req.headers.accept?.includes('text/html') ?? false\n const hasFileExtension = /\\.[^/]+$/.test(requestPath)\n if (!acceptsHtml || hasFileExtension) {\n next()\n return\n }\n\n try {\n const html = await server.transformIndexHtml(requestPath, DEFAULT_HTML)\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n res.end(html)\n } catch (error) {\n next(error)\n }\n })\n },\n }\n}\n\nexport async function createViteConfig(options: ClarifyViteConfigOptions, env: ConfigEnv, engine: ClarifyEngine): Promise<InlineConfig> {\n const entryHtmlPath = ensureHtmlEntry(options.root)\n\n return {\n root: options.root,\n configFile: false,\n appType: 'custom',\n resolve: {\n alias: createClarifyRuntimeAliases(),\n },\n customLogger: createClarifyLogger(options.root, env, 'info'),\n plugins: [\n createViteAdapter(engine),\n createHtmlFallbackPlugin(),\n ],\n server: {\n host: options.host,\n port: options.port,\n open: options.open,\n },\n build: {\n outDir: options.output,\n rolldownOptions: {\n input: {\n index: entryHtmlPath,\n },\n checks: {\n pluginTimings: false,\n },\n output: {\n codeSplitting: {\n groups: [\n {\n name: 'react-vendor',\n test: /node_modules[\\\\/](react|react-dom|react-router|react-router-dom)[\\\\/]/,\n priority: 40,\n },\n {\n name: 'icons-vendor',\n test: /node_modules[\\\\/]lucide-react[\\\\/]/,\n priority: 35,\n },\n {\n name: 'ui-vendor',\n test: /node_modules[\\\\/](@headlessui|framer-motion)[\\\\/]/,\n priority: 30,\n },\n {\n name: 'mermaid-viewer-vendor',\n test: /node_modules[\\\\/]react-zoom-pan-pinch[\\\\/]/,\n priority: 25,\n },\n {\n // Keep mermaid and its heavy diagram/render dependencies out of\n // the eager `vendor` chunk so they stay lazily loaded only on\n // pages that actually render a diagram.\n name: 'mermaid-vendor',\n test: /node_modules[\\\\/](mermaid|@mermaid-js|cytoscape|cytoscape-[^\\\\/]+|dagre-d3-es|@dagrejs|dagre|graphlib|elkjs|katex|d3|d3-[^\\\\/]+|internmap|delaunator|robust-predicates|roughjs|points-on-curve|points-on-path|path-data-parser|@braintree[\\\\/]sanitize-url|dompurify|khroma|ts-dedent|stylis|cose-base|layout-base)[\\\\/]/,\n priority: 20,\n },\n {\n name: 'vendor',\n test: /node_modules[\\\\/]/,\n priority: 10\n },\n ],\n },\n },\n },\n },\n }\n}\n","import { build as viteBuild } from 'vite'\n\nimport { createClarifyEngine } from '../../core/engine/engine.js'\nimport { logBuildError } from '../../core/runtime/log.js'\nimport { createViteConfig } from '../../core/runtime/vite-config.js'\nimport type { ResolvedCliOptions } from '../options.js'\n\nexport async function runBuild(options: ResolvedCliOptions): Promise<void> {\n const env = { command: 'build' as const, mode: 'production' }\n const engine = createClarifyEngine({\n projectRoot: options.root,\n rootDirectory: options.content,\n outputDirectory: options.output,\n })\n try {\n await engine.prepare(env)\n await viteBuild(await createViteConfig(options, env, engine))\n } catch (error) {\n await logBuildError(options.root, error)\n throw error\n }\n}\n","import { lstat, stat } from 'node:fs/promises'\nimport { dirname, extname, isAbsolute, join, normalize, relative, resolve } from 'node:path'\n\nimport { createClarifyEngine } from '../../core/engine/engine.js'\nimport type { ContentRoute } from '../../types.js'\nimport type { CliOptions } from '../options.js'\n\nexport type CheckCommandOptions = CliOptions & {\n strict?: boolean\n format?: 'text' | 'json' | string\n}\n\ntype CheckLevel = 'error' | 'warning'\n\ntype CheckDiagnostic = {\n level: CheckLevel\n code: string\n message: string\n filePath?: string\n routePath?: string\n}\n\ntype CheckResult = {\n errors: CheckDiagnostic[]\n warnings: CheckDiagnostic[]\n}\n\nconst LOCAL_LINK_PATTERN = /(?<!!)(?:\\[[^\\]]*\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)|<a\\s+[^>]*href=[\"']([^\"']+)[\"'])/gi\nconst ROUTE_EXTENSIONS = new Set(['.md', '.mdx'])\nconst IGNORED_SCHEMES = /^[a-z][a-z0-9+.-]*:/i\n\nfunction addDiagnostic(result: CheckResult, diagnostic: CheckDiagnostic): void {\n if (diagnostic.level === 'error') result.errors.push(diagnostic)\n else result.warnings.push(diagnostic)\n}\n\nfunction normalizeRoutePath(path: string): string {\n const [withoutHash] = path.split('#')\n const clean = withoutHash.replace(/\\/index$/, '') || '/'\n return clean.startsWith('/') ? clean : `/${clean}`\n}\n\nfunction routePathCandidates(href: string, route: ContentRoute): string[] {\n const [withoutHashOrQuery] = href.split(/[?#]/)\n if (!withoutHashOrQuery || withoutHashOrQuery.startsWith('#')) return []\n if (withoutHashOrQuery.startsWith('/')) return [normalizeRoutePath(withoutHashOrQuery)]\n\n const routeDir = dirname(route.path)\n const joined = normalize(join(routeDir, withoutHashOrQuery)).replaceAll('\\\\', '/')\n const extension = extname(joined)\n const base = ROUTE_EXTENSIONS.has(extension) ? joined.slice(0, -extension.length) : joined\n return [normalizeRoutePath(base)]\n}\n\nasync function pathExists(filePath: string): Promise<boolean> {\n try {\n await stat(filePath)\n return true\n } catch {\n return false\n }\n}\n\nfunction isLocalHref(href: string): boolean {\n return Boolean(href) && !href.startsWith('#') && !href.startsWith('//') && !IGNORED_SCHEMES.test(href)\n}\n\nasync function resolveLocalFileLink(href: string, route: ContentRoute, contentRoot: string): Promise<boolean> {\n const [withoutHashOrQuery] = href.split(/[?#]/)\n if (!withoutHashOrQuery || withoutHashOrQuery.startsWith('/')) return false\n\n const target = resolve(dirname(route.source.filePath), withoutHashOrQuery)\n const relativeTarget = relative(contentRoot, target)\n if (relativeTarget.startsWith('..') || isAbsolute(relativeTarget)) return false\n if (await pathExists(target)) return true\n\n if (!extname(target)) {\n return pathExists(`${target}.md`) || pathExists(`${target}.mdx`) || pathExists(join(target, 'index.md')) || pathExists(join(target, 'index.mdx'))\n }\n return false\n}\n\nasync function checkContentDirectory(contentRoot: string, result: CheckResult): Promise<void> {\n try {\n const stats = await lstat(contentRoot)\n if (!stats.isDirectory()) {\n addDiagnostic(result, {\n level: 'error',\n code: 'content-not-directory',\n message: `Content path is not a directory: ${contentRoot}`,\n filePath: contentRoot,\n })\n }\n } catch {\n addDiagnostic(result, {\n level: 'error',\n code: 'content-missing',\n message: `Content directory does not exist: ${contentRoot}`,\n filePath: contentRoot,\n })\n }\n}\n\nfunction checkDuplicateRoutes(routes: ContentRoute[], result: CheckResult): void {\n const byPath = new Map<string, ContentRoute[]>()\n for (const route of routes) {\n const key = `${route.locale ?? ''}:${route.path}`\n byPath.set(key, [...(byPath.get(key) ?? []), route])\n }\n\n for (const duplicated of byPath.values()) {\n if (duplicated.length < 2) continue\n for (const route of duplicated) {\n addDiagnostic(result, {\n level: 'error',\n code: 'duplicate-route',\n message: `Route \"${route.path}\" is defined by multiple files: ${duplicated.map(route => relative(process.cwd(), route.source.filePath)).join(', ')}`,\n filePath: route.source.filePath,\n routePath: route.path,\n })\n }\n }\n}\n\nfunction checkFallbackRoutes(routes: ContentRoute[], result: CheckResult): void {\n for (const route of routes) {\n if (!route.isFallback) continue\n addDiagnostic(result, {\n level: 'warning',\n code: 'i18n-fallback-route',\n message: `Route \"${route.path}\" falls back to ${route.locale ?? 'default'} content from ${relative(process.cwd(), route.source.filePath)}`,\n filePath: route.source.filePath,\n routePath: route.path,\n })\n }\n}\n\nasync function checkLocalLinks(routes: ContentRoute[], contentRoot: string, result: CheckResult): Promise<void> {\n const routePaths = new Set(routes.map(route => route.path))\n\n for (const route of routes) {\n if (route.kind !== 'mdx' || !route.source.content) continue\n for (const match of route.source.content.matchAll(LOCAL_LINK_PATTERN)) {\n const href = match[1] ?? match[2]\n if (!href || !isLocalHref(href)) continue\n const candidates = routePathCandidates(href, route)\n if (candidates.some(candidate => routePaths.has(candidate))) continue\n if (await resolveLocalFileLink(href, route, contentRoot)) continue\n\n addDiagnostic(result, {\n level: 'error',\n code: 'broken-link',\n message: `Broken local link \"${href}\" in route \"${route.path}\"`,\n filePath: route.source.filePath,\n routePath: route.path,\n })\n }\n }\n}\n\nfunction printTextResult(result: CheckResult, strict: boolean): void {\n const diagnostics = [...result.errors, ...result.warnings]\n if (diagnostics.length === 0) {\n console.log('✓ Clarify check passed')\n return\n }\n\n for (const diagnostic of diagnostics) {\n const location = diagnostic.filePath ? ` ${relative(process.cwd(), diagnostic.filePath)}` : ''\n const route = diagnostic.routePath ? ` (${diagnostic.routePath})` : ''\n console.log(`${diagnostic.level.toUpperCase()} ${diagnostic.code}${location}${route}`)\n console.log(` ${diagnostic.message}`)\n }\n\n const warningExit = strict && result.warnings.length > 0\n console.log(`\\n${result.errors.length} error(s), ${result.warnings.length} warning(s)${warningExit ? ' (--strict treats warnings as failures)' : ''}`)\n}\n\nexport async function runCheck(options: CheckCommandOptions = {}): Promise<void> {\n const root = resolve(options.root ?? process.cwd())\n const engine = createClarifyEngine({\n projectRoot: root,\n rootDirectory: options.content,\n outputDirectory: options.output,\n })\n await engine.prepare(undefined, undefined, { htmlShell: false, skipModules: true, skipHints: true })\n\n const result: CheckResult = { errors: [], warnings: [] }\n await checkContentDirectory(engine.contentRoot, result)\n checkDuplicateRoutes(engine.routes, result)\n checkFallbackRoutes(engine.routes, result)\n await checkLocalLinks(engine.routes, engine.contentRoot, result)\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2))\n } else {\n printTextResult(result, Boolean(options.strict))\n }\n\n if (result.errors.length > 0 || (options.strict && result.warnings.length > 0)) {\n process.exitCode = 1\n }\n}\n","import { createServer } from 'vite'\n\nimport { createClarifyEngine } from '../../core/engine/engine.js'\nimport { createViteConfig } from '../../core/runtime/vite-config.js'\nimport type { ResolvedCliOptions } from '../options.js'\n\nexport async function runDev(options: ResolvedCliOptions): Promise<void> {\n const env = { command: 'serve' as const, mode: 'development' }\n const engine = createClarifyEngine({\n projectRoot: options.root,\n rootDirectory: options.content,\n outputDirectory: options.output,\n })\n await engine.prepare(env)\n const server = await createServer(await createViteConfig(options, env, engine))\n await server.listen()\n server.printUrls()\n server.bindCLIShortcuts({ print: true })\n}\n","import { spawnSync as nodeSpawnSync, SpawnSyncOptions } from 'node:child_process'\n\ntype SpawnOptions = { cwd?: string; stdio?: 'inherit' | 'ignore' | Array<string> }\n\nexport function spawnSync(command: string, args: string[], options: SpawnOptions) {\n return nodeSpawnSync(command, args, options as SpawnSyncOptions)\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { copyTemplateDirectory, getTemplateDirectory, resolveTemplate } from '@clarify-labs/templates'\n\nimport type { ResolvedCliOptions } from '../options.js'\nimport { cliPackageVersionWithCaret } from '../package.js'\nimport { spawnSync } from '../spawn.js'\n\nconst require = createRequire(import.meta.url)\n\nfunction findTemplatesPackagePath(): string {\n try {\n return require.resolve('@clarify-labs/templates/package.json')\n } catch {\n const currentDirectory = dirname(fileURLToPath(import.meta.url))\n const workspacePackagePath = resolve(currentDirectory, '../../../../templates/package.json')\n if (existsSync(workspacePackagePath)) return workspacePackagePath\n throw new Error('[clarify] Templates package not found.')\n }\n}\n\nconst templatesPackagePath = findTemplatesPackagePath()\nconst templatesDirectory = dirname(templatesPackagePath)\n\nfunction commandExists(program: string): boolean {\n const result = spawnSync(program, ['--version'], { stdio: 'ignore' })\n return result.status === 0 && result.error === undefined\n}\n\ntype PackageManager = 'pnpm' | 'npm' | 'yarn'\n\nfunction detectPackageManager(): PackageManager {\n if (commandExists('pnpm')) return 'pnpm'\n if (commandExists('npm')) return 'npm'\n if (commandExists('yarn')) return 'yarn'\n return 'npm'\n}\n\nfunction installDependencies(root: string, command: PackageManager): void {\n const args = ['install']\n console.log(`[clarify] Installing dependencies with ${command}...`)\n const result = spawnSync(command, args, { cwd: root, stdio: 'inherit' })\n if (result.status !== 0) {\n throw new Error(`[clarify] Dependency install failed with ${command}`)\n }\n}\n\nfunction getSuggestedInstallCommand(packageManager: PackageManager): string {\n return `${packageManager} install`\n}\n\nfunction getSuggestedRunCommand(packageManager: PackageManager): string {\n if (packageManager === 'pnpm') return 'pnpm dev'\n if (packageManager === 'yarn') return 'yarn dev'\n return 'npm run dev'\n}\n\nfunction updatePackageJson(root: string, force: boolean): boolean {\n const packageJsonPath = resolve(root, 'package.json')\n const packageJson = existsSync(packageJsonPath)\n ? JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as Record<string, unknown>\n : { type: 'module' }\n\n const scripts = typeof packageJson.scripts === 'object' && packageJson.scripts !== null\n ? packageJson.scripts as Record<string, string>\n : {}\n\n if (force || !scripts.dev) scripts.dev = 'clarify dev'\n if (force || !scripts.build) scripts.build = 'clarify build'\n packageJson.scripts = scripts\n\n const devDependencies = typeof packageJson.devDependencies === 'object' && packageJson.devDependencies !== null\n ? packageJson.devDependencies as Record<string, string>\n : {}\n if (!devDependencies['@clarify-labs/cli']) devDependencies['@clarify-labs/cli'] = cliPackageVersionWithCaret\n packageJson.devDependencies = devDependencies\n\n writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\\n`, 'utf-8')\n return true\n}\n\nexport function runInit(options: ResolvedCliOptions, force: boolean, template?: string, install = false): void {\n const selectedTemplate = resolveTemplate(template)\n const templateDirectory = getTemplateDirectory(templatesDirectory, selectedTemplate)\n const { created } = copyTemplateDirectory(templateDirectory, options.root, {\n contentDir: options.content,\n force,\n })\n\n const packageJsonUpdated = updatePackageJson(options.root, force)\n if (packageJsonUpdated) created.push('package.json')\n\n console.log(`[clarify] Project scaffold created using the ${selectedTemplate} template.`)\n if (created.length > 0) {\n console.log(`[clarify] Created or updated ${created.length} ${created.length === 1 ? 'file' : 'files'}: ${created.join(', ')}`)\n }\n\n const packageManager = detectPackageManager()\n if (install) {\n installDependencies(options.root, packageManager)\n const suggestedRun = getSuggestedRunCommand(packageManager)\n console.log('[clarify] Dependencies installed successfully.')\n console.log(`[clarify] You can now run \\`${suggestedRun}\\` to start the local documentation server.`)\n return\n }\n\n const suggestedInstall = getSuggestedInstallCommand(packageManager)\n const suggestedRun = getSuggestedRunCommand(packageManager)\n console.log('[clarify] Next steps:')\n console.log(' 1. Change into your new project directory:')\n console.log(` cd ${options.root}`)\n console.log(' 2. Install dependencies:')\n console.log(` ${suggestedInstall}`)\n console.log(' 3. Start the local documentation server:')\n console.log(` ${suggestedRun}`)\n}\n","import { createHash } from 'node:crypto'\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nimport type { McpSiteConfig } from '../../plugins/mcp-search/mcp-config.js'\nimport type { McpSearchResult } from '../../plugins/mcp-search/orama-index.js'\nimport { deserializeSearchIndex, searchMcpIndex } from '../../plugins/mcp-search/orama-index.js'\n\n/**\n * A ready-to-search Orama index loaded for the MCP server.\n *\n * The underlying db is fully in-memory after load, so `search` is synchronous\n * to the index. `dispose` drops the reference so the buffer can be GC'd; it's\n * safe to call multiple times.\n */\nexport type LoadedSearchIndex = {\n /** Search the index. Locale filter is optional. */\n search: (params: { query: string; locale?: string; limit?: number }) => McpSearchResult\n /** Release the in-memory index. Safe to call multiple times. */\n dispose: () => void\n}\n\n/** Re-export so callers can name the result type without reaching into orama-index. */\nexport type { McpSearchResult as SearchResult } from '../../plugins/mcp-search/orama-index.js'\n\nexport type OramaLoaderOptions = {\n /**\n * Root directory for the on-disk cache. Defaults to `~/.clarify/mcp-cache`.\n * Each site gets a subdirectory keyed by a stable hash of its origin + path.\n */\n cacheDir?: string\n /**\n * Bypass the cache and always fetch fresh. Implies purging the cached copy\n * for this site on a successful refresh.\n */\n noCache?: boolean\n /** Optional fetch override (testing). */\n fetchImpl?: typeof fetch\n /** Optional logger (testing). Defaults to no-op. */\n log?: (message: string) => void\n}\n\nconst DEFAULT_CACHE_DIR = () => join(homedir(), '.clarify', 'mcp-cache')\nconst FETCH_TIMEOUT_MS = 60_000\n\n/** Stable per-site cache key. Two URLs with the same origin+path share a cache. */\nfunction siteCacheKey(siteUrl: string): string {\n let url: URL\n try {\n url = new URL(siteUrl)\n } catch {\n throw new Error(`[clarify] Invalid site URL: ${siteUrl}`)\n }\n // Origin + pathname, trailing slash normalized, query/hash ignored.\n // Query/hash are irrelevant for \"where does the site live\" and would\n // fragment the cache unnecessarily.\n const normalized = `${url.origin}${url.pathname.replace(/\\/+$/, '')}`\n return createHash('sha256').update(normalized).digest('hex').slice(0, 16)\n}\n\nasync function fetchBufferWithTimeout(url: string, fetchImpl: typeof fetch, log: (m: string) => void): Promise<Uint8Array> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n try {\n log(`Fetching ${url}`)\n const res = await fetchImpl(url, { signal: controller.signal, redirect: 'follow' })\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} ${res.statusText} fetching ${url}`)\n }\n const buf = await res.arrayBuffer()\n return new Uint8Array(buf)\n } finally {\n clearTimeout(timer)\n }\n}\n\n/**\n * Load the Orama binary index for a remote site and return a ready-to-search\n * handle.\n *\n * The `.msp` index is a single versioned binary file containing a\n * Brotli-compressed, MessagePack-serialized Orama `save()` payload. It is\n * cached on disk so repeated MCP starts don't re-download.\n * Cache validity is keyed by `capabilities.search.indexHash` when available.\n * For older sites that do not emit `indexHash`, we fall back to document\n * count + locale fingerprint matching.\n *\n * The caller must supply the same `defaultLocale` recorded in `mcp.json` so\n * the tokenizer matches the one used at build time. A mismatch would not\n * corrupt data but would cause CJK query terms to be tokenized incorrectly.\n */\nexport async function loadSearchIndex(siteUrl: string, config: McpSiteConfig, options: OramaLoaderOptions = {}): Promise<LoadedSearchIndex> {\n const log = options.log ?? (() => {})\n const fetchImpl = options.fetchImpl ?? fetch\n const cacheDir = options.cacheDir ?? DEFAULT_CACHE_DIR()\n const cacheKey = siteCacheKey(siteUrl)\n const siteCacheDir = join(cacheDir, cacheKey)\n const indexCachePath = join(siteCacheDir, 'mcp-search.msp')\n const manifestPath = join(siteCacheDir, 'manifest.json')\n\n const base = new URL(siteUrl).href\n log(`Site base resolved to ${base}`)\n\n // The index path in mcp.json is root-relative (e.g. `/mcp-search.msp` or\n // `/docs/mcp-search.msp`). Resolve it against the site base.\n const search = config.capabilities.search\n if (!search) {\n throw new Error(`[clarify] mcp.json for ${siteUrl} has no search capability.`)\n }\n const indexUrl = new URL(search.indexPath, base).href\n\n // Cache validity: reuse the cached .msp only when the document count and\n // locale fingerprint recorded at last fetch match the caller-provided\n // config. These change whenever the index is rebuilt with different content.\n const fingerprint = localeFingerprint(config)\n const indexHash = search.indexHash\n let useCache = !options.noCache\n if (useCache) {\n try {\n const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as {\n documentCount?: number\n fingerprint?: string\n indexHash?: string\n }\n if (indexHash) {\n if (manifest.indexHash !== indexHash) {\n log('Cache stale (index hash changed); refetching')\n useCache = false\n }\n } else if (manifest.documentCount !== search.documentCount || manifest.fingerprint !== fingerprint) {\n log('Cache stale (document count or locales changed); refetching')\n useCache = false\n }\n } catch {\n useCache = false\n }\n }\n\n let buffer: Uint8Array | undefined\n if (useCache) {\n try {\n buffer = await readFile(indexCachePath)\n log('Using cached mcp-search.msp')\n } catch {\n // Cache file unreadable; fall through to fetch below.\n }\n }\n\n if (buffer === undefined) {\n const fetched = await fetchBufferWithTimeout(indexUrl, fetchImpl, log)\n buffer = fetched\n // Best-effort persist; failure to cache is non-fatal.\n try {\n await mkdir(siteCacheDir, { recursive: true })\n await writeFile(indexCachePath, fetched)\n await writeFile(\n manifestPath,\n JSON.stringify(\n {\n siteUrl: base,\n fetchedAt: new Date().toISOString(),\n documentCount: search.documentCount,\n fingerprint,\n indexHash,\n },\n null,\n 2,\n ),\n 'utf8',\n )\n log(`Cached mcp-search.msp to ${indexCachePath}`)\n } catch (err) {\n log(`Warning: failed to cache index: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n const defaultLocale = search.defaultLocale\n const db = deserializeSearchIndex(buffer, defaultLocale)\n let disposed = false\n\n return {\n search: ({ query, locale, limit }) => {\n if (disposed) throw new Error('[clarify] Search index already disposed.')\n return searchMcpIndex(db, { query, locale, limit })\n },\n dispose: () => {\n // Orama's in-memory index is plain JS data; dropping the reference is\n // enough for GC. Nothing to flush.\n disposed = true\n },\n }\n}\n\n/**\n * Build a stable fingerprint of the indexed locales so the cache can detect\n * locale-set changes even when the document count happens to stay the same.\n */\nfunction localeFingerprint(config: McpSiteConfig): string {\n return createHash('sha256').update((config.capabilities.search?.locales ?? []).slice().sort().join('|')).digest('hex').slice(0, 16)\n}\n\n/**\n * Remove the on-disk cache for a site. Useful for `--no-cache` cleanup or for\n * tests. No-op if the site has no cache directory.\n */\nexport async function purgeSiteCache(siteUrl: string, cacheDir?: string): Promise<void> {\n const dir = cacheDir ?? DEFAULT_CACHE_DIR()\n const key = siteCacheKey(siteUrl)\n await rm(join(dir, key), { recursive: true, force: true })\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { z } from 'zod'\n\nimport type { McpSiteConfig } from '../../plugins/mcp-search/mcp-config.js'\nimport type { McpSearchHit } from '../../plugins/mcp-search/orama-index.js'\n\nimport type { LoadedSearchIndex } from './orama-loader.js'\n\nexport type SearchServerOptions = {\n /** Optional logger routed to stderr (stdout is the JSON-RPC channel). */\n log?: (message: string) => void\n}\n\n/**\n * A site loaded for the MCP server: its descriptor, ready-to-search index,\n * and the origin URL the index was fetched from (used to resolve relative\n * result paths and to label results by source site).\n */\nexport type LoadedMcpSite = {\n siteUrl: string\n config: McpSiteConfig\n index: LoadedSearchIndex\n}\n\n/** A search hit annotated with the site it came from. */\ntype SourcedHit = McpSearchHit & { site: string }\n\n/**\n * Build the MCP server exposing site search over one or more Clarify sites.\n *\n * Tools registered:\n * - `search_docs`: full-text search across all loaded sites, with each\n * result annotated by its source site.\n *\n * Results are serialized to a compact, LLM-friendly shape: title, URL, site,\n * excerpt, score, and locale. Full page content is intentionally omitted to\n * keep responses within token budgets; clients can fetch the URL themselves.\n */\nexport function createMcpSearchServer(sites: LoadedMcpSite[], options: SearchServerOptions = {}): McpServer {\n const log = options.log ?? (() => {})\n const server = new McpServer({\n name: 'clarify-search',\n version: '1.0.0',\n })\n\n if (sites.length === 0) {\n throw new Error('[clarify] createMcpSearchServer requires at least one loaded site.')\n }\n\n // Aggregate metadata across all loaded sites for the tool description.\n const totalDocs = sites.reduce((sum, site) => sum + (site.config.capabilities.search?.documentCount ?? 0), 0)\n const localeSet = new Set<string>()\n for (const site of sites) {\n for (const locale of site.config.capabilities.search?.locales ?? []) localeSet.add(locale)\n }\n const localeList = [...localeSet]\n const siteTitles = sites\n .map(site => site.config.site.title ?? 'site')\n .filter((title, i, arr) => arr.indexOf(title) === i)\n const siteHint = siteTitles.length === 1\n ? `\"${siteTitles[0]}\"`\n : `${sites.length} sites (${siteTitles.join(', ')})`\n\n const localeHint = localeList.length > 0\n ? ` Available locales: ${localeList.join(', ')}.`\n : ''\n const defaultLocale = sites[0].config.capabilities.search?.defaultLocale\n const defaultLocaleHint = defaultLocale\n ? ` Defaults to \"${defaultLocale}\".`\n : ''\n\n server.registerTool(\n 'search_docs',\n {\n title: 'Search documentation',\n description: [\n `Full-text search over ${siteHint} documentation index.`,\n `Returns ranked results with excerpts, URLs, and source site. The index contains ${totalDocs} pages across ${localeList.length} locale(s).`,\n localeHint,\n defaultLocaleHint,\n 'Pass a `locale` filter to restrict results to a specific language.',\n ].filter(Boolean).join(' '),\n inputSchema: {\n query: z\n .string()\n .min(1)\n .describe('Search query. CJK text is word-segmented automatically; Latin text is split on whitespace/punctuation.'),\n locale: z\n .string()\n .optional()\n .describe(`Filter results to a single locale. One of: ${localeList.join(', ')}.`),\n limit: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe('Maximum results to return. Default 10, max 50.'),\n },\n },\n async ({ query, locale, limit }) => {\n log(`search_docs query=${JSON.stringify(query)} locale=${JSON.stringify(locale)} limit=${limit ?? 10}`)\n\n // Search every loaded site and merge hits. Each hit is annotated with\n // its source site so the caller can tell results apart when multiple\n // sites are loaded. Results are ranked globally by score.\n const allHits: SourcedHit[] = []\n let errorResult: { text: string } | undefined\n for (const site of sites) {\n try {\n const result = site.index.search({ query, locale, limit })\n for (const hit of result.hits) {\n allHits.push({ ...hit, site: site.siteUrl })\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n log(`search failed for ${site.siteUrl}: ${message}`)\n errorResult = { text: `Search failed for ${site.siteUrl}: ${message}` }\n }\n }\n\n if (allHits.length === 0 && errorResult) {\n return {\n isError: true,\n content: [{ type: 'text', text: errorResult.text }],\n }\n }\n\n allHits.sort((a, b) => b.score - a.score)\n const capped = limit ? allHits.slice(0, limit) : allHits.slice(0, 10)\n\n const summary = [\n `Found ${allHits.length} result(s) across ${totalDocs} indexed pages from ${sites.length} site(s).`,\n `Showing top ${capped.length}.`,\n '',\n ].join('\\n')\n\n const text = [summary, ...capped.map((hit, i) => formatResultText(hit, i))].join('\\n---\\n')\n\n return {\n content: [{ type: 'text', text }],\n }\n },\n )\n\n return server\n}\n\n/**\n * Run the search server over stdio until the client disconnects or the process\n * is signaled. Resolves on clean shutdown.\n */\nexport async function runMcpSearchServer(sites: LoadedMcpSite[], options: SearchServerOptions = {}): Promise<void> {\n const log = options.log ?? (() => {})\n const server = createMcpSearchServer(sites, options)\n const transport = new StdioServerTransport()\n // Dispose every search index when the client disconnects. StdioServerTransport\n // calls onclose after stdin closes.\n transport.onclose = () => {\n log('MCP transport closed; disposing search indices')\n for (const site of sites) site.index.dispose()\n }\n await server.connect(transport)\n log(`MCP search server listening on stdio (${sites.length} site(s))`)\n}\n\nfunction formatResultText(hit: SourcedHit, index: number): string {\n const lines = [\n `## ${index + 1}. ${hit.title}`,\n `URL: ${hit.path}`,\n `Site: ${hit.site}`,\n `Score: ${hit.score}`,\n ]\n if (hit.locale) {\n lines.push(`Locale: ${hit.locale}`)\n }\n if (hit.excerpt) {\n lines.push('', hit.excerpt)\n }\n if (hit.description) {\n lines.push('', `Description: ${hit.description}`)\n }\n if (hit.keywords?.length > 0) {\n lines.push('', `Keywords: ${hit.keywords.join(', ')}`)\n }\n return lines.join('\\n')\n}\n","import type { McpSiteConfig } from '../../plugins/mcp-search/mcp-config.js'\nimport { loadSearchIndex } from '../mcp/orama-loader.js'\nimport type { LoadedMcpSite } from '../mcp/search-server.js'\nimport { runMcpSearchServer } from '../mcp/search-server.js'\n\nexport type McpCliOptions = {\n /** Skip the on-disk index cache; always fetch fresh. */\n noCache?: boolean\n /** Optional logger for diagnostics (defaults to stderr). */\n log?: (message: string) => void\n}\n\n/**\n * Start a local MCP server (stdio transport) that exposes full-text search\n * over one or more deployed Clarify sites' Orama indices.\n *\n * For each site:\n * 1. Fetch `<site>/mcp.json` to learn the index path, default locale, and\n * document count. This is a tiny file and avoids hardcoding any\n * assumptions about where the index lives on the site.\n * 2. Use the descriptor to fetch the binary `.msp` index (cached locally\n * keyed by site origin + document count + locale fingerprint) and\n * deserialize it into an in-memory Orama db with the correct tokenizer.\n *\n * Then register the `search_docs` tool, which searches across all loaded\n * sites and merges results (each hit annotated with its source site), and\n * serve over stdio.\n *\n * All logs go to stderr - stdout is reserved for the JSON-RPC protocol.\n */\nexport async function runMcp(siteUrls: string[], options: McpCliOptions = {}): Promise<void> {\n if (siteUrls.length === 0) {\n throw new Error('[clarify] At least one site URL is required. Usage: clarify mcp <site> [site...]')\n }\n\n const log = options.log ?? stderrLog\n const sites: LoadedMcpSite[] = []\n for (const siteUrl of siteUrls) {\n const config = await fetchMcpConfig(siteUrl, fetch, log)\n const search = config.capabilities.search\n if (!search) {\n throw new Error(`[clarify] mcp.json for ${siteUrl} has no search capability. Run a build with search enabled.`)\n }\n log(`Loaded mcp.json for ${siteUrl}: ${search.documentCount} doc(s), ${search.locales.length} locale(s)`)\n\n const index = await loadSearchIndex(siteUrl, config, {\n noCache: options.noCache,\n fetchImpl: fetch,\n log,\n })\n sites.push({ siteUrl, config, index })\n }\n\n await runMcpSearchServer(sites, { log })\n}\n\nfunction stderrLog(message: string): void {\n process.stderr.write(`[clarify] ${message}\\n`)\n}\n\nexport async function fetchMcpConfig(siteUrl: string, fetchImpl: typeof fetch, log: (m: string) => void): Promise<McpSiteConfig> {\n const configUrl = new URL('mcp.json', new URL(siteUrl).href).href\n log(`Fetching ${configUrl}`)\n const res = await fetchImpl(configUrl, { redirect: 'follow' })\n if (!res.ok) {\n throw new Error(\n `[clarify] Failed to fetch mcp.json from ${configUrl} (HTTP ${res.status}). ` +\n 'Ensure the site was built with a recent version of Clarify that emits mcp.json.',\n )\n }\n const config = (await res.json()) as McpSiteConfig\n if (config.version !== 3) {\n throw new Error(`[clarify] Unsupported mcp.json schema version ${config.version}. Please update the clarify CLI.`)\n }\n const search = config.capabilities.search\n if (!search || search.documentCount === 0) {\n throw new Error(`[clarify] mcp.json at ${configUrl} has no indexed documents. Run a build with search enabled.`)\n }\n if (!search.indexPath) {\n throw new Error(`[clarify] mcp.json at ${configUrl} is missing capabilities.search.indexPath.`)\n }\n if (search.indexHash !== undefined && (typeof search.indexHash !== 'string' || search.indexHash.length === 0)) {\n throw new Error(`[clarify] mcp.json at ${configUrl} has an invalid capabilities.search.indexHash.`)\n }\n return config\n}\n","import { resolve } from 'node:path'\n\nexport type CliOptions = {\n root?: string\n content?: string\n output?: string\n host?: string | boolean\n port?: string | number\n open?: boolean | string\n}\n\nexport type ResolvedCliOptions = {\n root: string\n content: string\n output: string\n host?: string | boolean\n port?: number\n open?: boolean | string\n}\n\nfunction resolvePort(port: CliOptions['port']): number | undefined {\n if (port === undefined) return undefined\n\n const parsedPort = typeof port === 'string' ? Number(port) : port\n if (!Number.isInteger(parsedPort) || parsedPort < 1 || parsedPort > 65535) {\n throw new Error('[clarify] --port must be an integer between 1 and 65535')\n }\n\n return parsedPort\n}\n\nexport function resolveCliOptions(options: CliOptions): ResolvedCliOptions {\n return {\n root: resolve(options.root ?? process.cwd()),\n content: options.content ?? 'source',\n output: options.output ?? 'output',\n host: options.host,\n port: resolvePort(options.port),\n open: options.open,\n }\n}\n","import { cac } from 'cac'\n\nimport { runBuild } from './commands/build.js'\nimport { runCheck, type CheckCommandOptions } from './commands/check.js'\nimport { runDev } from './commands/dev.js'\nimport { runInit } from './commands/init.js'\nimport { runMcp, type McpCliOptions } from './commands/mcp.js'\nimport { resolveCliOptions, type CliOptions } from './options.js'\nimport { cliPackageVersion } from './package.js'\n\ntype InitCommandOptions = CliOptions & {\n force?: boolean\n template?: string\n install?: boolean\n}\n\nfunction withBuildOptions(command: ReturnType<ReturnType<typeof cac>['command']>) {\n return command\n .option('--content <dir>', 'Content directory relative to root')\n}\n\nfunction withSharedOptions(command: ReturnType<ReturnType<typeof cac>['command']>) {\n return command\n .option('--root <dir>', 'Project root directory')\n .option('--content <dir>', 'Content directory relative to root')\n .option('--output <dir>', 'Build output directory relative to root')\n}\n\nfunction createCli() {\n const cli = cac('clarify')\n\n cli\n .version(cliPackageVersion)\n .help()\n\n withSharedOptions(cli.command('dev', 'Start the local documentation server'))\n .option('--host [host]', 'Dev server host')\n .option('--port <port>', 'Dev server port')\n .option('--open [path]', 'Open the dev server in a browser')\n .action(async (options: CliOptions) => {\n await runDev(resolveCliOptions(options))\n })\n\n withSharedOptions(cli.command('build', 'Build the static documentation site'))\n .action(async (options: CliOptions) => {\n await runBuild(resolveCliOptions(options))\n })\n\n withSharedOptions(cli.command('check', 'Validate the documentation project'))\n .option('--strict', 'Treat warnings as failures')\n .option('--format <format>', 'Output format: text or json')\n .action(async (options: CheckCommandOptions) => {\n await runCheck(options)\n })\n\n withBuildOptions(cli.command('init [directory]', 'Create a Clarify project scaffold'))\n .option('--force', 'Overwrite files created by init')\n .option('--template <name>', 'Template to use: minimal, standard, or complete')\n .option('--install', 'Install dependencies after init')\n .action((directory: string | undefined, options: InitCommandOptions) => {\n runInit(resolveCliOptions({ ...options, root: directory }), options.force === true, options.template, options.install === true)\n })\n\n cli\n .command('mcp <...site>', 'Start a local MCP server exposing full-text search over one or more deployed sites')\n .option('--no-cache', 'Skip the local search index cache and always fetch fresh')\n .action(async (sites: string[], options: McpCliOptions) => {\n await runMcp(sites, { noCache: options.noCache === true })\n })\n\n return cli\n}\n\nexport async function main(argv = process.argv): Promise<void> {\n const cli = createCli()\n const args = argv.slice(2)\n cli.parse(argv, { run: false })\n\n if (args.length === 0) {\n cli.outputHelp()\n return\n }\n\n await cli.runMatchedCommand()\n}\n","#!/usr/bin/env node\nimport { main } from './program.js'\n\nmain().catch(error => {\n console.error(error instanceof Error ? error.stack ?? error.message : String(error))\n process.exitCode = 1\n})\n"],"mappings":"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"}
@@ -49,6 +49,7 @@ let vite = require("vite");
49
49
  let zod = require("zod");
50
50
  let yaml = require("yaml");
51
51
  let node_crypto = require("node:crypto");
52
+ let node_zlib = require("node:zlib");
52
53
  let _msgpack_msgpack = require("@msgpack/msgpack");
53
54
  let _orama_orama = require("@orama/orama");
54
55
  let node_url = require("node:url");
@@ -1588,7 +1589,7 @@ function createViteAdapter(engine) {
1588
1589
  }
1589
1590
  var cliPackageVersion = {
1590
1591
  name: "@clarify-labs/cli",
1591
- version: "0.11.2",
1592
+ version: "0.11.3",
1592
1593
  license: "AGPL-3.0-only",
1593
1594
  type: "module",
1594
1595
  repository: {
@@ -1970,6 +1971,22 @@ function createMcpSiteConfig(projectConfig, options) {
1970
1971
  }
1971
1972
  //#endregion
1972
1973
  //#region source/plugins/mcp-search/orama-index.ts
1974
+ var MSP_MAGIC = new Uint8Array([
1975
+ 67,
1976
+ 76,
1977
+ 65,
1978
+ 82,
1979
+ 73,
1980
+ 70,
1981
+ 89,
1982
+ 77,
1983
+ 83,
1984
+ 80,
1985
+ 1
1986
+ ]);
1987
+ function hasMspMagic(buffer) {
1988
+ return buffer.byteLength >= MSP_MAGIC.byteLength && MSP_MAGIC.every((byte, index) => buffer[index] === byte);
1989
+ }
1973
1990
  /**
1974
1991
  * Orama schema for the MCP search index.
1975
1992
  *
@@ -2208,17 +2225,22 @@ function guessTitleFromPath(path) {
2208
2225
  return segments[segments.length - 1].replace(/\.(md|mdx|html)$/, "").replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2209
2226
  }
2210
2227
  /**
2211
- * Serialize an Orama index to a msgpack binary buffer.
2228
+ * Serialize an Orama index to a versioned, Brotli-compressed binary buffer.
2212
2229
  *
2213
- * Uses `save()` to extract the raw index data, then msgpack-encodes it for a
2214
- * compact binary representation. The same schema + tokenizer must be supplied
2215
- * when loading so query-time tokenization matches indexing-time tokenization.
2230
+ * Uses `save()` to extract the raw index data, MessagePack-encodes it, then
2231
+ * compresses the payload so source documents are not embedded as contiguous
2232
+ * plaintext. The leading magic bytes identify the container and its version.
2216
2233
  */
2217
2234
  function serializeSearchIndex(db) {
2218
- return (0, _msgpack_msgpack.encode)((0, _orama_orama.save)(db));
2235
+ const compressed = (0, node_zlib.brotliCompressSync)((0, _msgpack_msgpack.encode)((0, _orama_orama.save)(db)), { params: { [node_zlib.constants.BROTLI_PARAM_QUALITY]: 9 } });
2236
+ const buffer = new Uint8Array(MSP_MAGIC.byteLength + compressed.byteLength);
2237
+ buffer.set(MSP_MAGIC);
2238
+ buffer.set(compressed, MSP_MAGIC.byteLength);
2239
+ return buffer;
2219
2240
  }
2220
2241
  /**
2221
- * Deserialize a msgpack binary buffer into a ready-to-search Orama index.
2242
+ * Deserialize a current compressed container or legacy MessagePack buffer
2243
+ * into a ready-to-search Orama index.
2222
2244
  *
2223
2245
  * The caller must supply the same `defaultLocale` used when the index was
2224
2246
  * built, so the tokenizer matches. A mismatch would not corrupt data but
@@ -2226,7 +2248,7 @@ function serializeSearchIndex(db) {
2226
2248
  * as a single token instead of split into "文" + "档").
2227
2249
  */
2228
2250
  function deserializeSearchIndex(buffer, defaultLocale) {
2229
- const raw = (0, _msgpack_msgpack.decode)(buffer);
2251
+ const raw = (0, _msgpack_msgpack.decode)(hasMspMagic(buffer) ? (0, node_zlib.brotliDecompressSync)(buffer.subarray(MSP_MAGIC.byteLength)) : buffer);
2230
2252
  const db = createMcpSearchIndex(defaultLocale);
2231
2253
  (0, _orama_orama.load)(db, raw);
2232
2254
  return db;
@@ -3856,4 +3878,4 @@ Object.defineProperty(exports, "searchMcpIndex", {
3856
3878
  }
3857
3879
  });
3858
3880
 
3859
- //# sourceMappingURL=engine--5unu78V.cjs.map
3881
+ //# sourceMappingURL=engine-6WmOk7xk.cjs.map