{"version":3,"file":"services-BHKno3F_.cjs","sources":["../src/services/MergeService.ts","../src/services/BuildToolsService.ts","../src/services/FileService.ts","../src/services/FileBrowserService.ts","../src/services/UIService.ts","../src/services/ConfigService.ts","../src/services/ProjectOptionsService.ts"],"sourcesContent":["import type { ConfigFileInfo } from './ConfigService.ts'\nimport { FileMerger } from '../core/FileMerger.ts'\n\n/**\n * 配置合并服务类\n * 负责智能合并不同类型的配置文件内容，提供业务相关的合并策略\n */\nexport class MergeService {\n  private configMerger: FileMerger\n\n  constructor() {\n    this.configMerger = new FileMerger()\n  }\n\n  /**\n   * 确定配置文件的更新模式\n   */\n  async determineUpdateMode(\n    targetContent: string,\n    templateContent: string,\n    config: ConfigFileInfo\n  ): Promise<'merge' | 'overwrite' | 'skip'> {\n    // 如果内容完全相同，跳过\n    if (targetContent.trim() === templateContent.trim()) {\n      return 'skip'\n    }\n    const needOverride = ['.gitconfig', '.editorconfig']\n    // 如果targetContent为空，应该覆盖\n    if (\n      config.group === 'git-hooks' ||\n      needOverride.includes(config.name) ||\n      !targetContent.trim()\n    ) {\n      return 'overwrite'\n    }\n\n    // 默认使用合并模式\n    return 'merge'\n  }\n\n  /**\n   * 智能合并配置文件内容\n   */\n  async mergeConfigContent(\n    targetContent: string,\n    templateContent: string,\n    config: Required<Pick<ConfigFileInfo, 'name'>> & Partial<Omit<ConfigFileInfo, 'name'>>\n  ): Promise<string> {\n    // 使用通用合并算法\n    return this.configMerger.mergeConfigContent(targetContent, templateContent, config)\n  }\n}\n","import { join, relative } from 'path'\nimport type { ArchitectureType, ProjectType } from '../types.ts'\nimport { FileOperations } from '../core/FileOperations.ts'\nimport { MergeService } from './MergeService.ts'\n\n/**\n * 构建工具服务类\n * 用于处理 vite 配置文件和 typescript 配置文件\n */\nexport class BuildToolsService {\n  private mergeService: MergeService\n  // 用于跟踪已更新的 monorepo 根目录配置文件，避免重复更新\n  private updatedMonorepoConfigs: Set<string>\n\n  constructor() {\n    this.mergeService = new MergeService()\n    this.updatedMonorepoConfigs = new Set<string>()\n  }\n\n  /**\n   * 判断 typescript 配置文件是否拆分基文件和特异文件\n   */\n  private isTsConfigSeparated(content: string): boolean {\n    try {\n      const tsConfig = JSON.parse(content)\n\n      // 处理 extends 可能为字符串、数组或其他类型的情况\n      const checkExtends = (extendsValue: unknown): boolean => {\n        // 更宽松的正则表达式来匹配 extends 值，去除引号\n        const reg = /^(?:\\.\\.\\/|\\.\\/|[\\w-]+\\/)*tsconfig\\.json$/\n        // extends 是单个字符串\n        if (typeof extendsValue === 'string') {\n          // 去除引号后测试\n          const cleanValue = extendsValue.replace(/^[\"']|[\"']$/g, '')\n          return reg.test(cleanValue)\n        }\n        // extends 是字符串数组\n        if (Array.isArray(extendsValue)) {\n          return extendsValue.some(item => {\n            if (typeof item === 'string') {\n              const cleanValue = item.replace(/^[\"']|[\"']$/g, '')\n              return reg.test(cleanValue)\n            }\n            return false\n          })\n        }\n        // 情况3：extends 是其他类型（不符合规范，返回false）\n        return false\n      }\n\n      return checkExtends(tsConfig.extends ?? '')\n    } catch {\n      // 如果解析失败，认为没有拆分\n      return false\n    }\n  }\n\n  /**\n   * 判断 vite 配置文件是否拆分基文件和特异文件\n   */\n  private isViteConfigSeparated(content: string): boolean {\n    // 检查是否通过 import 导入了其他 vite 配置文件\n    // 使用更宽松的正则表达式来匹配 import 语句\n    const reg = /import\\s+.*\\s+from\\s+[\"'][.\\/]+.*vite\\.config\\.(?:ts|js)[\"']/\n    return reg.test(content)\n  }\n\n  /**\n   * 检查配置文件状态\n   */\n  private async checkConfigStatus(\n    projectPath: string,\n    type: 'vite' | 'ts'\n  ): Promise<'not-exists' | 'separated' | 'not-separated'> {\n    const fileName = type === 'vite' ? 'vite.config.ts' : 'tsconfig.json'\n    try {\n      const configPath = join(projectPath, fileName)\n\n      // 检查配置文件是否存在\n      const exists = await FileOperations.exists(configPath)\n      if (!exists) {\n        return 'not-exists'\n      }\n\n      // 读取配置文件内容\n      const content = await FileOperations.readFile(configPath)\n\n      // 检查是否拆分基文件和特异文件\n      let isSeparated: boolean\n      if (type === 'vite') {\n        isSeparated = this.isViteConfigSeparated(content)\n      } else {\n        isSeparated = this.isTsConfigSeparated(content)\n      }\n\n      return isSeparated ? 'separated' : 'not-separated'\n    } catch {\n      // 如果出现错误，默认认为配置文件不存在\n      return 'not-exists'\n    }\n  }\n\n  /**\n   * 处理配置文件\n   */\n  async process(\n    configType: 'vite' | 'ts',\n    templatesDir: string,\n    projectPath: string,\n    rootPath: string,\n    architecture: ArchitectureType,\n    projectType: ProjectType\n  ): Promise<void> {\n    // 确定情景类型\n\n    // 识别目标项目 vite 配置文件的情况\n    const status = await this.checkConfigStatus(projectPath, configType)\n\n    switch (status) {\n      case 'not-exists':\n        await this.handleProjectConfigNotExists(\n          templatesDir,\n          projectPath,\n          rootPath,\n          configType,\n          architecture,\n          projectType\n        )\n        break\n      case 'separated':\n        await this.handleProjectConfigSeparated(\n          templatesDir,\n          projectPath,\n          rootPath,\n          configType,\n          architecture,\n          projectType\n        )\n        break\n      case 'not-separated':\n        await this.handleProjectConfigNotSeparated(\n          templatesDir,\n          projectPath,\n          rootPath,\n          configType,\n          architecture,\n          projectType\n        )\n        break\n    }\n  }\n\n  /**\n   * 计算相对路径\n   */\n  private calculateRelativePath(from: string, to: string): string {\n    const relativePath = relative(from, to).replace(/\\\\/g, '/')\n    // 确保路径以 ./ 或 ../ 开头\n    if (!relativePath.startsWith('./') && !relativePath.startsWith('../')) {\n      return `./${relativePath}`\n    }\n    return relativePath\n  }\n\n  /**\n   * 更新基配置文件（避免重复更新）\n   */\n  private async updateBaseConfigFile(targetPath: string, templatePath: string): Promise<void> {\n    const configKey = targetPath\n\n    if (!this.updatedMonorepoConfigs.has(configKey)) {\n      const templateContent = await FileOperations.readFile(templatePath)\n      await FileOperations.writeFile(targetPath, templateContent)\n      this.updatedMonorepoConfigs.add(configKey)\n    }\n  }\n\n  /**\n   * 合并并更新基配置文件（避免重复更新）\n   */\n  private async mergeAndUpdateBaseConfigFile(\n    configsFilePath: string,\n    templatePath: string,\n    configName: string\n  ): Promise<void> {\n    const configKey = configsFilePath\n\n    if (!this.updatedMonorepoConfigs.has(configKey)) {\n      const templateContent = await FileOperations.readFile(templatePath)\n      const existingContent = await FileOperations.readFile(configsFilePath)\n      const mergedContent = await this.mergeConfigContent(\n        existingContent,\n        templateContent,\n        configName\n      )\n      await FileOperations.writeFile(configsFilePath, mergedContent)\n      this.updatedMonorepoConfigs.add(configKey)\n    }\n  }\n\n  /**\n   * 通用方法：处理项目配置文件不存在的情况\n   */\n  private async handleProjectConfigNotExists(\n    templatesDir: string,\n    projectPath: string,\n    rootPath: string,\n    configType: 'vite' | 'ts',\n    architecture: ArchitectureType,\n    projectType: ProjectType\n  ): Promise<void> {\n    // 1. 确保根目录下存在configs文件夹\n    await FileOperations.ensureDir(join(rootPath, 'configs'))\n\n    // 2. 将模板中的基础配置文件复制到 configs 中\n    const fileName = configType === 'vite' ? 'vite.config.ts' : 'tsconfig.json'\n    const baseTemplatePath = join(templatesDir, 'configs', 'build-tools', fileName)\n    const baseTargetPath = join(rootPath, 'configs', fileName)\n    await this.updateBaseConfigFile(baseTargetPath, baseTemplatePath)\n\n    if (architecture === 'monorepo' && projectType === 'root') return\n\n    // 3. 读取应用类型的配置文件\n    const templatePath = join(\n      templatesDir,\n      'configs',\n      'build-tools',\n      projectType === 'lib' ? 'libs' : 'apps',\n      fileName\n    )\n    let templateContent = await FileOperations.readFile(templatePath)\n\n    // 4. 计算相对于项目根目录的 configs 目录路径\n    const relativeConfigsPath = this.calculateRelativePath(projectPath, join(rootPath, 'configs'))\n    // 4. 根据配置类型进行特定处理\n    if (configType === 'vite') {\n      // 在读取到的文件顶部增加 import 语句\n      templateContent = `import getBaseConfig from '${relativeConfigsPath}/vite.config'\\n${templateContent}`\n\n      // 将 return config 替换为 return mergeConfig(getBaseConfig, config)\n      templateContent = templateContent.replace(\n        /return\\s+config/g,\n        'return mergeConfig(getBaseConfig(env), config)'\n      )\n    } else {\n      // 解析 tsconfig.json 内容\n      const tsConfig = JSON.parse(templateContent)\n      // 添加 extends 属性\n      tsConfig.extends = `${relativeConfigsPath}/tsconfig.json`\n      templateContent = JSON.stringify(tsConfig, null, 2)\n    }\n\n    // 5. 使用上述处理后的内容，在项目根目录创建配置文件\n    await FileOperations.writeFile(join(projectPath, fileName), templateContent)\n  }\n\n  /**\n   * 通用方法：处理项目配置文件拆分的情况\n   */\n  private async handleProjectConfigSeparated(\n    templatesDir: string,\n    projectPath: string,\n    rootPath: string,\n    configType: 'vite' | 'ts',\n    architecture: ArchitectureType,\n    projectType: ProjectType\n  ): Promise<void> {\n    // 1. 以模板中的基础配置文件作为模板文件，对配置基文件进行更新\n    const fileName = configType === 'vite' ? 'vite.config.ts' : 'tsconfig.json'\n    const baseTargetPath = join(rootPath, 'configs', fileName)\n\n    const baseTemplatePath = join(templatesDir, 'configs', 'build-tools', fileName)\n\n    if (architecture === 'monorepo') {\n      await this.mergeAndUpdateBaseConfigFile(baseTargetPath, baseTemplatePath, fileName)\n    } else {\n      const baseTemplateContent = await FileOperations.readFile(baseTemplatePath)\n      // 使用 MergeService 更新基文件\n      const baseTargetContent = await FileOperations.readFile(baseTargetPath)\n      const mergedBaseContent = await this.mergeConfigContent(\n        baseTargetContent,\n        baseTemplateContent,\n        fileName\n      )\n      await FileOperations.writeFile(baseTargetPath, mergedBaseContent)\n    }\n    if (architecture === 'monorepo' && projectType === 'root') return\n\n    // 2. 读取应用类型的配置文件\n    const templatePath = join(\n      templatesDir,\n      'configs',\n      'build-tools',\n      projectType === 'lib' ? 'libs' : 'apps',\n      fileName\n    )\n    const templateContent = await FileOperations.readFile(templatePath)\n\n    // 3. 使用上述处理后的内容作为模板，对项目根目录下的配置文件进行更新\n    const targetPath = join(projectPath, fileName)\n    const targetContent = await FileOperations.readFile(targetPath)\n    const mergedProjectContent = await this.mergeConfigContent(\n      targetContent,\n      templateContent,\n      fileName\n    )\n    await FileOperations.writeFile(targetPath, mergedProjectContent)\n  }\n\n  /**\n   * 通用方法：处理项目配置文件未拆分的情况\n   */\n  private async handleProjectConfigNotSeparated(\n    templatesDir: string,\n    projectPath: string,\n    rootPath: string,\n    configType: 'vite' | 'ts',\n    architecture: ArchitectureType,\n    projectType: ProjectType\n  ): Promise<void> {\n    const fileName = configType === 'vite' ? 'vite.config.ts' : 'tsconfig.json'\n    const projectConfigPath = join(projectPath, fileName)\n    const backupConfigPath = `${projectConfigPath}.backup`\n\n    if (await FileOperations.exists(projectConfigPath)) {\n      await FileOperations.rename(projectConfigPath, backupConfigPath)\n      console.log(`原始配置文件已备份为: ${backupConfigPath}`)\n    }\n\n    // 2. 按照配置文件不存在的逻辑处理\n    // 调用 handleProjectConfigNotExists 方法处理\n    await this.handleProjectConfigNotExists(\n      templatesDir,\n      projectPath,\n      rootPath,\n      configType,\n      architecture, // 假设为 monorepo 架构\n      projectType\n    )\n  }\n\n  /**\n   * 智能合并配置文件内容\n   */\n  private async mergeConfigContent(\n    targetContent: string,\n    templateContent: string,\n    configName: string\n  ): Promise<string> {\n    const commentPrefix: string = configName === 'vite.config.ts' ? '// ' : '/*'\n    const commentSuffix: string = configName === 'vite.config.ts' ? ' ' : '*/'\n    // 使用通用合并算法\n    return this.mergeService.mergeConfigContent(targetContent, templateContent, {\n      name: configName,\n      commentPrefix,\n      commentSuffix,\n    })\n  }\n}\n","import { join, dirname } from 'path'\nimport type { ArchitectureType, ProjectType } from '../types.ts'\nimport { FileOperations } from '../core/FileOperations.ts'\nimport { MergeService } from './MergeService.ts'\nimport type { ConfigFileInfo } from './ConfigService.ts'\nimport { BuildToolsService } from './BuildToolsService.ts'\n\n/**\n * 配置文件服务类\n * 负责处理单个配置文件的更新和特殊文件处理\n */\nexport class FileService {\n  private templatesDir: string\n  private mergeService: MergeService\n  private buildToolsService: BuildToolsService\n\n  constructor(templatesDir: string) {\n    this.templatesDir = templatesDir\n    this.mergeService = new MergeService()\n    this.buildToolsService = new BuildToolsService()\n  }\n\n  /**\n   * 更新单个配置文件\n   */\n  async updateConfigFile(\n    config: ConfigFileInfo,\n    projectRoot: string,\n    rootPath: string,\n    architecture: ArchitectureType,\n    projectType: ProjectType\n  ): Promise<boolean> {\n    try {\n      // 特殊处理 vite.config.ts 文件\n      if (config.name.startsWith('vite.config')) {\n        await this.buildToolsService.process(\n          'vite',\n          this.templatesDir,\n          projectRoot,\n          rootPath,\n          architecture,\n          projectType\n        )\n        // Vite配置文件已更新\n        return true\n      }\n\n      // 特殊处理 tsconfig.json 文件\n      if (config.name === 'tsconfig.json') {\n        // 使用BuildToolsConfigService提供的方法处理tsconfig.json\n        await this.buildToolsService.process(\n          'ts',\n          this.templatesDir,\n          projectRoot,\n          rootPath,\n          architecture,\n          projectType\n        )\n        // TypeScript配置文件已更新\n        return true\n      }\n\n      let updateCtx\n      // 特殊处理 .pnpmrc 文件\n      if (config.name === '.pnpmrc' || config.name === '.npmrc') {\n        // 需要做拼接\n        updateCtx = await this.getAutoUpdateModeOfNpmrc(config, architecture)\n      } else {\n        // 自动选择更新策略\n        updateCtx = await this.getAutoUpdateMode(config)\n      }\n\n      if (updateCtx.updateMode === 'skip') {\n        // 文件内容相同，静默跳过\n        return false\n      }\n\n      // 更新文件内容\n      let finalContent: string\n      if (updateCtx.updateMode === 'overwrite') {\n        // 完全覆盖模式\n        finalContent = updateCtx.templateContent\n      } else {\n        // 智能合并模式\n        finalContent = await this.mergeService.mergeConfigContent(\n          updateCtx.targetContent,\n          updateCtx.templateContent,\n          config\n        )\n      }\n\n      // Git hooks 需要可执行权限\n      await FileOperations.writeFile(\n        config.path,\n        finalContent,\n        config.group === 'git-hooks' ? { mode: 0o755 } : 'utf8'\n      )\n      return true\n    } catch (error: any) {\n      // 统一错误处理格式，不直接输出到控制台\n      // 错误将在上层处理中统一显示\n      throw new Error(`更新配置文件失败 ${config.name}: ${error.message}`)\n    }\n  }\n\n  /**\n   * 自动选择更新模式\n   */\n  private async getAutoUpdateMode(config: ConfigFileInfo): Promise<{\n    updateMode: 'merge' | 'overwrite' | 'skip'\n    targetContent: string\n    templateContent: string\n  }> {\n    const { templatePath, path: targetPath } = config\n    // 读取模板文件内容\n    const templateContent = await FileOperations.readFile(templatePath)\n    // 检查目标文件是否存在\n    const targetExists = await FileOperations.exists(targetPath)\n    let targetContent = ''\n\n    if (targetExists) {\n      targetContent = await FileOperations.readFile(targetPath)\n    } else {\n      // 确保目标目录存在\n      await FileOperations.ensureDir(dirname(targetPath))\n    }\n\n    // 使用ConfigMergeService来判断更新模式\n    const updateMode = await this.mergeService.determineUpdateMode(\n      targetContent,\n      templateContent,\n      config\n    )\n\n    return {\n      updateMode,\n      targetContent,\n      templateContent,\n    }\n  }\n\n  /**\n   * 更新 .pnpmrc 文件或 .npmrc 文件\n   */\n  private async getAutoUpdateModeOfNpmrc(\n    config: ConfigFileInfo,\n    architecture: ArchitectureType\n  ): Promise<{\n    updateMode: 'merge' | 'overwrite' | 'skip'\n    targetContent: string\n    templateContent: string\n  }> {\n    //   1、基础模版路径 config.templatePath\n    const baseTemplatePath = config.templatePath\n    //   2、架构特异性模板路径\n    const architectureTemplatePath = join(\n      this.templatesDir,\n      'configs',\n      'npm',\n      architecture,\n      config.name.replace(/^\\./, '')\n    )\n\n    //   3、读取模版文件内容\n    const baseTemplateContent = await FileOperations.readFile(baseTemplatePath)\n    const architectureTemplateContent = await FileOperations.readFile(architectureTemplatePath)\n    //   4、拼接两个模板内容，生成新的模版内容\n    const templateContent = await this.mergeService.mergeConfigContent(\n      architectureTemplateContent,\n      baseTemplateContent,\n      config\n    )\n    //   5、读取目标文件内容\n    const targetExists = await FileOperations.exists(config.path)\n    let targetContent = ''\n\n    if (targetExists) {\n      targetContent = await FileOperations.readFile(config.path)\n    } else {\n      // 确保目标目录存在\n      await FileOperations.ensureDir(dirname(config.path))\n    }\n\n    //   6、使用新的模板内容与目标文件内容进行对比，分析更新模式\n    const updateMode = await this.mergeService.determineUpdateMode(\n      targetContent,\n      templateContent,\n      config\n    )\n\n    //   7、根据更新模式进行更新\n    return {\n      updateMode,\n      targetContent,\n      templateContent,\n    }\n  }\n}\n","import { readdir } from 'fs/promises'\nimport { join, dirname, basename } from 'path'\nimport prompts from 'prompts'\nimport chalk from 'chalk'\n\n/**\n * 文件浏览器服务\n * 专门负责文件系统浏览和选择功能\n */\nexport class FileBrowserService {\n  /**\n   * 浏览文件系统选择 package.json 文件\n   * @param startDir 起始目录\n   * @returns 选择的文件路径，如果未选择则返回 null\n   */\n  async browseForPackageJson(startDir: string): Promise<string | null> {\n    let currentDir = startDir\n    let selectedFile: string | null = null\n\n    while (true) {\n      const { action, file } = await this.browseDirectory(currentDir, startDir)\n\n      if (action === 'cancel') {\n        console.log(chalk.yellow('⚠️ 操作已取消'))\n        return null\n      }\n\n      if (action === 'select' && file) {\n        selectedFile = file\n        break\n      }\n\n      if (action === 'navigate' && file) {\n        currentDir = file\n      }\n\n      if (action === 'back') {\n        const parentDir = dirname(currentDir)\n        if (parentDir !== currentDir) {\n          currentDir = parentDir\n        }\n      }\n    }\n\n    if (selectedFile) {\n      console.log(chalk.green(`✓ 已选择: ${basename(selectedFile)}`))\n    }\n\n    return selectedFile\n  }\n\n  /**\n   * 浏览目录\n   */\n  private async browseDirectory(\n    currentDir: string,\n    startDir: string\n  ): Promise<{ action: 'select' | 'navigate' | 'back' | 'cancel'; file?: string }> {\n    try {\n      const entries = await readdir(currentDir, { withFileTypes: true })\n      const relativePath = this.getRelativePath(currentDir, startDir)\n\n      console.log(chalk.blue(`\\n📁 当前目录: ${relativePath}`))\n\n      const choices = await this.buildChoices(entries, currentDir)\n\n      if (choices.length === 1) {\n        console.log(chalk.yellow('⚠️ 当前目录中没有找到 package.json 文件'))\n        return { action: 'cancel' }\n      }\n\n      const { selection } = await prompts({\n        type: 'select',\n        name: 'selection',\n        message: '请选择操作:',\n        choices,\n        instructions: false,\n      })\n\n      return selection ?? { action: 'cancel' }\n    } catch (error: unknown) {\n      const errorMessage = error instanceof Error ? error.message : '未知错误'\n      console.log(chalk.red(`❌ 无法访问目录: ${errorMessage}`))\n      return { action: 'cancel' }\n    }\n  }\n\n  /**\n   * 构建选择列表\n   */\n  private async buildChoices(\n    entries: Array<{ name: string; isFile(): boolean; isDirectory(): boolean }>,\n    currentDir: string\n  ): Promise<\n    Array<{\n      title: string\n      value: { action: string; file?: string }\n      description?: string\n    }>\n  > {\n    const choices: Array<{\n      title: string\n      value: { action: string; file?: string }\n      description?: string\n    }> = []\n\n    // 返回上级目录选项\n    if (dirname(currentDir) !== currentDir) {\n      choices.push({\n        title: '📁 .. (返回上级目录)',\n        value: { action: 'back' },\n        description: '返回上级目录',\n      })\n    }\n\n    // 检查当前目录是否有 package.json 文件\n    const hasPackageJson = entries.some(entry => entry.isFile() && entry.name === 'package.json')\n\n    if (hasPackageJson) {\n      choices.push({\n        title: '📄 package.json',\n        value: { action: 'select', file: join(currentDir, 'package.json') },\n        description: '选择此文件',\n      })\n    }\n\n    // 只显示包含 package.json 的目录\n    await this.addDirectoriesWithPackageJson(choices, entries, currentDir)\n\n    // 取消选项\n    choices.push({\n      title: '❌ 取消',\n      value: { action: 'cancel' },\n      description: '取消选择',\n    })\n\n    return choices\n  }\n\n  /**\n   * 添加包含 package.json 的目录\n   */\n  private async addDirectoriesWithPackageJson(\n    choices: Array<{\n      title: string\n      value: { action: string; file?: string }\n      description?: string\n    }>,\n    entries: Array<{ name: string; isDirectory(): boolean }>,\n    currentDir: string\n  ): Promise<void> {\n    const directoriesWithPackageJson = await this.getDirectoriesWithPackageJson(entries, currentDir)\n\n    directoriesWithPackageJson.forEach(dir => {\n      choices.push({\n        title: `📁 ${dir.name}/`,\n        value: { action: 'navigate', file: join(currentDir, dir.name) },\n        description: '进入目录',\n      })\n    })\n  }\n\n  /**\n   * 获取包含 package.json 的目录列表\n   */\n  private async getDirectoriesWithPackageJson(\n    entries: Array<{ name: string; isDirectory(): boolean }>,\n    currentDir: string\n  ): Promise<Array<{ name: string }>> {\n    const directoriesWithPackageJson: Array<{ name: string }> = []\n\n    for (const entry of entries) {\n      if (entry.isDirectory() && !entry.name.startsWith('.')) {\n        try {\n          const subEntries = await readdir(join(currentDir, entry.name), { withFileTypes: true })\n          const hasPackageJson = subEntries.some(\n            subEntry => subEntry.isFile() && subEntry.name === 'package.json'\n          )\n\n          if (hasPackageJson) {\n            directoriesWithPackageJson.push({ name: entry.name })\n          }\n        } catch {\n          // 忽略无法访问的目录\n        }\n      }\n    }\n\n    return directoriesWithPackageJson.sort((a, b) => a.name.localeCompare(b.name))\n  }\n\n  /**\n   * 获取相对路径\n   */\n  private getRelativePath(currentDir: string, startDir: string): string {\n    return currentDir.replace(startDir, '').replace(/^[\\\\/]/, '') || '.'\n  }\n}\n","/*\n * @Description  :\n * @Author       : tcsl-fast-tianyu\n * @Date         : 2025-09-11\n * @LastEditors  : tcsl-fast-tianyu\n * @LastEditTime : 2025-10-21\n */\nimport prompts from 'prompts'\nimport chalk from 'chalk'\nimport type { ConfigFileInfo } from './ConfigService.ts'\nimport { ArrayUtils } from '../utils/array-utils.ts'\nimport { FileBrowserService } from './FileBrowserService.ts'\n\n/**\n * 配置UI服务类\n * 负责处理用户界面交互相关功能\n */\nexport class UIService {\n  private fileBrowserService: FileBrowserService\n\n  constructor() {\n    this.fileBrowserService = new FileBrowserService()\n  }\n\n  /**\n   * 选择配置文件（交互式）\n   */\n  async selectConfigFiles(allConfigs: ConfigFileInfo[]): Promise<ConfigFileInfo[]> {\n    if (allConfigs.length === 0) {\n      return []\n    }\n\n    // 按组分类配置文件\n    const groups = ArrayUtils.groupBy(allConfigs, config => config.group)\n    const selectedConfigs: ConfigFileInfo[] = []\n    const groupEntries = Array.from(groups.entries())\n    const totalGroups = groupEntries.length\n\n    // 逐组展示并选择文件\n    for (let i = 0; i < totalGroups; i++) {\n      const groupEntry = ArrayUtils.safeGet(groupEntries, i)\n      if (!groupEntry) continue\n\n      const [groupName, groupConfigs] = groupEntry\n      const currentIndex = i + 1\n\n      // 显示进度和组信息\n      console.log(\n        `${chalk.cyan(`[${currentIndex}/${totalGroups}]`)} ${chalk.bold(groupName)} ${chalk.gray(`(${groupConfigs.length} 个文件)`)}`\n      )\n\n      // 为当前组创建文件选择列表\n      const fileChoices = groupConfigs.map((config: ConfigFileInfo) => ({\n        title: config.name,\n        value: config,\n      }))\n\n      const { selectedFiles } = await prompts({\n        type: 'multiselect',\n        name: 'selectedFiles',\n        message: '选择要更新的文件:',\n        choices: fileChoices,\n        instructions: false,\n      })\n\n      if (!selectedFiles || selectedFiles.length === 0) {\n        continue\n      }\n\n      // 处理选择结果\n      selectedConfigs.push(...selectedFiles)\n    }\n\n    if (selectedConfigs.length === 0) {\n      console.log(chalk.yellow('⚠️ 未选择任何配置文件'))\n      return []\n    }\n\n    // 显示最终选择的文件汇总\n    this.displaySelectionSummary(selectedConfigs)\n\n    return selectedConfigs\n  }\n\n  /**\n   * 选择依赖列表文件（交互式）\n   * @param projectRoot 项目根目录\n   * @returns 选择的文件路径，如果未选择则返回 null\n   */\n  async selectDependencyFile(projectRoot: string): Promise<string | null> {\n    console.log(chalk.blue('\\n📦 依赖列表文件选择'))\n    console.log(chalk.gray('您可以选择使用本地 package.json 文件，或使用项目默认的依赖列表'))\n\n    // 询问是否要使用自定义 package.json 文件\n    const { useCustomFile } = await prompts({\n      type: 'confirm',\n      name: 'useCustomFile',\n      message: '是否要使用自定义 package.json 文件？',\n      initial: false,\n    })\n\n    if (!useCustomFile) {\n      console.log(chalk.green('✓ 使用项目默认依赖列表'))\n      return null\n    }\n\n    // 浏览文件系统选择 package.json 文件\n    return await this.fileBrowserService.browseForPackageJson(projectRoot)\n  }\n\n  /**\n   * 显示选择汇总\n   */\n  private displaySelectionSummary(selectedConfigs: ConfigFileInfo[]): void {\n    console.log(\n      `\\n${chalk.blue('📋')} ${chalk.bold('最终选择汇总:')} 共 ${selectedConfigs.length} 个文件`\n    )\n\n    const finalGroups = ArrayUtils.groupBy(selectedConfigs, config => config.group)\n\n    Array.from(finalGroups.entries()).forEach(([groupName, configs]) => {\n      console.log(`  ${chalk.green('✓')} ${groupName}: ${configs.length} 个文件`)\n    })\n  }\n}\n","import chalk from 'chalk'\nimport ora from 'ora'\nimport type { ArchitectureType, ProjectType, UpdateConfigOptions } from '../types.ts'\nimport { FileService } from './FileService.ts'\nimport { Discovery } from '../core/Discovery.ts'\nimport { UIService } from './UIService.ts'\n/**\n * 配置文件信息接口\n */\nexport interface ConfigFileInfo {\n  name: string\n  path: string\n  templatePath: string\n  description: string\n  commentPrefix?: string\n  commentSuffix?: string\n  group: string\n  priority: number\n}\n\n/**\n * 配置服务类\n * 负责管理项目配置文件的扫描、分析和更新\n */\nexport class ConfigService {\n  private templatesDir: string\n  private fileService: FileService\n  private uiService: UIService\n\n  constructor(templatesDir: string) {\n    this.templatesDir = templatesDir\n    this.fileService = new FileService(templatesDir)\n    this.uiService = new UIService()\n  }\n\n  /**\n   * 更新项目配置文件\n   */\n  async updateConfig(options?: UpdateConfigOptions): Promise<void> {\n    // 添加初始加载状态\n    const initialSpinner = options?.silent ? null : ora('正在初始化配置更新...').start()\n\n    try {\n      let projectPath, rootPath\n      if (options?.projectPath) {\n        // eslint-disable-next-line prefer-destructuring\n        projectPath = options.projectPath\n        // eslint-disable-next-line prefer-destructuring\n        rootPath = options.rootPath\n      } else {\n        const { projectPath: discoveredProjectPath, rootPath: discoveredRootPath } =\n          await Discovery.findProjectRoot()\n        projectPath = discoveredProjectPath\n        rootPath = discoveredRootPath\n      }\n\n      if (!projectPath || !rootPath) {\n        if (initialSpinner) initialSpinner.fail('未找到项目根目录（package.json）')\n        throw new Error('未找到项目根目录（package.json）')\n      }\n\n      // 添加架构检测加载状态\n      if (initialSpinner) {\n        initialSpinner.text = '正在检测项目架构...'\n      }\n\n      // 检测项目架构类型\n      const architecture =\n        options?.architectureType ?? (await Discovery.detectArchitectureType(rootPath))\n\n      // 检测项目类型\n      const projectType = options?.projectType ?? (await Discovery.detectProjectType(projectPath))\n\n      if (initialSpinner) {\n        initialSpinner.succeed(\n          chalk.gray(\n            `📋 项目架构: ${architecture}；项目类型: ${projectType === 'app' ? '应用' : projectType === 'lib' ? '库' : '根目录'}`\n          )\n        )\n      }\n      // 获取可用的配置文件列表\n      const allConfigs = await Discovery.getAvailableConfigFiles(\n        this.templatesDir,\n        projectPath,\n        options\n      )\n\n      if (allConfigs.length === 0) {\n        if (!options?.silent) {\n          console.log(chalk.yellow('⚠️ 未找到可更新的配置文件'))\n        }\n        return\n      }\n\n      // 选择要更新的文件（静默模式下选择所有文件）\n      const selectedConfigs = options?.silent\n        ? allConfigs\n        : await this.uiService.selectConfigFiles(allConfigs)\n\n      if (selectedConfigs.length === 0) {\n        return\n      }\n\n      await this.updateSelectedConfigs(\n        selectedConfigs,\n        projectPath,\n        rootPath,\n        architecture,\n        projectType,\n        options?.silent\n      )\n    } catch (error) {\n      if (initialSpinner) {\n        initialSpinner.fail('配置更新初始化失败')\n      }\n      throw error\n    }\n  }\n\n  /**\n   * 更新选中的配置文件\n   */\n  private async updateSelectedConfigs(\n    selectedConfigs: ConfigFileInfo[],\n    projectRoot: string,\n    rootPath: string,\n    architecture: ArchitectureType,\n    projectType: ProjectType,\n    silent?: boolean\n  ): Promise<void> {\n    let spinner = silent ? null : ora('正在更新配置文件...').start()\n\n    try {\n      let updatedCount = 0\n      let hasEnvFiles = false\n      for (const config of selectedConfigs) {\n        try {\n          await this.fileService.updateConfigFile(\n            config,\n            projectRoot,\n            rootPath,\n            architecture,\n            projectType\n          )\n          updatedCount++\n          // 检查是否包含环境变量文件\n          if (config.group === 'env' || config.name.startsWith('.env')) {\n            hasEnvFiles = true\n          }\n        } catch (error: any) {\n          // 记录失败的文件，但继续处理其他文件\n          if (!silent && spinner) {\n            spinner.warn(chalk.yellow(`⚠️ ${error.message}`))\n            spinner = ora('正在更新配置文件...').start()\n          }\n        }\n      }\n\n      if (spinner) {\n        const totalFiles = selectedConfigs.length\n        const failedCount = totalFiles - updatedCount\n        let message = `配置更新完成！成功更新 ${updatedCount}/${totalFiles} 个文件`\n\n        if (failedCount > 0) {\n          message += chalk.yellow(` (${failedCount} 个文件更新失败)`)\n        }\n\n        if (hasEnvFiles) {\n          message += chalk.gray(' • 已更新环境变量配置')\n        }\n\n        spinner.succeed(chalk.green(message))\n      }\n\n      // 只有在更新了环境变量文件时才检查并更新package.json中的构建脚本\n      if (hasEnvFiles) {\n        await Discovery.updatePackageJsonScripts(projectRoot)\n      }\n    } catch (error: any) {\n      if (spinner) {\n        spinner.fail(chalk.red('配置文件更新失败'))\n      }\n      throw error\n    }\n  }\n}\n","import chalk from 'chalk'\nimport prompts from 'prompts'\nimport { join } from 'path'\nimport type { ArchitectureType, FrameworkType, ProjectOptions } from '../types.ts'\nimport type { CreateProjectOptions } from '../workflows/CreateProjectWorkflow.ts'\n\n/**\n * 项目选项服务\n * 负责处理用户输入和项目配置选项的获取\n */\nexport class ProjectOptionsService {\n  constructor() {\n    // 初始化服务\n  }\n  /**\n   * 获取项目创建选项\n   */\n  async getProjectOptions(\n    projectName?: string,\n    options: ProjectOptions = {}\n  ): Promise<CreateProjectOptions> {\n    console.log()\n    // 开始创建项目\n    console.log()\n\n    // 获取项目基本信息\n    const name = await this.getProjectName(projectName)\n    const architecture = await this.getArchitectureType(options)\n    const framework = await this.getFrameworkType(options)\n\n    // 获取项目路径\n    const targetPath = await this.getTargetPath()\n\n    // 显示项目配置摘要\n    await this.displayProjectSummary({\n      projectName: name,\n      architectureType: architecture,\n      framework,\n      targetPath,\n    })\n\n    return {\n      projectName: name,\n      architectureType: architecture,\n      framework,\n      targetPath,\n    }\n  }\n\n  /**\n   * 获取项目名称\n   */\n  private async getProjectName(projectName?: string): Promise<string> {\n    if (projectName) {\n      return projectName\n    }\n\n    const response = await prompts(\n      {\n        type: 'text',\n        name: 'projectName',\n        message: '请输入项目名称:',\n        initial: 'my-project',\n        validate: (value: string) => {\n          if (!value.trim()) return '项目名称不能为空'\n          if (!/^[a-zA-Z0-9-_]+$/.test(value)) return '项目名称只能包含字母、数字、连字符和下划线'\n          return true\n        },\n      },\n      {\n        onCancel: () => {\n          // 已取消项目创建\n          process.exit(0)\n        },\n      }\n    )\n\n    if (!response.projectName) {\n      // 已取消项目创建\n      process.exit(0)\n    }\n\n    return response.projectName\n  }\n\n  /**\n   * 获取架构类型\n   */\n  private async getArchitectureType(options: ProjectOptions): Promise<ArchitectureType> {\n    if (options.architecture) {\n      return options.architecture\n    }\n\n    if (options.monorepo) {\n      return 'monorepo'\n    }\n\n    if (options.single) {\n      return 'single'\n    }\n\n    const response = await prompts(\n      {\n        type: 'select',\n        name: 'architecture',\n        message: '选择项目架构:',\n        choices: [\n          {\n            title: '单体仓库 (Single Repository)',\n            value: 'single',\n            description: '适合小到中型项目，所有代码在一个仓库中',\n          },\n          {\n            title: 'Monorepo (多包管理)',\n            value: 'monorepo',\n            description: '适合大型项目，支持多个包的统一管理',\n          },\n        ],\n        initial: 0,\n      },\n      {\n        onCancel: () => {\n          // 已取消项目创建\n          process.exit(0)\n        },\n      }\n    )\n\n    if (!response.architecture) {\n      // 已取消项目创建\n      process.exit(0)\n    }\n\n    return response.architecture\n  }\n\n  /**\n   * 获取框架类型\n   */\n  private async getFrameworkType(options: ProjectOptions): Promise<FrameworkType> {\n    if (options.framework) {\n      return options.framework\n    }\n\n    // 目前只支持 Vue3，直接返回\n    return 'vue3'\n  }\n\n  /**\n   * 获取目标路径\n   */\n  private async getTargetPath(): Promise<string> {\n    // 直接在当前目录下创建项目文件夹\n    return process.cwd()\n  }\n\n  /**\n   * 显示项目配置摘要\n   */\n  private async displayProjectSummary(config: {\n    projectName: string\n    architectureType: ArchitectureType\n    framework: FrameworkType\n    targetPath: string\n  }): Promise<void> {\n    console.log()\n    // 项目配置摘要\n    console.log(chalk.gray('─'.repeat(50)))\n    console.log(`${chalk.bold('项目名称:')} ${chalk.cyan(config.projectName)}`)\n    console.log(\n      `${chalk.bold('项目架构:')} ${chalk.cyan(config.architectureType === 'monorepo' ? 'Monorepo' : 'Single Repository')}`\n    )\n    console.log(`${chalk.bold('开发框架:')} ${chalk.cyan('Vue 3')}`)\n    console.log(\n      `${chalk.bold('创建路径:')} ${chalk.cyan(join(config.targetPath, config.projectName))}`\n    )\n    console.log(chalk.gray('─'.repeat(50)))\n    console.log()\n  }\n}\n"],"names":["MergeService","configMerger","constructor","this","FileMerger","determineUpdateMode","targetContent","templateContent","config","trim","group","includes","name","mergeConfigContent","BuildToolsService","mergeService","updatedMonorepoConfigs","Set","isTsConfigSeparated","content","tsConfig","JSON","parse","extendsValue","reg","cleanValue","replace","test","Array","isArray","some","item","checkExtends","extends","isViteConfigSeparated","checkConfigStatus","projectPath","type","fileName","configPath","join","FileOperations","exists","readFile","isSeparated","process","configType","templatesDir","rootPath","architecture","projectType","handleProjectConfigNotExists","handleProjectConfigSeparated","handleProjectConfigNotSeparated","calculateRelativePath","from","to","relativePath","relative","startsWith","updateBaseConfigFile","targetPath","templatePath","configKey","has","writeFile","add","mergeAndUpdateBaseConfigFile","configsFilePath","configName","existingContent","mergedContent","ensureDir","baseTemplatePath","baseTargetPath","relativeConfigsPath","stringify","baseTemplateContent","baseTargetContent","mergedBaseContent","mergedProjectContent","projectConfigPath","backupConfigPath","rename","console","log","commentPrefix","commentSuffix","FileService","buildToolsService","updateConfigFile","projectRoot","updateCtx","finalContent","getAutoUpdateModeOfNpmrc","getAutoUpdateMode","updateMode","path","mode","error","Error","message","dirname","architectureTemplatePath","architectureTemplateContent","FileBrowserService","browseForPackageJson","startDir","currentDir","selectedFile","action","file","browseDirectory","chalk","yellow","parentDir","green","basename","entries","readdir","withFileTypes","getRelativePath","blue","choices","buildChoices","length","selection","prompts","instructions","errorMessage","red","push","title","value","description","entry","isFile","addDirectoriesWithPackageJson","getDirectoriesWithPackageJson","forEach","dir","directoriesWithPackageJson","isDirectory","subEntries","subEntry","sort","a","b","localeCompare","UIService","fileBrowserService","selectConfigFiles","allConfigs","groups","ArrayUtils","groupBy","selectedConfigs","groupEntries","totalGroups","i","groupEntry","safeGet","groupName","groupConfigs","currentIndex","cyan","bold","gray","fileChoices","map","selectedFiles","displaySelectionSummary","selectDependencyFile","useCustomFile","initial","finalGroups","configs","fileService","uiService","updateConfig","options","initialSpinner","silent","ora","start","discoveredProjectPath","discoveredRootPath","Discovery","findProjectRoot","fail","text","architectureType","detectArchitectureType","detectProjectType","succeed","getAvailableConfigFiles","updateSelectedConfigs","spinner","updatedCount","hasEnvFiles","warn","totalFiles","failedCount","updatePackageJsonScripts","getProjectOptions","projectName","getProjectName","getArchitectureType","framework","getFrameworkType","getTargetPath","displayProjectSummary","response","validate","onCancel","exit","monorepo","single","cwd","repeat"],"mappings":"2RAOO,MAAMA,EACHC,aAER,WAAAC,GACEC,KAAKF,aAAe,IAAIG,YAC1B,CAKA,yBAAMC,CACJC,EACAC,EACAC,GAGA,GAAIF,EAAcG,SAAWF,EAAgBE,OAC3C,MAAO,OAIT,MACmB,cAAjBD,EAAOE,OAHY,CAAC,aAAc,iBAIrBC,SAASH,EAAOI,QAC5BN,EAAcG,OAER,YAIF,OACT,CAKA,wBAAMI,CACJP,EACAC,EACAC,GAGA,OAAOL,KAAKF,aAAaY,mBAAmBP,EAAeC,EAAiBC,EAC9E,ECzCK,MAAMM,EACHC,aAEAC,uBAER,WAAAd,GACEC,KAAKY,aAAe,IAAIf,EACxBG,KAAKa,2BAA6BC,GACpC,CAKQ,mBAAAC,CAAoBC,GAC1B,IACE,MAAMC,EAAWC,KAAKC,MAAMH,GA0B5B,MAvBqB,CAACI,IAEpB,MAAMC,EAAM,4CAEZ,GAA4B,iBAAjBD,EAA2B,CAEpC,MAAME,EAAaF,EAAaG,QAAQ,eAAgB,IACxD,OAAOF,EAAIG,KAAKF,EAClB,CAEA,QAAIG,MAAMC,QAAQN,IACTA,EAAaO,KAAKC,IACvB,GAAoB,iBAATA,EAAmB,CAC5B,MAAMN,EAAaM,EAAKL,QAAQ,eAAgB,IAChD,OAAOF,EAAIG,KAAKF,EAClB,CACA,OAAO,KAONO,CAAaZ,EAASa,SAAW,GAC1C,CAAA,MAEE,OAAO,CACT,CACF,CAKQ,qBAAAC,CAAsBf,GAI5B,MADY,+DACDQ,KAAKR,EAClB,CAKA,uBAAcgB,CACZC,EACAC,GAEA,MAAMC,EAAoB,SAATD,EAAkB,iBAAmB,gBACtD,IACE,MAAME,EAAaC,EAAAA,KAAKJ,EAAaE,GAIrC,WADqBG,iBAAeC,OAAOH,IAEzC,MAAO,aAIT,MAAMpB,QAAgBsB,iBAAeE,SAASJ,GAG9C,IAAIK,EAOJ,OALEA,EADW,SAATP,EACYlC,KAAK+B,sBAAsBf,GAE3BhB,KAAKe,oBAAoBC,GAGlCyB,EAAc,YAAc,eACrC,CAAA,MAEE,MAAO,YACT,CACF,CAKA,aAAMC,CACJC,EACAC,EACAX,EACAY,EACAC,EACAC,GAOA,aAFqB/C,KAAKgC,kBAAkBC,EAAaU,IAGvD,IAAK,mBACG3C,KAAKgD,6BACTJ,EACAX,EACAY,EACAF,EACAG,EACAC,GAEF,MACF,IAAK,kBACG/C,KAAKiD,6BACTL,EACAX,EACAY,EACAF,EACAG,EACAC,GAEF,MACF,IAAK,sBACG/C,KAAKkD,gCACTN,EACAX,EACAY,EACAF,EACAG,EACAC,GAIR,CAKQ,qBAAAI,CAAsBC,EAAcC,GAC1C,MAAMC,EAAeC,EAAAA,SAASH,EAAMC,GAAI9B,QAAQ,MAAO,KAEvD,OAAK+B,EAAaE,WAAW,OAAUF,EAAaE,WAAW,OAGxDF,EAFE,KAAKA,GAGhB,CAKA,0BAAcG,CAAqBC,EAAoBC,GACrD,MAAMC,EAAYF,EAElB,IAAK1D,KAAKa,uBAAuBgD,IAAID,GAAY,CAC/C,MAAMxD,QAAwBkC,iBAAeE,SAASmB,SAChDrB,iBAAewB,UAAUJ,EAAYtD,GAC3CJ,KAAKa,uBAAuBkD,IAAIH,EAClC,CACF,CAKA,kCAAcI,CACZC,EACAN,EACAO,GAEA,MAAMN,EAAYK,EAElB,IAAKjE,KAAKa,uBAAuBgD,IAAID,GAAY,CAC/C,MAAMxD,QAAwBkC,iBAAeE,SAASmB,GAChDQ,QAAwB7B,iBAAeE,SAASyB,GAChDG,QAAsBpE,KAAKU,mBAC/ByD,EACA/D,EACA8D,SAEI5B,iBAAewB,UAAUG,EAAiBG,GAChDpE,KAAKa,uBAAuBkD,IAAIH,EAClC,CACF,CAKA,kCAAcZ,CACZJ,EACAX,EACAY,EACAF,EACAG,EACAC,SAGMT,EAAAA,eAAe+B,UAAUhC,EAAAA,KAAKQ,EAAU,YAG9C,MAAMV,EAA0B,SAAfQ,EAAwB,iBAAmB,gBACtD2B,EAAmBjC,EAAAA,KAAKO,EAAc,UAAW,cAAeT,GAChEoC,EAAiBlC,EAAAA,KAAKQ,EAAU,UAAWV,GAGjD,SAFMnC,KAAKyD,qBAAqBc,EAAgBD,GAE3B,aAAjBxB,GAA+C,SAAhBC,EAAwB,OAG3D,MAAMY,EAAetB,EAAAA,KACnBO,EACA,UACA,cACgB,QAAhBG,EAAwB,OAAS,OACjCZ,GAEF,IAAI/B,QAAwBkC,iBAAeE,SAASmB,GAGpD,MAAMa,EAAsBxE,KAAKmD,sBAAsBlB,EAAaI,OAAKQ,EAAU,YAEnF,GAAmB,SAAfF,EAEFvC,EAAkB,8BAA8BoE,mBAAqCpE,IAGrFA,EAAkBA,EAAgBmB,QAChC,mBACA,sDAEG,CAEL,MAAMN,EAAWC,KAAKC,MAAMf,GAE5Ba,EAASa,QAAU,GAAG0C,kBACtBpE,EAAkBc,KAAKuD,UAAUxD,EAAU,KAAM,EACnD,OAGMqB,EAAAA,eAAewB,UAAUzB,EAAAA,KAAKJ,EAAaE,GAAW/B,EAC9D,CAKA,kCAAc6C,CACZL,EACAX,EACAY,EACAF,EACAG,EACAC,GAGA,MAAMZ,EAA0B,SAAfQ,EAAwB,iBAAmB,gBACtD4B,EAAiBlC,EAAAA,KAAKQ,EAAU,UAAWV,GAE3CmC,EAAmBjC,EAAAA,KAAKO,EAAc,UAAW,cAAeT,GAEtE,GAAqB,aAAjBW,QACI9C,KAAKgE,6BAA6BO,EAAgBD,EAAkBnC,OACrE,CACL,MAAMuC,QAA4BpC,iBAAeE,SAAS8B,GAEpDK,QAA0BrC,iBAAeE,SAAS+B,GAClDK,QAA0B5E,KAAKU,mBACnCiE,EACAD,EACAvC,SAEIG,iBAAewB,UAAUS,EAAgBK,EACjD,CACA,GAAqB,aAAjB9B,GAA+C,SAAhBC,EAAwB,OAG3D,MAAMY,EAAetB,EAAAA,KACnBO,EACA,UACA,cACgB,QAAhBG,EAAwB,OAAS,OACjCZ,GAEI/B,QAAwBkC,iBAAeE,SAASmB,GAGhDD,EAAarB,EAAAA,KAAKJ,EAAaE,GAC/BhC,QAAsBmC,iBAAeE,SAASkB,GAC9CmB,QAA6B7E,KAAKU,mBACtCP,EACAC,EACA+B,SAEIG,iBAAewB,UAAUJ,EAAYmB,EAC7C,CAKA,qCAAc3B,CACZN,EACAX,EACAY,EACAF,EACAG,EACAC,GAEA,MAAMZ,EAA0B,SAAfQ,EAAwB,iBAAmB,gBACtDmC,EAAoBzC,EAAAA,KAAKJ,EAAaE,GACtC4C,EAAmB,GAAGD,iBAElBxC,EAAAA,eAAeC,OAAOuC,WACxBxC,iBAAe0C,OAAOF,EAAmBC,GAC/CE,QAAQC,IAAI,eAAeH,YAKvB/E,KAAKgD,6BACTJ,EACAX,EACAY,EACAF,EACAG,EACAC,EAEJ,CAKA,wBAAcrC,CACZP,EACAC,EACA8D,GAEA,MAAMiB,EAAuC,mBAAfjB,EAAkC,MAAQ,KAClEkB,EAAuC,mBAAflB,EAAkC,IAAM,KAEtE,OAAOlE,KAAKY,aAAaF,mBAAmBP,EAAeC,EAAiB,CAC1EK,KAAMyD,EACNiB,gBACAC,iBAEJ,EC1VK,MAAMC,EACHzC,aACAhC,aACA0E,kBAER,WAAAvF,CAAY6C,GACV5C,KAAK4C,aAAeA,EACpB5C,KAAKY,aAAe,IAAIf,EACxBG,KAAKsF,kBAAoB,IAAI3E,CAC/B,CAKA,sBAAM4E,CACJlF,EACAmF,EACA3C,EACAC,EACAC,GAEA,IAEE,GAAI1C,EAAOI,KAAK+C,WAAW,eAUzB,aATMxD,KAAKsF,kBAAkB5C,QAC3B,OACA1C,KAAK4C,aACL4C,EACA3C,EACAC,EACAC,IAGK,EAIT,GAAoB,kBAAhB1C,EAAOI,KAWT,aATMT,KAAKsF,kBAAkB5C,QAC3B,KACA1C,KAAK4C,aACL4C,EACA3C,EACAC,EACAC,IAGK,EAGT,IAAI0C,EAgBAC,EANJ,OANED,EAFkB,YAAhBpF,EAAOI,MAAsC,WAAhBJ,EAAOI,WAEpBT,KAAK2F,yBAAyBtF,EAAQyC,SAGtC9C,KAAK4F,kBAAkBvF,GAGd,SAAzBoF,EAAUI,YAEL,GAOPH,EAF2B,cAAzBD,EAAUI,WAEGJ,EAAUrF,sBAGJJ,KAAKY,aAAaF,mBACrC+E,EAAUtF,cACVsF,EAAUrF,gBACVC,SAKEiC,EAAAA,eAAewB,UACnBzD,EAAOyF,KACPJ,EACiB,cAAjBrF,EAAOE,MAAwB,CAAEwF,KAAM,KAAU,SAE5C,EACT,OAASC,GAGP,MAAM,IAAIC,MAAM,YAAY5F,EAAOI,SAASuF,EAAME,UACpD,CACF,CAKA,uBAAcN,CAAkBvF,GAK9B,MAAMsD,aAAEA,EAAcmC,KAAMpC,GAAerD,EAErCD,QAAwBkC,iBAAeE,SAASmB,GAGtD,IAAIxD,EAAgB,SADOmC,iBAAeC,OAAOmB,GAI/CvD,QAAsBmC,EAAAA,eAAeE,SAASkB,SAGxCpB,iBAAe+B,UAAU8B,EAAAA,QAAQzC,IAUzC,MAAO,CACLmC,iBAPuB7F,KAAKY,aAAaV,oBACzCC,EACAC,EACAC,GAKAF,gBACAC,kBAEJ,CAKA,8BAAcuF,CACZtF,EACAyC,GAOA,MAAMwB,EAAmBjE,EAAOsD,aAE1ByC,EAA2B/D,EAAAA,KAC/BrC,KAAK4C,aACL,UACA,MACAE,EACAzC,EAAOI,KAAKc,QAAQ,MAAO,KAIvBmD,QAA4BpC,iBAAeE,SAAS8B,GACpD+B,QAAoC/D,iBAAeE,SAAS4D,GAE5DhG,QAAwBJ,KAAKY,aAAaF,mBAC9C2F,EACA3B,EACArE,GAIF,IAAIF,EAAgB,SADOmC,EAAAA,eAAeC,OAAOlC,EAAOyF,MAItD3F,QAAsBmC,EAAAA,eAAeE,SAASnC,EAAOyF,YAG/CxD,EAAAA,eAAe+B,UAAU8B,EAAAA,QAAQ9F,EAAOyF,OAWhD,MAAO,CACLD,iBARuB7F,KAAKY,aAAaV,oBACzCC,EACAC,EACAC,GAMAF,gBACAC,kBAEJ,EC3LK,MAAMkG,EAMX,0BAAMC,CAAqBC,GACzB,IAAIC,EAAaD,EACbE,EAA8B,KAElC,OAAa,CACX,MAAMC,OAAEA,OAAQC,SAAe5G,KAAK6G,gBAAgBJ,EAAYD,GAEhE,GAAe,WAAXG,EAEF,OADA1B,QAAQC,IAAI4B,EAAMC,OAAO,aAClB,KAGT,GAAe,WAAXJ,GAAuBC,EAAM,CAC/BF,EAAeE,EACf,KACF,CAMA,GAJe,aAAXD,GAAyBC,IAC3BH,EAAaG,GAGA,SAAXD,EAAmB,CACrB,MAAMK,EAAYb,EAAAA,QAAQM,GACtBO,IAAcP,IAChBA,EAAaO,EAEjB,CACF,CAMA,OAJIN,GACFzB,QAAQC,IAAI4B,EAAMG,MAAM,UAAUC,WAASR,OAGtCA,CACT,CAKA,qBAAcG,CACZJ,EACAD,GAEA,IACE,MAAMW,QAAgBC,EAAAA,QAAQX,EAAY,CAAEY,eAAe,IACrD/D,EAAetD,KAAKsH,gBAAgBb,EAAYD,GAEtDvB,QAAQC,IAAI4B,EAAMS,KAAK,cAAcjE,MAErC,MAAMkE,QAAgBxH,KAAKyH,aAAaN,EAASV,GAEjD,GAAuB,IAAnBe,EAAQE,OAEV,OADAzC,QAAQC,IAAI4B,EAAMC,OAAO,iCAClB,CAAEJ,OAAQ,UAGnB,MAAMgB,UAAEA,SAAoBC,EAAQ,CAClC1F,KAAM,SACNzB,KAAM,YACNyF,QAAS,SACTsB,UACAK,cAAc,IAGhB,OAAOF,GAAa,CAAEhB,OAAQ,SAChC,OAASX,GACP,MAAM8B,EAAe9B,aAAiBC,MAAQD,EAAME,QAAU,OAE9D,OADAjB,QAAQC,IAAI4B,EAAMiB,IAAI,aAAaD,MAC5B,CAAEnB,OAAQ,SACnB,CACF,CAKA,kBAAcc,CACZN,EACAV,GAQA,MAAMe,EAID,GAGDrB,EAAAA,QAAQM,KAAgBA,GAC1Be,EAAQQ,KAAK,CACXC,MAAO,iBACPC,MAAO,CAAEvB,OAAQ,QACjBwB,YAAa,WAyBjB,OApBuBhB,EAAQxF,KAAKyG,GAASA,EAAMC,UAA2B,iBAAfD,EAAM3H,OAGnE+G,EAAQQ,KAAK,CACXC,MAAO,kBACPC,MAAO,CAAEvB,OAAQ,SAAUC,KAAMvE,OAAKoE,EAAY,iBAClD0B,YAAa,gBAKXnI,KAAKsI,8BAA8Bd,EAASL,EAASV,GAG3De,EAAQQ,KAAK,CACXC,MAAO,OACPC,MAAO,CAAEvB,OAAQ,UACjBwB,YAAa,SAGRX,CACT,CAKA,mCAAcc,CACZd,EAKAL,EACAV,UAEyCzG,KAAKuI,8BAA8BpB,EAASV,IAE1D+B,QAAQC,IACjCjB,EAAQQ,KAAK,CACXC,MAAO,MAAMQ,EAAIhI,QACjByH,MAAO,CAAEvB,OAAQ,WAAYC,KAAMvE,EAAAA,KAAKoE,EAAYgC,EAAIhI,OACxD0H,YAAa,UAGnB,CAKA,mCAAcI,CACZpB,EACAV,GAEA,MAAMiC,EAAsD,GAE5D,IAAA,MAAWN,KAASjB,EAClB,GAAIiB,EAAMO,gBAAkBP,EAAM3H,KAAK+C,WAAW,KAChD,IACE,MAAMoF,QAAmBxB,UAAQ/E,EAAAA,KAAKoE,EAAY2B,EAAM3H,MAAO,CAAE4G,eAAe,IACzDuB,EAAWjH,KAChCkH,GAAYA,EAASR,UAA8B,iBAAlBQ,EAASpI,OAI1CiI,EAA2BV,KAAK,CAAEvH,KAAM2H,EAAM3H,MAElD,CAAA,MAEA,CAIJ,OAAOiI,EAA2BI,KAAK,CAACC,EAAGC,IAAMD,EAAEtI,KAAKwI,cAAcD,EAAEvI,MAC1E,CAKQ,eAAA6G,CAAgBb,EAAoBD,GAC1C,OAAOC,EAAWlF,QAAQiF,EAAU,IAAIjF,QAAQ,SAAU,KAAO,GACnE,ECnLK,MAAM2H,EACHC,mBAER,WAAApJ,GACEC,KAAKmJ,mBAAqB,IAAI7C,CAChC,CAKA,uBAAM8C,CAAkBC,GACtB,GAA0B,IAAtBA,EAAW3B,OACb,MAAO,GAIT,MAAM4B,EAASC,EAAAA,WAAWC,QAAQH,EAAYhJ,GAAUA,EAAOE,OACzDkJ,EAAoC,GACpCC,EAAejI,MAAM2B,KAAKkG,EAAOnC,WACjCwC,EAAcD,EAAahC,OAGjC,IAAA,IAASkC,EAAI,EAAGA,EAAID,EAAaC,IAAK,CACpC,MAAMC,EAAaN,EAAAA,WAAWO,QAAQJ,EAAcE,GACpD,IAAKC,EAAY,SAEjB,MAAOE,EAAWC,GAAgBH,EAC5BI,EAAeL,EAAI,EAGzB3E,QAAQC,IACN,GAAG4B,EAAMoD,KAAK,IAAID,KAAgBN,SAAmB7C,EAAMqD,KAAKJ,MAAcjD,EAAMsD,KAAK,IAAIJ,EAAatC,kBAI5G,MAAM2C,EAAcL,EAAaM,IAAKjK,IAAA,CACpC4H,MAAO5H,EAAOI,KACdyH,MAAO7H,MAGHkK,cAAEA,SAAwB3C,EAAQ,CACtC1F,KAAM,cACNzB,KAAM,gBACNyF,QAAS,YACTsB,QAAS6C,EACTxC,cAAc,IAGX0C,GAA0C,IAAzBA,EAAc7C,QAKpC+B,EAAgBzB,QAAQuC,EAC1B,CAEA,OAA+B,IAA3Bd,EAAgB/B,QAClBzC,QAAQC,IAAI4B,EAAMC,OAAO,iBAClB,KAIT/G,KAAKwK,wBAAwBf,GAEtBA,EACT,CAOA,0BAAMgB,CAAqBjF,GACzBP,QAAQC,IAAI4B,EAAMS,KAAK,kBACvBtC,QAAQC,IAAI4B,EAAMsD,KAAK,2CAGvB,MAAMM,cAAEA,SAAwB9C,EAAQ,CACtC1F,KAAM,UACNzB,KAAM,gBACNyF,QAAS,4BACTyE,SAAS,IAGX,OAAKD,QAMQ1K,KAAKmJ,mBAAmB5C,qBAAqBf,IALxDP,QAAQC,IAAI4B,EAAMG,MAAM,iBACjB,KAKX,CAKQ,uBAAAuD,CAAwBf,GAC9BxE,QAAQC,IACN,KAAK4B,EAAMS,KAAK,SAAST,EAAMqD,KAAK,gBAAgBV,EAAgB/B,cAGtE,MAAMkD,EAAcrB,EAAAA,WAAWC,QAAQC,EAAiBpJ,GAAUA,EAAOE,OAEzEkB,MAAM2B,KAAKwH,EAAYzD,WAAWqB,QAAQ,EAAEuB,EAAWc,MACrD5F,QAAQC,IAAI,KAAK4B,EAAMG,MAAM,QAAQ8C,MAAcc,EAAQnD,eAE/D,wBCnGK,MACG9E,aACAkI,YACAC,UAER,WAAAhL,CAAY6C,GACV5C,KAAK4C,aAAeA,EACpB5C,KAAK8K,YAAc,IAAIzF,EAAYzC,GACnC5C,KAAK+K,UAAY,IAAI7B,CACvB,CAKA,kBAAM8B,CAAaC,GAEjB,MAAMC,EAAiBD,GAASE,OAAS,KAAOC,EAAI,gBAAgBC,QAEpE,IACE,IAAIpJ,EAAaY,EACjB,GAAIoI,GAAShJ,YAEXA,EAAcgJ,EAAQhJ,YAEtBY,EAAWoI,EAAQpI,aACd,CACL,MAAQZ,YAAaqJ,EAAuBzI,SAAU0I,SAC9CC,EAAAA,UAAUC,kBAClBxJ,EAAcqJ,EACdzI,EAAW0I,CACb,CAEA,IAAKtJ,IAAgBY,EAEnB,MADIqI,GAAgBA,EAAeQ,KAAK,0BAClC,IAAIzF,MAAM,0BAIdiF,IACFA,EAAeS,KAAO,eAIxB,MAAM7I,EACJmI,GAASW,wBAA2BJ,EAAAA,UAAUK,uBAAuBhJ,GAGjEE,EAAckI,GAASlI,mBAAsByI,EAAAA,UAAUM,kBAAkB7J,GAE3EiJ,GACFA,EAAea,QACbjF,EAAMsD,KACJ,YAAYtH,WAAsC,QAAhBC,EAAwB,KAAuB,QAAhBA,EAAwB,IAAM,UAKrG,MAAMsG,QAAmBmC,EAAAA,UAAUQ,wBACjChM,KAAK4C,aACLX,EACAgJ,GAGF,GAA0B,IAAtB5B,EAAW3B,OAIb,YAHKuD,GAASE,QACZlG,QAAQC,IAAI4B,EAAMC,OAAO,oBAM7B,MAAM0C,EAAkBwB,GAASE,OAC7B9B,QACMrJ,KAAK+K,UAAU3B,kBAAkBC,GAE3C,GAA+B,IAA3BI,EAAgB/B,OAClB,aAGI1H,KAAKiM,sBACTxC,EACAxH,EACAY,EACAC,EACAC,EACAkI,GAASE,OAEb,OAASnF,GAIP,MAHIkF,GACFA,EAAeQ,KAAK,aAEhB1F,CACR,CACF,CAKA,2BAAciG,CACZxC,EACAjE,EACA3C,EACAC,EACAC,EACAoI,GAEA,IAAIe,EAAUf,EAAS,KAAOC,EAAI,eAAeC,QAEjD,IACE,IAAIc,EAAe,EACfC,GAAc,EAClB,IAAA,MAAW/L,KAAUoJ,EACnB,UACQzJ,KAAK8K,YAAYvF,iBACrBlF,EACAmF,EACA3C,EACAC,EACAC,GAEFoJ,KAEqB,QAAjB9L,EAAOE,OAAmBF,EAAOI,KAAK+C,WAAW,WACnD4I,GAAc,EAElB,OAASpG,IAEFmF,GAAUe,IACbA,EAAQG,KAAKvF,EAAMC,OAAO,MAAMf,EAAME,YACtCgG,EAAUd,EAAI,eAAeC,QAEjC,CAGF,GAAIa,EAAS,CACX,MAAMI,EAAa7C,EAAgB/B,OAC7B6E,EAAcD,EAAaH,EACjC,IAAIjG,EAAU,eAAeiG,KAAgBG,QAEzCC,EAAc,IAChBrG,GAAWY,EAAMC,OAAO,KAAKwF,eAG3BH,IACFlG,GAAWY,EAAMsD,KAAK,iBAGxB8B,EAAQH,QAAQjF,EAAMG,MAAMf,GAC9B,CAGIkG,SACIZ,EAAAA,UAAUgB,yBAAyBhH,EAE7C,OAASQ,GAIP,MAHIkG,GACFA,EAAQR,KAAK5E,EAAMiB,IAAI,aAEnB/B,CACR,CACF,iCC9KK,MACL,WAAAjG,GAEA,CAIA,uBAAM0M,CACJC,EACAzB,EAA0B,IAE1BhG,QAAQC,MAERD,QAAQC,MAGR,MAAMzE,QAAaT,KAAK2M,eAAeD,GACjC5J,QAAqB9C,KAAK4M,oBAAoB3B,GAC9C4B,QAAkB7M,KAAK8M,iBAAiB7B,GAGxCvH,QAAmB1D,KAAK+M,gBAU9B,aAPM/M,KAAKgN,sBAAsB,CAC/BN,YAAajM,EACbmL,iBAAkB9I,EAClB+J,YACAnJ,eAGK,CACLgJ,YAAajM,EACbmL,iBAAkB9I,EAClB+J,YACAnJ,aAEJ,CAKA,oBAAciJ,CAAeD,GAC3B,GAAIA,EACF,OAAOA,EAGT,MAAMO,QAAiBrF,EACrB,CACE1F,KAAM,OACNzB,KAAM,cACNyF,QAAS,WACTyE,QAAS,aACTuC,SAAWhF,GACJA,EAAM5H,SACN,mBAAmBkB,KAAK0G,IAAe,wBADlB,YAK9B,CACEiF,SAAU,KAERzK,QAAQ0K,KAAK,MAUnB,OALKH,EAASP,aAEZhK,QAAQ0K,KAAK,GAGRH,EAASP,WAClB,CAKA,yBAAcE,CAAoB3B,GAChC,GAAIA,EAAQnI,aACV,OAAOmI,EAAQnI,aAGjB,GAAImI,EAAQoC,SACV,MAAO,WAGT,GAAIpC,EAAQqC,OACV,MAAO,SAGT,MAAML,QAAiBrF,EACrB,CACE1F,KAAM,SACNzB,KAAM,eACNyF,QAAS,UACTsB,QAAS,CACP,CACES,MAAO,2BACPC,MAAO,SACPC,YAAa,uBAEf,CACEF,MAAO,kBACPC,MAAO,WACPC,YAAa,sBAGjBwC,QAAS,GAEX,CACEwC,SAAU,KAERzK,QAAQ0K,KAAK,MAUnB,OALKH,EAASnK,cAEZJ,QAAQ0K,KAAK,GAGRH,EAASnK,YAClB,CAKA,sBAAcgK,CAAiB7B,GAC7B,OAAIA,EAAQ4B,UACH5B,EAAQ4B,UAIV,MACT,CAKA,mBAAcE,GAEZ,OAAOrK,QAAQ6K,KACjB,CAKA,2BAAcP,CAAsB3M,GAMlC4E,QAAQC,MAERD,QAAQC,IAAI4B,EAAMsD,KAAK,IAAIoD,OAAO,MAClCvI,QAAQC,IAAI,GAAG4B,EAAMqD,KAAK,YAAYrD,EAAMoD,KAAK7J,EAAOqM,gBACxDzH,QAAQC,IACN,GAAG4B,EAAMqD,KAAK,YAAYrD,EAAMoD,KAAiC,aAA5B7J,EAAOuL,iBAAkC,WAAa,wBAE7F3G,QAAQC,IAAI,GAAG4B,EAAMqD,KAAK,YAAYrD,EAAMoD,KAAK,YACjDjF,QAAQC,IACN,GAAG4B,EAAMqD,KAAK,YAAYrD,EAAMoD,KAAK7H,EAAAA,KAAKhC,EAAOqD,WAAYrD,EAAOqM,iBAEtEzH,QAAQC,IAAI4B,EAAMsD,KAAK,IAAIoD,OAAO,MAClCvI,QAAQC,KACV"}