{"version":3,"file":"plugin-BYw2PRe-.mjs","names":[],"sources":["../src/plugin/merge.ts","../src/plugin/index.ts"],"sourcesContent":["// Plugin → unified registry merge.\n//\n// Resolution rules (per the v1 spec + dogfood pivot):\n//   - duplicate plugin `name` across the input array → conflict error.\n//     Catches the double-install case (built-in shipped twice, or\n//     adopter requiring the same plugin twice).\n//   - plugin commands appear first in the merged list, then adopter\n//     commands; adopter `commands` of the same name override the\n//     plugin entry (filter pass).\n//   - duplicate command name across two plugins → conflict error\n//     listing both plugin names. Adopter overriding a plugin is\n//     allowed and not an error.\n//   - duplicate typegen id across two plugins → same error. Typegens\n//     have no adopter override path; only plugins contribute them.\n//   - register() functions are collected in input order; the caller\n//     invokes each one against the same Command program. They have no\n//     id-level conflict surface — owners are responsible for picking\n//     non-colliding command names inside their own register().\n//   - plugin order = array order. No implicit precedence rules.\n\nimport type { Command } from 'commander'\n\nimport type { KickCommandDefinition } from '../config'\nimport type { TypegenPlugin } from '../typegen/plugin'\nimport type { GeneratorSpec } from '../generator-extension/define'\nimport type { DiscoveredGenerator } from '../generator-extension/discover'\nimport { KickPluginConflictError, type KickCliPlugin, type KickCliPluginContext } from './types'\n\nexport interface MergedPlugins {\n  commands: KickCommandDefinition[]\n  typegens: TypegenPlugin[]\n  /** DiscoveredGenerator shape so this list slots into the existing\n   * dispatch path next to package.json-discovered entries. `source`\n   * carries the plugin name for error attribution. */\n  generators: DiscoveredGenerator[]\n  /**\n   * Apply every plugin's register() in input order. ctx is optional so\n   * tests + lightweight callers can invoke `register(program)` without\n   * constructing a full context; it falls back to cwd=process.cwd(),\n   * config=null, log=no-op.\n   */\n  register: (program: Command, ctx?: KickCliPluginContext) => Promise<void>\n}\n\nexport function mergeCliPlugins(\n  plugins: readonly KickCliPlugin[],\n  adopterCommands: readonly KickCommandDefinition[] = [],\n): MergedPlugins {\n  // Plugin-name dedup — catches double-install.\n  const seenPluginNames = new Map<string, number>()\n  for (const p of plugins) {\n    const count = (seenPluginNames.get(p.name) ?? 0) + 1\n    seenPluginNames.set(p.name, count)\n    if (count === 2) {\n      throw new KickPluginConflictError('plugin', p.name, [p.name, p.name])\n    }\n  }\n\n  const commandOwners = new Map<string, string>()\n  const pluginCommands: KickCommandDefinition[] = []\n  for (const p of plugins) {\n    for (const cmd of p.commands ?? []) {\n      const prior = commandOwners.get(cmd.name)\n      if (prior) {\n        throw new KickPluginConflictError('command', cmd.name, [prior, p.name])\n      }\n      commandOwners.set(cmd.name, p.name)\n      pluginCommands.push(cmd)\n    }\n  }\n\n  const adopterNames = new Set(adopterCommands.map((c) => c.name))\n  const filteredPlugin = pluginCommands.filter((c) => !adopterNames.has(c.name))\n  const commands = [...filteredPlugin, ...adopterCommands]\n\n  const typegenOwners = new Map<string, string>()\n  const typegens: TypegenPlugin[] = []\n  for (const p of plugins) {\n    for (const tg of p.typegens ?? []) {\n      const prior = typegenOwners.get(tg.id)\n      if (prior) {\n        throw new KickPluginConflictError('typegen', tg.id, [prior, p.name])\n      }\n      typegenOwners.set(tg.id, p.name)\n      typegens.push(tg)\n    }\n  }\n\n  const generatorOwners = new Map<string, string>()\n  const generators: DiscoveredGenerator[] = []\n  for (const p of plugins) {\n    for (const spec of p.generators ?? []) {\n      const prior = generatorOwners.get(spec.name)\n      if (prior) {\n        throw new KickPluginConflictError('generator', spec.name, [prior, p.name])\n      }\n      generatorOwners.set(spec.name, p.name)\n      generators.push({ source: p.name, spec: spec satisfies GeneratorSpec })\n    }\n  }\n\n  /**\n   * Apply every plugin's `register()` callback in input order against the\n   * given Commander program. Each callback receives a {@link KickCliPluginContext}:\n   * caller-supplied ctx wins (test fixtures can inject a different\n   * workspace boundary); otherwise a default ctx is built with\n   * `findProjectRoot(process.cwd())` as the project root, `cwd` matching\n   * `process.cwd()`, null config, no-op log, and the merged generator set\n   * threaded through so the `kick/generate` built-in can surface each as\n   * a Commander subcommand. The dynamic import of `findProjectRoot` keeps\n   * the caller-supplied fast path zero-cost.\n   */\n  const register = async (program: Command, ctx?: KickCliPluginContext): Promise<void> => {\n    let resolved: KickCliPluginContext\n    if (ctx) {\n      resolved = { generators, ...ctx }\n    } else {\n      const { findProjectRoot } = await import('../utils/project-root')\n      const cwd = process.cwd()\n      resolved = {\n        cwd,\n        projectRoot: findProjectRoot(cwd),\n        config: null,\n        log: () => {},\n        generators,\n      }\n    }\n    for (const p of plugins) {\n      if (p.register) await p.register(program, resolved)\n    }\n  }\n\n  return { commands, typegens, generators, register }\n}\n","// Barrel intentionally omits `./builtins` — that module top-level-imports\n// every register*Command, which pulls heavy modules (project scaffolders,\n// fs reads at import time) into the graph. Importers that need the\n// builtin list go through `./plugin/builtins` directly; tests + adopter\n// plugins consuming only the contract types import from here.\n\nexport type { KickCliPlugin } from './types'\nexport { defineCliPlugin, KickPluginConflictError } from './types'\nexport { mergeCliPlugins, type MergedPlugins } from './merge'\n"],"mappings":";;;;;;;;;;wFA4CA,SAAgB,EACd,EACA,EAAoD,CAAC,EACtC,CAEf,IAAM,EAAkB,IAAI,IAC5B,IAAK,IAAM,KAAK,EAAS,CACvB,IAAM,GAAS,EAAgB,IAAI,EAAE,IAAI,GAAK,GAAK,EAEnD,GADA,EAAgB,IAAI,EAAE,KAAM,CAAK,EAC7B,IAAU,EACZ,MAAM,IAAI,EAAwB,SAAU,EAAE,KAAM,CAAC,EAAE,KAAM,EAAE,IAAI,CAAC,CAExE,CAEA,IAAM,EAAgB,IAAI,IACpB,EAA0C,CAAC,EACjD,IAAK,IAAM,KAAK,EACd,IAAK,IAAM,KAAO,EAAE,UAAY,CAAC,EAAG,CAClC,IAAM,EAAQ,EAAc,IAAI,EAAI,IAAI,EACxC,GAAI,EACF,MAAM,IAAI,EAAwB,UAAW,EAAI,KAAM,CAAC,EAAO,EAAE,IAAI,CAAC,EAExE,EAAc,IAAI,EAAI,KAAM,EAAE,IAAI,EAClC,EAAe,KAAK,CAAG,CACzB,CAGF,IAAM,EAAe,IAAI,IAAI,EAAgB,IAAK,GAAM,EAAE,IAAI,CAAC,EAEzD,EAAW,CAAC,GADK,EAAe,OAAQ,GAAM,CAAC,EAAa,IAAI,EAAE,IAAI,CAC1C,EAAG,GAAG,CAAe,EAEjD,EAAgB,IAAI,IACpB,EAA4B,CAAC,EACnC,IAAK,IAAM,KAAK,EACd,IAAK,IAAM,KAAM,EAAE,UAAY,CAAC,EAAG,CACjC,IAAM,EAAQ,EAAc,IAAI,EAAG,EAAE,EACrC,GAAI,EACF,MAAM,IAAI,EAAwB,UAAW,EAAG,GAAI,CAAC,EAAO,EAAE,IAAI,CAAC,EAErE,EAAc,IAAI,EAAG,GAAI,EAAE,IAAI,EAC/B,EAAS,KAAK,CAAE,CAClB,CAGF,IAAM,EAAkB,IAAI,IACtB,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAK,EACd,IAAK,IAAM,KAAQ,EAAE,YAAc,CAAC,EAAG,CACrC,IAAM,EAAQ,EAAgB,IAAI,EAAK,IAAI,EAC3C,GAAI,EACF,MAAM,IAAI,EAAwB,YAAa,EAAK,KAAM,CAAC,EAAO,EAAE,IAAI,CAAC,EAE3E,EAAgB,IAAI,EAAK,KAAM,EAAE,IAAI,EACrC,EAAW,KAAK,CAAE,OAAQ,EAAE,KAAY,MAA6B,CAAC,CACxE,CAkCF,MAAO,CAAE,WAAU,WAAU,aAAY,eApBjB,EAAkB,IAA8C,CACtF,IAAI,EACJ,GAAI,EACF,EAAW,CAAE,aAAY,GAAG,CAAI,MAC3B,CACL,GAAM,CAAE,mBAAoB,MAAM,OAAO,8BAAwB,CAAA,KAAA,GAAA,EAAA,CAAA,EAC3D,EAAM,QAAQ,IAAI,EACxB,EAAW,CACT,MACA,YAAa,EAAgB,CAAG,EAChC,OAAQ,KACR,QAAW,CAAC,EACZ,YACF,CACF,CACA,IAAK,IAAM,KAAK,EACV,EAAE,UAAU,MAAM,EAAE,SAAS,EAAS,CAAQ,CAEtD,CAEkD,CACpD"}