{"version":3,"sources":["../../src/core/types.ts","../../src/core/utils.ts","../../src/core/registry.ts","../../src/core/search.ts","../../src/core/keywords.ts","../../src/core/access-control.ts","../../src/core/frecency.ts","../../src/core/frecency-storage.ts","../../src/core/grouping.ts","../../src/core/context.ts","../../src/core/i18n.ts","../../src/core/search-history.ts"],"names":["items"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ReactNode } from 'react'\n\n// ============================================================\n// Command Definition\n// ============================================================\n\n/** A single command item in the palette */\nexport interface CommandItem {\n  /** Unique identifier */\n  id: string\n  /** Display label shown in the palette */\n  label: string\n  /** Optional description text */\n  description?: string\n  /** Icon — string, emoji, or React element (e.g. `<Settings size={16} />`) */\n  icon?: ReactNode\n  /** Additional search terms for fuzzy matching */\n  keywords?: string[]\n  /** Group this command belongs to */\n  group?: string\n  /** Manual ordering weight (higher = appears first) */\n  priority?: number\n  /** Navigation target URL/path for route commands */\n  href?: string\n  /** Execution callback when command is selected */\n  action?: (item: CommandItem) => void | Promise<void>\n  /** Whether this command is disabled */\n  disabled?: boolean\n  /** Hidden from results but still searchable */\n  hidden?: boolean\n  /** Required permissions to see this command */\n  permissions?: string[]\n  /** Keyboard shortcut display (e.g., [\"g\", \"h\"]) */\n  shortcut?: string[]\n  /** Extensible metadata for consumer use */\n  meta?: Record<string, unknown>\n  /** Scopes where this command is most relevant (e.g., ['/billing', '/billing/*']) */\n  scope?: string[]\n  /** Child commands for nested/hierarchical menus */\n  children?: CommandItem[]\n  /** Parent command ID (set automatically when flattening) */\n  parentId?: string\n}\n\n// ============================================================\n// Registry\n// ============================================================\n\n/** Command registry — the central store for all commands */\nexport interface CommandRegistry {\n  /** Register a single command. Returns an unregister function. */\n  register(command: CommandItem): () => void\n  /** Register multiple commands. Returns an unregister function for all. */\n  registerMany(commands: CommandItem[]): () => void\n  /** Update a command by ID with partial fields */\n  update(id: string, partial: Partial<CommandItem>): void\n  /** Remove a command by ID */\n  unregister(id: string): void\n  /** Get all registered commands */\n  getAll(): CommandItem[]\n  /** Get a command by ID */\n  getById(id: string): CommandItem | undefined\n  /** Get commands in a specific group */\n  getByGroup(groupId: string): CommandItem[]\n  /** Subscribe to changes. Returns an unsubscribe function. */\n  subscribe(listener: () => void): () => void\n  /** Get a stable snapshot for useSyncExternalStore */\n  getSnapshot(): CommandItem[]\n}\n\n// ============================================================\n// Search\n// ============================================================\n\n/** A search engine implementation */\nexport interface SearchEngine {\n  /** Search items against a query string. Returns scored results. */\n  search(query: string, items: CommandItem[]): ScoredItem[]\n}\n\n/** A command item with a relevance score */\nexport interface ScoredItem {\n  /** The matched command item */\n  item: CommandItem\n  /** Relevance score from 0 (worst) to 1 (best match) */\n  score: number\n}\n\n// ============================================================\n// Access Control\n// ============================================================\n\n/** Interface for checking user permissions */\nexport interface AccessControlProvider {\n  /** Check if user has a specific permission */\n  hasPermission(permission: string): boolean\n  /** Check if user has ANY of the given permissions */\n  hasAnyPermission(permissions: string[]): boolean\n  /** Check if user has ALL of the given permissions */\n  hasAllPermissions(permissions: string[]): boolean\n}\n\n/** Access control check mode */\nexport type AccessCheckMode = 'any' | 'all'\n\n// ============================================================\n// Frecency\n// ============================================================\n\n/** A single frecency tracking entry */\nexport interface FrecencyEntry {\n  /** Command ID */\n  id: string\n  /** Number of times used */\n  count: number\n  /** Unix timestamp of last use */\n  lastUsed: number\n  /** Decayed score based on frequency + recency */\n  halfLifeScore: number\n}\n\n/** Storage backend for frecency data */\nexport interface FrecencyStorage {\n  /** Get entry by key */\n  get(key: string): FrecencyEntry | null\n  /** Set entry */\n  set(key: string, entry: FrecencyEntry): void\n  /** Get all entries */\n  getAll(): FrecencyEntry[]\n  /** Clear all entries */\n  clear(): void\n}\n\n/** Frecency engine configuration */\nexport interface FrecencyOptions {\n  /** Storage backend (defaults to localStorage) */\n  storage?: FrecencyStorage\n  /** localStorage key prefix (default: 'cmdk-frecency') */\n  storageKey?: string\n  /** Max age in days before entries are removed (default: 30) */\n  maxAge?: number\n  /** Half-life in days for exponential decay (default: 7) */\n  halfLife?: number\n}\n\n// ============================================================\n// Groups\n// ============================================================\n\n/** A command group definition */\nexport interface CommandGroup {\n  /** Unique group identifier */\n  id: string\n  /** Display label for the group */\n  label: string\n  /** Rendering priority (higher = rendered first) */\n  priority?: number\n  /** Optional icon for the group */\n  icon?: ReactNode\n}\n\n// ============================================================\n// Keywords / Synonyms\n// ============================================================\n\n/** Map of keyword → synonyms */\nexport interface SynonymMap {\n  [keyword: string]: string[]\n}\n\n// ============================================================\n// Route Adapter\n// ============================================================\n\n/** Metadata for a route command, colocated in route definitions */\nexport interface RouteCommandMeta {\n  /** Display label (falls back to path-derived label) */\n  label?: string\n  /** Description text */\n  description?: string\n  /** Additional search keywords */\n  keywords?: string[]\n  /** Group ID */\n  group?: string\n  /** Icon — string, emoji, or React element */\n  icon?: ReactNode\n  /** Required permissions */\n  permissions?: string[]\n  /** Ordering priority */\n  priority?: number\n  /** Whether to hide from palette */\n  hidden?: boolean\n}\n\n// ============================================================\n// CLI Config\n// ============================================================\n\n/** Configuration file shape for cmdk-engine.config.ts */\nexport interface CmdkEngineConfig {\n  /** Framework to scan (auto-detected if not set) */\n  framework?: 'react-router' | 'nextjs-app' | 'nextjs-pages' | 'custom'\n  /** Directory to scan for routes */\n  routesDir?: string\n  /** Output file for generated route map */\n  output?: string\n  /** Custom keyword/metadata overrides per route path */\n  overrides?: Record<string, Partial<RouteCommandMeta>>\n  /** Route paths/patterns to exclude */\n  exclude?: string[]\n  /** Synonym dictionary */\n  synonyms?: SynonymMap\n}\n\n/** Generated route sitemap entry */\nexport interface SitemapRoute {\n  /** Unique route ID */\n  id: string\n  /** Route path */\n  path: string\n  /** Display label */\n  label: string\n  /** Search keywords */\n  keywords: string[]\n  /** Group name */\n  group?: string\n  /** Source file path */\n  source?: string\n}\n\n/** Full generated sitemap output */\nexport interface Sitemap {\n  /** Schema version */\n  version: number\n  /** Generation timestamp (ISO 8601) */\n  generatedAt: string\n  /** Detected framework */\n  framework: string\n  /** All discovered routes */\n  routes: SitemapRoute[]\n}\n\n// ============================================================\n// Context / Scope\n// ============================================================\n\n/** Current app context for scope-aware command boosting */\nexport interface CommandContext {\n  /** Current path/URL (e.g., '/billing/overview') */\n  path?: string\n  /** Current page/section tags for matching */\n  tags?: string[]\n}\n\n// ============================================================\n// i18n\n// ============================================================\n\n/** Translation function — maps a key to a localized string */\nexport type TranslationFn = (key: string, params?: Record<string, string | number>) => string\n\n// ============================================================\n// Search History\n// ============================================================\n\n/** A recorded search query */\nexport interface SearchHistoryEntry {\n  /** The search query string */\n  query: string\n  /** Timestamp when the search was performed */\n  timestamp: number\n  /** Number of results returned */\n  resultCount: number\n}\n\n/** Configuration for search history tracking */\nexport interface SearchHistoryConfig {\n  /** Enable search history tracking (default: false) */\n  enabled?: boolean\n  /** Maximum history entries to keep (default: 20) */\n  maxEntries?: number\n  /** localStorage key prefix (default: 'cmdk-search-history') */\n  storageKey?: string\n  /** Minimum query length to record (default: 2) */\n  minQueryLength?: number\n}\n\n// ============================================================\n// Palette State (used by React hooks)\n// ============================================================\n\n/** Full command palette state */\nexport interface CommandPaletteState {\n  /** Current search query */\n  search: string\n  /** Filtered and ranked results */\n  results: ScoredItem[]\n  /** Available groups (only groups with visible items) */\n  groups: CommandGroup[]\n  /** Whether the palette is open */\n  isOpen: boolean\n  /** Whether results are loading (async) */\n  isLoading: boolean\n  /** Breadcrumb trail of parent commands (for nested navigation) */\n  breadcrumbs: CommandItem[]\n  /** Current nesting depth (0 = root) */\n  depth: number\n}\n\n// ============================================================\n// Engine Config (React Provider)\n// ============================================================\n\n/** Configuration for the CommandEngine React provider */\nexport interface CommandEngineConfig {\n  /** Custom search engine (defaults to built-in fuzzy search) */\n  searchEngine?: SearchEngine\n  /** Access control provider for permission filtering */\n  accessControl?: AccessControlProvider\n  /** Access check mode: 'any' or 'all' permissions required */\n  accessCheckMode?: AccessCheckMode\n  /** Synonym dictionary for keyword expansion */\n  synonyms?: SynonymMap\n  /** Frecency configuration */\n  frecency?: FrecencyOptions & RecentCommandsConfig\n  /** Group definitions and ordering */\n  groups?: CommandGroup[]\n  /** Maximum results to return */\n  maxResults?: number\n  /** Centralized handler when a command is selected. Auto-records frecency. */\n  onSelect?: (item: CommandItem) => void\n  /** Current context for scope-aware command boosting */\n  context?: CommandContext\n  /** Boost weight for in-scope commands (0-1, default: 0.2) */\n  contextBoostWeight?: number\n  /** Translation function for UI strings (defaults to English) */\n  t?: TranslationFn\n  /** Locale for collation-aware operations (default: 'en') */\n  locale?: string\n  /** Search history configuration */\n  searchHistory?: SearchHistoryConfig\n}\n\n/** Configuration for the \"Recent\" commands group */\nexport interface RecentCommandsConfig {\n  /** Show a \"Recent\" group when search is empty (default: false) */\n  showRecent?: boolean\n  /** Number of recent items to show (default: 5) */\n  recentCount?: number\n  /** Label for the recent group (default: \"Recent\") */\n  recentLabel?: string\n}\n\n// ============================================================\n// Helpers\n// ============================================================\n\n/** Helper to define a cmdk-engine config file with type checking */\nexport function defineConfig(config: CmdkEngineConfig): CmdkEngineConfig {\n  return config\n}\n","/**\n * Schedule a microtask-batched callback. Multiple calls within the same\n * microtask only execute the callback once.\n */\nexport function createBatchScheduler(): (fn: () => void) => void {\n  let scheduled = false\n\n  return (fn: () => void) => {\n    if (scheduled) return\n    scheduled = true\n    queueMicrotask(() => {\n      scheduled = false\n      fn()\n    })\n  }\n}\n\n/**\n * Convert a path segment to a readable label.\n * Handles kebab-case, snake_case, camelCase, PascalCase.\n *\n * Examples:\n *  \"user-settings\" -> \"User Settings\"\n *  \"phone_numbers\" -> \"Phone Numbers\"\n *  \"phoneNumbers\"  -> \"Phone Numbers\"\n *  \"BillingOverview\" -> \"Billing Overview\"\n */\nexport function pathSegmentToLabel(segment: string): string {\n  return (\n    segment\n      // Insert space before uppercase letters in camelCase/PascalCase\n      .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n      // Replace hyphens and underscores with spaces\n      .replace(/[-_]/g, ' ')\n      // Capitalize first letter of each word\n      .replace(/\\b\\w/g, (c) => c.toUpperCase())\n      .trim()\n  )\n}\n\n/**\n * Convert a full path to a readable label.\n * Uses the last meaningful segment.\n *\n * \"/billing/overview\" -> \"Billing Overview\"\n * \"/settings\" -> \"Settings\"\n * \"/\" -> \"Home\"\n */\nexport function pathToLabel(path: string): string {\n  if (path === '/' || path === '') return 'Home'\n\n  const segments = path.split('/').filter(Boolean)\n  // Filter out dynamic segments like :id, [id], etc.\n  const meaningful = segments.filter((s) => !s.startsWith(':') && !s.startsWith('['))\n  const last = meaningful[meaningful.length - 1]\n\n  return last ? pathSegmentToLabel(last) : 'Home'\n}\n\n/**\n * Convert a full path to a group name.\n * Uses the first meaningful segment.\n *\n * \"/billing/overview\" -> \"Billing\"\n * \"/settings/team\" -> \"Settings\"\n */\nexport function pathToGroup(path: string): string | undefined {\n  const segments = path.split('/').filter(Boolean)\n  const first = segments[0]\n\n  if (!first || segments.length <= 1) return undefined\n  return pathSegmentToLabel(first)\n}\n\n/**\n * Generate a stable ID from a route path.\n * \"/billing/overview\" -> \"billing-overview\"\n */\nexport function pathToId(path: string): string {\n  return path\n    .replace(/^\\//, '')\n    .replace(/\\/$/, '')\n    .replace(/\\//g, '--')\n    .replace(/[^a-zA-Z0-9-]/g, '')\n    .toLowerCase() || 'home'\n}\n","import type { CommandItem, CommandRegistry } from './types'\nimport { createBatchScheduler } from './utils'\n\n/**\n * Create a new command registry — the central store for all commands.\n *\n * The registry implements a pub/sub pattern compatible with React's\n * useSyncExternalStore. Commands can be registered, updated, and removed,\n * and subscribers are notified of changes via batched microtask updates.\n */\nexport function createRegistry(): CommandRegistry {\n  const commands = new Map<string, CommandItem>()\n  const listeners = new Set<() => void>()\n  const schedule = createBatchScheduler()\n\n  // Cached snapshot — only recalculated when commands change\n  let snapshot: CommandItem[] = []\n  let snapshotDirty = true\n\n  function notify(): void {\n    schedule(() => {\n      for (const listener of listeners) {\n        listener()\n      }\n    })\n  }\n\n  function invalidateSnapshot(): void {\n    snapshotDirty = true\n    notify()\n  }\n\n  function register(command: CommandItem): () => void {\n    commands.set(command.id, { ...command })\n    invalidateSnapshot()\n    return () => unregister(command.id)\n  }\n\n  function registerMany(items: CommandItem[]): () => void {\n    for (const item of items) {\n      commands.set(item.id, { ...item })\n    }\n    invalidateSnapshot()\n    return () => {\n      for (const item of items) {\n        commands.delete(item.id)\n      }\n      invalidateSnapshot()\n    }\n  }\n\n  function update(id: string, partial: Partial<CommandItem>): void {\n    const existing = commands.get(id)\n    if (!existing) return\n    commands.set(id, { ...existing, ...partial })\n    invalidateSnapshot()\n  }\n\n  function unregister(id: string): void {\n    if (commands.delete(id)) {\n      invalidateSnapshot()\n    }\n  }\n\n  function getAll(): CommandItem[] {\n    return Array.from(commands.values())\n  }\n\n  function getById(id: string): CommandItem | undefined {\n    return commands.get(id)\n  }\n\n  function getByGroup(groupId: string): CommandItem[] {\n    return getAll().filter((cmd) => cmd.group === groupId)\n  }\n\n  function subscribe(listener: () => void): () => void {\n    listeners.add(listener)\n    return () => {\n      listeners.delete(listener)\n    }\n  }\n\n  function getSnapshot(): CommandItem[] {\n    if (snapshotDirty) {\n      snapshot = Array.from(commands.values())\n      snapshotDirty = false\n    }\n    return snapshot\n  }\n\n  return {\n    register,\n    registerMany,\n    update,\n    unregister,\n    getAll,\n    getById,\n    getByGroup,\n    subscribe,\n    getSnapshot,\n  }\n}\n","import type { CommandItem, SearchEngine, ScoredItem } from './types'\n\n/**\n * Built-in lightweight fuzzy search engine.\n * Searches label, description, and keywords fields.\n * No external dependencies. Target: < 1KB gzipped.\n *\n * Scoring bonuses:\n * - Exact prefix match (highest)\n * - Word boundary match\n * - Consecutive character matches\n * - Case-sensitive exact match\n */\nexport function createFuzzySearch(): SearchEngine {\n  return {\n    search(query: string, items: CommandItem[]): ScoredItem[] {\n      if (!query || query.trim() === '') {\n        // Empty query returns all items with max score, sorted by priority\n        return items\n          .filter((item) => !item.hidden)\n          .map((item) => ({ item, score: 1 }))\n          .sort((a, b) => (b.item.priority ?? 0) - (a.item.priority ?? 0))\n      }\n\n      const normalizedQuery = query.toLowerCase().trim()\n      const results: ScoredItem[] = []\n\n      for (const item of items) {\n        if (item.hidden) continue\n\n        const score = scoreItem(normalizedQuery, item)\n        if (score > 0) {\n          results.push({ item, score })\n        }\n      }\n\n      // Sort by score descending, then by priority descending\n      results.sort((a, b) => {\n        const scoreDiff = b.score - a.score\n        if (Math.abs(scoreDiff) > 0.001) return scoreDiff\n        return (b.item.priority ?? 0) - (a.item.priority ?? 0)\n      })\n\n      return results\n    },\n  }\n}\n\n/**\n * Score a single item against a query.\n * Returns 0 if no match, up to 1 for perfect match.\n *\n * Scoring weights:\n * - Label:            1.0x  (exact label match is highest signal)\n * - Original keywords: 0.85x (user explicitly tagged these)\n * - Description:      0.7x\n * - Synonym keywords:  0.55x (injected by keyword engine, lower confidence)\n */\nfunction scoreItem(query: string, item: CommandItem): number {\n  let bestScore = 0\n\n  // Score against label (highest weight)\n  bestScore = Math.max(bestScore, fuzzyScore(query, item.label.toLowerCase()) * 1.0)\n\n  // Score against description (medium weight)\n  if (item.description) {\n    bestScore = Math.max(bestScore, fuzzyScore(query, item.description.toLowerCase()) * 0.7)\n  }\n\n  // Score against original keywords (medium-high weight)\n  if (item.keywords) {\n    for (const kw of item.keywords) {\n      bestScore = Math.max(bestScore, fuzzyScore(query, kw.toLowerCase()) * 0.85)\n    }\n  }\n\n  // Score against synonym-expanded keywords (lower weight)\n  const synonymKeywords = (item.meta?._synonymKeywords as string[] | undefined)\n  if (synonymKeywords) {\n    for (const kw of synonymKeywords) {\n      bestScore = Math.max(bestScore, fuzzyScore(query, kw.toLowerCase()) * 0.55)\n    }\n  }\n\n  const finalScore = Math.min(bestScore, 1)\n\n  // Reject very low-confidence matches\n  if (finalScore < 0.15) return 0\n\n  return finalScore\n}\n\n/**\n * Fuzzy match a query against a target string.\n * Returns a score between 0 and 1.\n *\n * Scoring tiers:\n * - Exact match: 1.0\n * - Prefix match: 0.95\n * - Substring match: 0.8\n * - Word initials: 0.7\n * - Fuzzy (consecutive chars): up to 0.6\n * - Fuzzy (scattered chars): heavily penalized, often rejected\n */\nfunction fuzzyScore(query: string, target: string): number {\n  if (query === target) return 1 // Exact match\n  if (target.startsWith(query)) return 0.95 // Prefix match\n  if (target.includes(query)) return 0.8 // Substring match\n\n  // Check word boundary matches\n  const words = target.split(/[\\s\\-_]+/)\n  const wordInitials = words.map((w) => w[0]).join('')\n  if (wordInitials.includes(query)) return 0.7 // Initials match (e.g., \"bs\" matches \"Billing Settings\")\n\n  // Fuzzy character-by-character matching\n  let queryIdx = 0\n  let currentConsecutive = 0\n  let maxConsecutive = 0\n  let totalBonus = 0\n  let matchCount = 0\n  let totalGaps = 0\n  let lastMatchIdx = -1\n\n  for (let i = 0; i < target.length && queryIdx < query.length; i++) {\n    if (target[i] === query[queryIdx]) {\n      matchCount++\n      queryIdx++\n\n      // Track gaps between matches\n      if (lastMatchIdx >= 0) {\n        totalGaps += i - lastMatchIdx - 1\n      }\n      lastMatchIdx = i\n\n      // Track consecutive matches\n      currentConsecutive++\n      if (currentConsecutive > maxConsecutive) {\n        maxConsecutive = currentConsecutive\n      }\n      totalBonus += currentConsecutive * 0.1\n\n      // Bonus for word boundary match\n      if (i === 0 || /[\\s\\-_]/.test(target[i - 1])) {\n        totalBonus += 0.15\n      }\n    } else {\n      currentConsecutive = 0\n    }\n  }\n\n  // All query characters must match\n  if (queryIdx < query.length) return 0\n\n  // Contiguity ratio: how consecutive are the matches?\n  const contiguityRatio = matchCount > 0 ? maxConsecutive / matchCount : 0\n\n  // Aggressive penalty for scattered matches (contiguity < 50%)\n  // If most chars are scattered, the match is likely a false positive\n  const contiguityMultiplier =\n    contiguityRatio < 0.5\n      ? contiguityRatio * 0.5 // Very scattered: 0 to 0.25x\n      : 0.4 + 0.6 * contiguityRatio // Mostly consecutive: 0.7 to 1.0x\n\n  // Average gap penalty\n  const avgGap = matchCount > 1 ? totalGaps / (matchCount - 1) : 0\n  const gapPenalty = avgGap > 3 ? 0.15 : 0\n\n  // Base score from match ratio + bonuses\n  const matchRatio = matchCount / target.length\n  const rawScore = 0.2 + matchRatio * 0.3 + Math.min(totalBonus, 0.4)\n  const score = (rawScore - gapPenalty) * contiguityMultiplier\n\n  return Math.min(Math.max(score, 0), 0.6) // Cap fuzzy matches well below substring matches\n}\n","import type { CommandItem, SynonymMap } from './types'\n\n/**\n * Create a keyword engine for synonym expansion and user alias management.\n *\n * The engine enriches command items with additional searchable keywords\n * based on a synonym dictionary and optional user-defined aliases.\n */\nexport function createKeywordEngine(\n  synonyms: SynonymMap = {},\n  userAliases: Map<string, string[]> = new Map(),\n) {\n  return {\n    /**\n     * Expand a search query using the synonym dictionary.\n     * Returns the original query plus any synonym matches.\n     *\n     * e.g., query \"money\" with synonyms { billing: [\"money\", \"payment\"] }\n     * returns [\"money\", \"billing\"]\n     */\n    expandQuery(query: string): string[] {\n      const q = query.toLowerCase().trim()\n      if (!q) return []\n\n      const expanded = new Set<string>([q])\n\n      for (const [key, values] of Object.entries(synonyms)) {\n        const lowerValues = values.map((v) => v.toLowerCase())\n        // If query matches a synonym value, add the key\n        if (lowerValues.includes(q)) {\n          expanded.add(key.toLowerCase())\n        }\n        // If query matches a key, add all synonym values\n        if (key.toLowerCase() === q) {\n          for (const v of lowerValues) {\n            expanded.add(v)\n          }\n        }\n      }\n\n      return Array.from(expanded)\n    },\n\n    /**\n     * Enrich a command item's keywords with synonyms and user aliases.\n     * Returns a new CommandItem with original keywords preserved and\n     * synonym-expanded keywords stored separately in meta._synonymKeywords.\n     * This lets the search engine score original keywords higher.\n     */\n    enrichItem(item: CommandItem): CommandItem {\n      const originalKeywords = new Set<string>(item.keywords ?? [])\n      const synonymKeywords = new Set<string>()\n\n      // Add synonyms for existing keywords\n      for (const kw of item.keywords ?? []) {\n        const kwLower = kw.toLowerCase()\n        if (synonyms[kwLower]) {\n          for (const syn of synonyms[kwLower]) {\n            if (!originalKeywords.has(syn)) synonymKeywords.add(syn)\n          }\n        }\n        for (const [key, values] of Object.entries(synonyms)) {\n          if (values.map((v) => v.toLowerCase()).includes(kwLower)) {\n            if (!originalKeywords.has(key)) synonymKeywords.add(key)\n          }\n        }\n      }\n\n      // Add synonyms for the label\n      const labelLower = item.label.toLowerCase()\n      for (const [key, values] of Object.entries(synonyms)) {\n        if (key.toLowerCase() === labelLower) {\n          for (const v of values) {\n            if (!originalKeywords.has(v)) synonymKeywords.add(v)\n          }\n        }\n        if (values.map((v) => v.toLowerCase()).includes(labelLower)) {\n          if (!originalKeywords.has(key)) synonymKeywords.add(key)\n        }\n      }\n\n      // Add user aliases as original keywords (user explicitly added these)\n      const aliases = userAliases.get(item.id)\n      if (aliases) {\n        for (const alias of aliases) {\n          originalKeywords.add(alias)\n        }\n      }\n\n      return {\n        ...item,\n        keywords: Array.from(originalKeywords),\n        meta: {\n          ...item.meta,\n          ...(synonymKeywords.size > 0\n            ? { _synonymKeywords: Array.from(synonymKeywords) }\n            : {}),\n        },\n      }\n    },\n\n    /**\n     * Enrich all items in a list.\n     */\n    enrichAll(items: CommandItem[]): CommandItem[] {\n      return items.map((item) => this.enrichItem(item))\n    },\n\n    /**\n     * Add a user alias for a command.\n     */\n    addAlias(commandId: string, alias: string): void {\n      const existing = userAliases.get(commandId) ?? []\n      if (!existing.includes(alias)) {\n        userAliases.set(commandId, [...existing, alias])\n      }\n    },\n\n    /**\n     * Remove a user alias for a command.\n     */\n    removeAlias(commandId: string, alias: string): void {\n      const existing = userAliases.get(commandId) ?? []\n      userAliases.set(\n        commandId,\n        existing.filter((a) => a !== alias),\n      )\n    },\n\n    /**\n     * Get all user aliases.\n     */\n    getAliases(): Map<string, string[]> {\n      return new Map(userAliases)\n    },\n\n    /**\n     * Set the synonym dictionary.\n     */\n    setSynonyms(newSynonyms: SynonymMap): void {\n      Object.keys(synonyms).forEach((k) => delete synonyms[k])\n      Object.assign(synonyms, newSynonyms)\n    },\n  }\n}\n","import type { AccessCheckMode, AccessControlProvider, CommandItem } from './types'\n\n/**\n * Create an access control filter that removes commands the user\n * doesn't have permission to see.\n *\n * This is a UI filter, not a security boundary. Always enforce\n * permissions server-side.\n *\n * @param provider - The permission checking backend\n * @param mode - 'any' = user needs any listed permission, 'all' = needs all (default: 'any')\n */\nexport function createAccessFilter(\n  provider: AccessControlProvider,\n  mode: AccessCheckMode = 'any',\n): (items: CommandItem[]) => CommandItem[] {\n  return (items: CommandItem[]) => {\n    return items.filter((item) => {\n      // No permissions required = open to all\n      if (!item.permissions || item.permissions.length === 0) {\n        return true\n      }\n\n      if (mode === 'all') {\n        return provider.hasAllPermissions(item.permissions)\n      }\n\n      return provider.hasAnyPermission(item.permissions)\n    })\n  }\n}\n\n/**\n * Create a simple access control provider from a set of permissions.\n * Useful for static permission sets.\n */\nexport function createSimpleAccessProvider(\n  userPermissions: string[] | Set<string>,\n): AccessControlProvider {\n  const perms = userPermissions instanceof Set ? userPermissions : new Set(userPermissions)\n\n  return {\n    hasPermission(permission: string): boolean {\n      return perms.has(permission)\n    },\n\n    hasAnyPermission(permissions: string[]): boolean {\n      return permissions.some((p) => perms.has(p))\n    },\n\n    hasAllPermissions(permissions: string[]): boolean {\n      return permissions.every((p) => perms.has(p))\n    },\n  }\n}\n","import type { FrecencyEntry, FrecencyOptions, FrecencyStorage, ScoredItem } from './types'\n\nconst DEFAULT_HALF_LIFE = 7 // days\nconst DEFAULT_MAX_AGE = 30 // days\nconst MS_PER_DAY = 86_400_000\n\n/**\n * Create a frecency engine that tracks usage patterns and\n * ranks items by frequency + recency using exponential decay.\n *\n * Algorithm:\n *   score = count * 2^(-timeSinceLastUse / halfLife)\n *\n * This means:\n * - An item used 10 times yesterday ranks higher than one used 100 times a month ago\n * - The half-life (default 7 days) controls how quickly old usage decays\n */\nexport function createFrecencyEngine(options: FrecencyOptions = {}) {\n  const halfLife = options.halfLife ?? DEFAULT_HALF_LIFE\n  const maxAge = options.maxAge ?? DEFAULT_MAX_AGE\n  const storage = options.storage ?? createInMemoryStorage()\n\n  /**\n   * Record that a command was used.\n   */\n  function recordUsage(commandId: string): void {\n    const now = Date.now()\n    const existing = storage.get(commandId)\n\n    const entry: FrecencyEntry = {\n      id: commandId,\n      count: (existing?.count ?? 0) + 1,\n      lastUsed: now,\n      halfLifeScore: 0, // Will be calculated\n    }\n\n    entry.halfLifeScore = calculateScore(entry, now)\n    storage.set(commandId, entry)\n  }\n\n  /**\n   * Calculate the decayed score for an entry at a given time.\n   */\n  function calculateScore(entry: FrecencyEntry, now: number): number {\n    const daysSinceUse = (now - entry.lastUsed) / MS_PER_DAY\n    return entry.count * Math.pow(2, -daysSinceUse / halfLife)\n  }\n\n  /**\n   * Get the frecency score for a command.\n   * Returns 0 if never used.\n   */\n  function getScore(commandId: string): number {\n    const entry = storage.get(commandId)\n    if (!entry) return 0\n    return calculateScore(entry, Date.now())\n  }\n\n  /**\n   * Rank scored search results by blending search score with frecency.\n   *\n   * @param items - Search results with scores\n   * @param frecencyWeight - How much frecency affects ranking (0-1, default 0.3)\n   * @returns Re-ranked items\n   */\n  function rank(items: ScoredItem[], frecencyWeight = 0.3): ScoredItem[] {\n    const now = Date.now()\n\n    // Get max frecency score for normalization\n    let maxFrecency = 0\n    const frecencyScores = new Map<string, number>()\n\n    for (const { item } of items) {\n      const entry = storage.get(item.id)\n      if (entry) {\n        const score = calculateScore(entry, now)\n        frecencyScores.set(item.id, score)\n        maxFrecency = Math.max(maxFrecency, score)\n      }\n    }\n\n    // Blend search score with normalized frecency\n    return items\n      .map(({ item, score }) => {\n        const rawFrecency = frecencyScores.get(item.id) ?? 0\n        const normalizedFrecency = maxFrecency > 0 ? rawFrecency / maxFrecency : 0\n\n        const blendedScore =\n          score * (1 - frecencyWeight) + normalizedFrecency * frecencyWeight\n\n        return { item, score: blendedScore }\n      })\n      .sort((a, b) => b.score - a.score)\n  }\n\n  /**\n   * Get the most recently used command IDs, sorted by last use (newest first).\n   */\n  function getRecent(count = 5): string[] {\n    return storage\n      .getAll()\n      .filter((e) => e.count > 0)\n      .sort((a, b) => b.lastUsed - a.lastUsed)\n      .slice(0, count)\n      .map((e) => e.id)\n  }\n\n  /**\n   * Clean up entries older than maxAge.\n   */\n  function cleanup(): void {\n    const now = Date.now()\n    const cutoff = now - maxAge * MS_PER_DAY\n\n    for (const entry of storage.getAll()) {\n      if (entry.lastUsed < cutoff) {\n        storage.set(entry.id, { ...entry, count: 0, halfLifeScore: 0 })\n      }\n    }\n  }\n\n  /**\n   * Clear all frecency data.\n   */\n  function clear(): void {\n    storage.clear()\n  }\n\n  return {\n    recordUsage,\n    getScore,\n    getRecent,\n    rank,\n    cleanup,\n    clear,\n  }\n}\n\n/**\n * In-memory frecency storage (for testing or SSR).\n */\nexport function createInMemoryStorage(): FrecencyStorage {\n  const store = new Map<string, FrecencyEntry>()\n\n  return {\n    get(key: string): FrecencyEntry | null {\n      return store.get(key) ?? null\n    },\n    set(key: string, entry: FrecencyEntry): void {\n      store.set(key, entry)\n    },\n    getAll(): FrecencyEntry[] {\n      return Array.from(store.values())\n    },\n    clear(): void {\n      store.clear()\n    },\n  }\n}\n","import type { FrecencyEntry, FrecencyStorage } from './types'\n\n/**\n * Create a localStorage-backed frecency storage.\n * Falls back gracefully in SSR or when localStorage is unavailable.\n *\n * @param storageKey - localStorage key prefix (default: 'cmdk-frecency')\n */\nexport function createLocalStorageFrecencyStorage(\n  storageKey = 'cmdk-frecency',\n): FrecencyStorage {\n  function isAvailable(): boolean {\n    try {\n      return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined'\n    } catch {\n      return false\n    }\n  }\n\n  function readAll(): Record<string, FrecencyEntry> {\n    if (!isAvailable()) return {}\n    try {\n      const raw = localStorage.getItem(storageKey)\n      return raw ? JSON.parse(raw) : {}\n    } catch {\n      return {}\n    }\n  }\n\n  function writeAll(data: Record<string, FrecencyEntry>): void {\n    if (!isAvailable()) return\n    try {\n      localStorage.setItem(storageKey, JSON.stringify(data))\n    } catch {\n      // localStorage full or unavailable — silently fail\n    }\n  }\n\n  return {\n    get(key: string): FrecencyEntry | null {\n      const data = readAll()\n      return data[key] ?? null\n    },\n\n    set(key: string, entry: FrecencyEntry): void {\n      const data = readAll()\n      data[key] = entry\n      writeAll(data)\n    },\n\n    getAll(): FrecencyEntry[] {\n      return Object.values(readAll())\n    },\n\n    clear(): void {\n      if (!isAvailable()) return\n      try {\n        localStorage.removeItem(storageKey)\n      } catch {\n        // silently fail\n      }\n    },\n  }\n}\n","import type { CommandGroup, CommandItem, ScoredItem } from './types'\n\n/**\n * Create a group manager that tracks command groups and their ordering.\n */\nexport function createGroupManager(initialGroups: CommandGroup[] = []) {\n  const groups = new Map<string, CommandGroup>()\n\n  for (const group of initialGroups) {\n    groups.set(group.id, group)\n  }\n\n  return {\n    /** Add or update a group definition */\n    addGroup(group: CommandGroup): void {\n      groups.set(group.id, group)\n    },\n\n    /** Remove a group */\n    removeGroup(id: string): void {\n      groups.delete(id)\n    },\n\n    /** Get a group by ID */\n    getGroup(id: string): CommandGroup | undefined {\n      return groups.get(id)\n    },\n\n    /** Get all defined groups sorted by priority (higher first) */\n    getAllGroups(): CommandGroup[] {\n      return Array.from(groups.values()).sort(\n        (a, b) => (b.priority ?? 0) - (a.priority ?? 0),\n      )\n    },\n\n    /**\n     * Group scored items by their group field.\n     * When query is empty: groups ordered by priority (higher first).\n     * When query is non-empty: groups ordered by best item score (relevance).\n     * Items without a group go into an \"Other\" bucket at the end.\n     */\n    groupResults(items: ScoredItem[], query?: string): GroupedResults {\n      const grouped = new Map<string, ScoredItem[]>()\n\n      for (const scored of items) {\n        const groupId = scored.item.group ?? '__ungrouped__'\n        if (!grouped.has(groupId)) {\n          grouped.set(groupId, [])\n        }\n        grouped.get(groupId)!.push(scored)\n      }\n\n      // Sort items within each group by score descending\n      for (const items of grouped.values()) {\n        items.sort((a, b) => b.score - a.score)\n      }\n\n      const isSearching = query !== undefined && query.trim() !== ''\n\n      // Collect all group entries\n      const allEntries: GroupedResult[] = []\n      const definedGroups = this.getAllGroups()\n      const usedGroupIds = new Set<string>()\n\n      for (const group of definedGroups) {\n        const groupItems = grouped.get(group.id)\n        if (groupItems && groupItems.length > 0) {\n          allEntries.push({ group, items: groupItems })\n          usedGroupIds.add(group.id)\n        }\n      }\n\n      // Add any groups that weren't pre-defined (auto-discovered from items)\n      for (const [groupId, groupItems] of grouped) {\n        if (groupId === '__ungrouped__' || usedGroupIds.has(groupId)) continue\n        allEntries.push({\n          group: { id: groupId, label: groupId },\n          items: groupItems,\n        })\n      }\n\n      // When searching, sort groups by best item score (relevance-first)\n      if (isSearching) {\n        allEntries.sort((a, b) => b.items[0].score - a.items[0].score)\n      }\n\n      // Add ungrouped items last\n      const ungrouped = grouped.get('__ungrouped__')\n      if (ungrouped && ungrouped.length > 0) {\n        allEntries.push({\n          group: { id: '__ungrouped__', label: 'Other' },\n          items: ungrouped,\n        })\n      }\n\n      return allEntries\n    },\n\n    /**\n     * Extract unique groups from a list of commands.\n     * Returns only groups that have at least one command.\n     */\n    extractGroups(commands: CommandItem[]): CommandGroup[] {\n      const seen = new Set<string>()\n      const result: CommandGroup[] = []\n\n      for (const cmd of commands) {\n        if (cmd.group && !seen.has(cmd.group)) {\n          seen.add(cmd.group)\n          const defined = groups.get(cmd.group)\n          result.push(defined ?? { id: cmd.group, label: cmd.group })\n        }\n      }\n\n      return result.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0))\n    },\n  }\n}\n\n/** A group with its scored items */\nexport interface GroupedResult {\n  group: CommandGroup\n  items: ScoredItem[]\n}\n\n/** Array of grouped results */\nexport type GroupedResults = GroupedResult[]\n","import type { CommandContext, ScoredItem } from './types'\n\n/**\n * Create a context engine that boosts commands matching the current app context.\n *\n * Commands with a `scope` field (e.g., ['/billing', '/billing/*']) get a score\n * boost when the current context path matches.\n *\n * @param boostWeight - How much to boost in-scope commands (0-1, default: 0.2)\n */\nexport function createContextEngine(boostWeight = 0.2) {\n  return {\n    /**\n     * Boost scores for items whose scope matches the current context.\n     * Items without a scope are unaffected.\n     */\n    boost(items: ScoredItem[], context: CommandContext): ScoredItem[] {\n      if (!context.path && (!context.tags || context.tags.length === 0)) {\n        return items\n      }\n\n      return items.map(({ item, score }) => {\n        if (!item.scope || item.scope.length === 0) {\n          return { item, score }\n        }\n\n        const matches = matchesContext(item.scope, context)\n        const boostedScore = matches\n          ? Math.min(score + boostWeight, 1)\n          : score\n\n        return { item, score: boostedScore }\n      })\n    },\n  }\n}\n\n/**\n * Check if any scope pattern matches the given context.\n */\nfunction matchesContext(scope: string[], context: CommandContext): boolean {\n  if (context.path) {\n    for (const pattern of scope) {\n      if (matchPath(pattern, context.path)) return true\n    }\n  }\n\n  if (context.tags && context.tags.length > 0) {\n    for (const pattern of scope) {\n      if (context.tags.includes(pattern)) return true\n    }\n  }\n\n  return false\n}\n\n/**\n * Match a scope pattern against a path.\n * Supports:\n * - Exact match: '/billing' matches '/billing'\n * - Prefix match: '/billing' matches '/billing/overview'\n * - Glob: '/billing/*' matches '/billing/overview' but not '/billing'\n */\nfunction matchPath(pattern: string, path: string): boolean {\n  // Glob pattern\n  if (pattern.endsWith('/*')) {\n    const prefix = pattern.slice(0, -2)\n    return path.startsWith(prefix + '/') && path !== prefix\n  }\n\n  // Exact or prefix match\n  return path === pattern || path.startsWith(pattern + '/')\n}\n","import type { TranslationFn } from './types'\n\n/** Default English UI strings */\nconst DEFAULT_STRINGS: Record<string, string> = {\n  'palette.placeholder': 'Type a command or search...',\n  'palette.empty': 'No results found.',\n  'palette.loading': 'Loading...',\n  'group.recent': 'Recent',\n  'group.other': 'Other',\n  'search.history': 'Recent Searches',\n}\n\n/**\n * Create the default English translation function.\n * Returns the English string for known keys, or the key itself as fallback.\n */\nexport function createDefaultTranslation(): TranslationFn {\n  return (key: string) => DEFAULT_STRINGS[key] ?? key\n}\n\n/**\n * Get the list of all known translation keys.\n * Useful for consumers building custom translation dictionaries.\n */\nexport function getTranslationKeys(): string[] {\n  return Object.keys(DEFAULT_STRINGS)\n}\n","import type { SearchHistoryConfig, SearchHistoryEntry } from './types'\n\nconst DEFAULT_MAX_ENTRIES = 20\nconst DEFAULT_STORAGE_KEY = 'cmdk-search-history'\nconst DEFAULT_MIN_QUERY_LENGTH = 2\n\n/**\n * Create a search history tracker that records search queries.\n * Separate from frecency (which tracks command usage).\n *\n * Uses localStorage for persistence (same pattern as frecency-storage.ts).\n */\nexport function createSearchHistory(config: SearchHistoryConfig = {}) {\n  const maxEntries = config.maxEntries ?? DEFAULT_MAX_ENTRIES\n  const storageKey = config.storageKey ?? DEFAULT_STORAGE_KEY\n  const minQueryLength = config.minQueryLength ?? DEFAULT_MIN_QUERY_LENGTH\n\n  function load(): SearchHistoryEntry[] {\n    try {\n      const raw = localStorage.getItem(storageKey)\n      return raw ? JSON.parse(raw) : []\n    } catch {\n      return []\n    }\n  }\n\n  function save(entries: SearchHistoryEntry[]): void {\n    try {\n      localStorage.setItem(storageKey, JSON.stringify(entries))\n    } catch {\n      // Silently fail (quota exceeded, SSR, etc.)\n    }\n  }\n\n  return {\n    /** Record a search query. Deduplicates by query string (updates timestamp). */\n    record(query: string, resultCount: number): void {\n      const trimmed = query.trim()\n      if (trimmed.length < minQueryLength) return\n\n      const entries = load()\n      // Remove existing entry for this query (will re-add at front)\n      const filtered = entries.filter((e) => e.query !== trimmed)\n      filtered.unshift({ query: trimmed, timestamp: Date.now(), resultCount })\n\n      // Trim to max entries\n      save(filtered.slice(0, maxEntries))\n    },\n\n    /** Get recent search queries, sorted by timestamp descending. */\n    getRecent(count?: number): SearchHistoryEntry[] {\n      const entries = load()\n      return count ? entries.slice(0, count) : entries\n    },\n\n    /** Remove a specific search query from history. */\n    remove(query: string): void {\n      const entries = load()\n      save(entries.filter((e) => e.query !== query))\n    },\n\n    /** Clear all search history. */\n    clear(): void {\n      try {\n        localStorage.removeItem(storageKey)\n      } catch {\n        // Silently fail\n      }\n    },\n  }\n}\n\n/**\n * In-memory search history (for testing or SSR).\n */\nexport function createInMemorySearchHistory(config: SearchHistoryConfig = {}) {\n  const maxEntries = config.maxEntries ?? DEFAULT_MAX_ENTRIES\n  const minQueryLength = config.minQueryLength ?? DEFAULT_MIN_QUERY_LENGTH\n  let entries: SearchHistoryEntry[] = []\n\n  return {\n    record(query: string, resultCount: number): void {\n      const trimmed = query.trim()\n      if (trimmed.length < minQueryLength) return\n      entries = entries.filter((e) => e.query !== trimmed)\n      entries.unshift({ query: trimmed, timestamp: Date.now(), resultCount })\n      entries = entries.slice(0, maxEntries)\n    },\n\n    getRecent(count?: number): SearchHistoryEntry[] {\n      return count ? entries.slice(0, count) : [...entries]\n    },\n\n    remove(query: string): void {\n      entries = entries.filter((e) => e.query !== query)\n    },\n\n    clear(): void {\n      entries = []\n    },\n  }\n}\n"]}