create-einja-app 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/cli.js +14 -1
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/.env.ci +11 -4
- package/templates/default/.env.preview +25 -0
- package/templates/default/.github/workflows/ci.yml +73 -1
- package/templates/default/AGENTS.md +3 -0
- package/templates/default/apps/web/src/lib/auth/index.ts +5 -0
- package/templates/default/scripts/env-show.ts +1 -0
- package/templates/default/scripts/lib/env-common.ts +6 -0
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/project.ts","../src/generators/template.ts","../src/utils/fs.ts","../src/utils/logger.ts","../src/generators/post-setup.ts","../src/commands/setup.ts","../src/prompts/setup.ts","../src/generators/tools/direnv.ts","../src/generators/tools/dotenvx.ts","../src/utils/package-json.ts","../src/generators/tools/volta.ts","../src/generators/tools/biome.ts","../src/generators/tools/husky.ts","../src/commands/add.ts","../src/prompts/add.ts","../src/generators/partials/packages.ts","../src/utils/merger.ts","../src/utils/package-json-merger.ts","../src/generators/partials/apps.ts","../src/generators/partials/config.ts","../src/commands/sync.ts","../src/generators/sync.ts","../src/prompts/sync.ts","../src/utils/backup.ts","../src/utils/git.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { createCommand } from \"./commands/create.js\";\nimport { setupCommand } from \"./commands/setup.js\";\nimport { addCommand } from \"./commands/add.js\";\nimport { syncCommand } from \"./commands/sync.js\";\n\n// package.jsonからバージョン情報を読み込み\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJsonPath = join(__dirname, \"../package.json\");\nconst packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n\nconst program = new Command();\n\nprogram\n .name(\"create-einja-app\")\n .description(\"CLI tool to create new projects with Einja Management Template\")\n .version(packageJson.version);\n\n// createコマンド\nprogram\n .argument(\"[project-name]\", \"Project name\")\n .option(\"--skip-git\", \"Skip git initialization\")\n .option(\"--skip-install\", \"Skip package installation\")\n .action(\n async (\n projectName: string | undefined,\n options: {\n skipGit?: boolean;\n skipInstall?: boolean;\n }\n ) => {\n await createCommand(projectName, options);\n }\n );\n\n// setupコマンド\nprogram\n .command(\"setup\")\n .description(\"Setup tools for existing project\")\n .action(async () => {\n await setupCommand();\n });\n\n// addコマンド\nprogram\n .command(\"add\")\n .description(\"Add einja components to existing monorepo\")\n .option(\"--all\", \"Select all components\")\n .option(\"--dry-run\", \"Preview changes without making them\")\n .action(\n async (options: { all?: boolean; dryRun?: boolean }) => {\n await addCommand({\n skipPrompts: options.all || false,\n dryRun: options.dryRun || false,\n });\n }\n );\n\n// syncコマンド\nprogram\n .command(\"sync\")\n .description(\"Sync template files to existing project\")\n .option(\"--categories <categories>\", \"Comma-separated list of categories to sync\")\n .option(\"--all\", \"Sync all categories\")\n .option(\"--dry-run\", \"Preview changes without making them\")\n .option(\"--backup\", \"Create backup before syncing (default: true)\", true)\n .option(\"--rollback\", \"Rollback to previous backup\")\n .option(\"--force\", \"Force sync even with uncommitted changes\")\n .action(\n async (options: {\n categories?: string;\n all?: boolean;\n dryRun?: boolean;\n backup?: boolean;\n rollback?: boolean;\n force?: boolean;\n }) => {\n await syncCommand({\n categories: options.categories?.split(\",\"),\n all: options.all || false,\n dryRun: options.dryRun || false,\n backup: options.backup !== false, // デフォルトtrue\n rollback: options.rollback || false,\n force: options.force || false,\n });\n }\n );\n\nprogram.parse();\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport ora from \"ora\";\nimport { promptProjectConfig, type ProjectConfig } from \"../prompts/project.js\";\nimport { generateTemplate } from \"../generators/template.js\";\nimport { execPostSetup } from \"../generators/post-setup.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * ディレクトリが空かどうかを確認\n * @param dirPath - ディレクトリパス\n * @returns 空の場合true、存在しないかファイルがある場合false\n */\nfunction isDirectoryEmpty(dirPath: string): boolean {\n if (!existsSync(dirPath)) {\n return true;\n }\n const files = readdirSync(dirPath);\n // .git, .DS_Store などの隠しファイルは無視(空のGitリポジトリは空とみなす)\n const significantFiles = files.filter(\n (f) => !f.startsWith(\".\")\n );\n return significantFiles.length === 0;\n}\n\n/**\n * CreateOptions型\n * createコマンドのオプション\n */\ninterface CreateOptions {\n skipGit?: boolean;\n skipInstall?: boolean;\n yes?: boolean;\n}\n\n/**\n * プロジェクト名のバリデーション\n * @param projectName - プロジェクト名\n * @returns エラーメッセージ(問題なければundefined)\n */\nfunction validateProjectName(projectName: string): string | undefined {\n const regex = /^[a-zA-Z][a-zA-Z0-9_-]{0,49}$/;\n if (!regex.test(projectName)) {\n return \"プロジェクト名は英字で始まり、英数字・ハイフン・アンダースコアのみ使用できます(1〜50文字)\";\n }\n return undefined;\n}\n\n/**\n * プロジェクトディレクトリの存在確認\n * @param targetPath - ターゲットパス\n * @returns 存在する場合true\n */\nfunction checkProjectExists(targetPath: string): boolean {\n return existsSync(targetPath);\n}\n\n\n/**\n * createコマンドの実装\n * @param projectName - プロジェクト名(オプション)\n * @param options - コマンドオプション\n */\nexport async function createCommand(\n projectName: string | undefined,\n options: CreateOptions\n): Promise<void> {\n try {\n // プロンプトで設定収集\n let config: ProjectConfig;\n\n if (options.yes && projectName) {\n // --yes オプション: デフォルト値を使用\n const error = validateProjectName(projectName);\n if (error) {\n logger.error(error);\n process.exit(1);\n }\n\n config = {\n projectName,\n packageScope: \"@repo\",\n template: \"default\",\n authMethod: \"default\",\n tools: {\n direnv: true,\n dotenvx: true,\n volta: true,\n biome: true,\n husky: true,\n },\n setupEinjaCli: true,\n worktreeConfig: undefined,\n useCurrentDir: false,\n };\n\n logger.info(`プロジェクト名: ${config.projectName}`);\n logger.info(`テンプレート: ${config.template}`);\n logger.info(`認証方式: ${config.authMethod}`);\n } else {\n // 対話式プロンプト\n config = await promptProjectConfig(projectName);\n }\n\n // ターゲットパスの解決\n const targetPath = config.useCurrentDir\n ? process.cwd()\n : resolve(process.cwd(), config.projectName);\n\n // ディレクトリの確認\n if (config.useCurrentDir) {\n // カレントディレクトリに展開する場合、空かどうか確認\n if (!isDirectoryEmpty(targetPath)) {\n logger.error(\"現在のディレクトリにファイルが存在します\");\n logger.info(\"空のディレクトリで実行するか、サブディレクトリを作成してください\");\n process.exit(1);\n }\n } else {\n // サブディレクトリを作成する場合、存在確認\n if (checkProjectExists(targetPath)) {\n logger.error(`ディレクトリ '${config.projectName}' は既に存在します`);\n logger.info(\"別の名前を指定するか、既存ディレクトリを削除してください\");\n process.exit(1);\n }\n }\n\n // テンプレート展開\n const spinner = ora(\"プロジェクトを作成中...\").start();\n\n try {\n await generateTemplate(config, targetPath);\n spinner.succeed(\"プロジェクトを作成しました\");\n } catch (error) {\n spinner.fail(\"プロジェクトの作成に失敗しました\");\n throw error;\n }\n\n // 生成後セットアップ実行\n await execPostSetup(config, targetPath, {\n skipGit: options.skipGit,\n skipInstall: options.skipInstall,\n });\n } catch (error) {\n logger.error(\"エラーが発生しました:\");\n if (error instanceof Error) {\n logger.error(error.message);\n } else {\n logger.error(String(error));\n }\n process.exit(1);\n }\n}\n","import inquirer from \"inquirer\";\nimport type { ProjectConfig, WorktreeConfig, App } from \"../types/index.js\";\n\nexport type { ProjectConfig, WorktreeConfig, App };\n\n/**\n * プロジェクト作成用プロンプトを実行\n * @param defaultProjectName - デフォルトのプロジェクト名\n * @returns ProjectConfig - プロジェクト設定\n */\nexport async function promptProjectConfig(\n defaultProjectName?: string\n): Promise<ProjectConfig> {\n const answers = await inquirer.prompt([\n {\n type: \"input\",\n name: \"projectName\",\n message: \"プロジェクト名:\",\n default: defaultProjectName || \"my-project\",\n validate: (input: string): boolean | string => {\n // 英数字・ハイフン・アンダースコアのみ許可、先頭は英字、1〜50文字\n const regex = /^[a-zA-Z][a-zA-Z0-9_-]{0,49}$/;\n if (!regex.test(input)) {\n return \"プロジェクト名は英字で始まり、英数字・ハイフン・アンダースコアのみ使用できます(1〜50文字)\";\n }\n return true;\n },\n },\n {\n type: \"confirm\",\n name: \"useCurrentDir\",\n message: \"今いるディレクトリに直接作成しますか?(Noならサブディレクトリを作成)\",\n default: false,\n },\n {\n type: \"input\",\n name: \"packageScope\",\n message: \"パッケージスコープ:\",\n default: \"@repo\",\n validate: (input: string): boolean | string => {\n // @で始まり、英数字・ハイフン・アンダースコアのみ許可\n const regex = /^@[a-zA-Z][a-zA-Z0-9_-]{0,49}$/;\n if (!regex.test(input)) {\n return \"パッケージスコープは@で始まり、英数字・ハイフン・アンダースコアのみ使用できます\";\n }\n return true;\n },\n },\n {\n type: \"list\",\n name: \"authMethod\",\n message: \"認証機能:\",\n choices: [\n { name: \"NextAuth.js を使用\", value: \"default\" },\n { name: \"なし(認証ファイルを除外)\", value: \"none\" },\n ],\n default: \"default\",\n },\n {\n type: \"confirm\",\n name: \"setupEinjaCli\",\n message: \"@einja/dev-cli を自動セットアップしますか?\",\n default: true,\n },\n {\n type: \"confirm\",\n name: \"customizeWorktree\",\n message: \"Worktree設定をカスタマイズしますか?\",\n default: false,\n },\n ]);\n\n // ツールは全て有効(固定)\n const tools = {\n direnv: true,\n dotenvx: true,\n volta: true,\n biome: true,\n husky: true,\n };\n\n let worktreeConfig: WorktreeConfig | undefined;\n\n // Worktree設定カスタマイズ\n if (answers.customizeWorktree) {\n const worktreeAnswers = await inquirer.prompt([\n {\n type: \"input\",\n name: \"postgresPort\",\n message: \"PostgreSQLポート番号:\",\n default: \"25432\",\n validate: (input: string): boolean | string => {\n const port = Number.parseInt(input, 10);\n if (Number.isNaN(port) || port < 1024 || port > 65535) {\n return \"ポート番号は1024〜65535の範囲で指定してください\";\n }\n return true;\n },\n },\n {\n type: \"input\",\n name: \"containerName\",\n message: \"Dockerコンテナ名:\",\n default: `${answers.projectName}-postgres`,\n },\n {\n type: \"input\",\n name: \"appId\",\n message: \"アプリケーションID:\",\n default: \"web\",\n },\n {\n type: \"input\",\n name: \"portRangeStart\",\n message: \"アプリポート範囲開始:\",\n default: \"3000\",\n validate: (input: string): boolean | string => {\n const port = Number.parseInt(input, 10);\n if (Number.isNaN(port) || port < 1024 || port > 65535) {\n return \"ポート番号は1024〜65535の範囲で指定してください\";\n }\n return true;\n },\n },\n {\n type: \"input\",\n name: \"rangeSize\",\n message: \"ポート範囲サイズ:\",\n default: \"1000\",\n validate: (input: string): boolean | string => {\n const size = Number.parseInt(input, 10);\n if (Number.isNaN(size) || size < 1 || size > 10000) {\n return \"範囲サイズは1〜10000の範囲で指定してください\";\n }\n return true;\n },\n },\n ]);\n\n worktreeConfig = {\n postgres: {\n port: Number.parseInt(worktreeAnswers.postgresPort, 10),\n containerName: worktreeAnswers.containerName,\n },\n apps: [\n {\n id: worktreeAnswers.appId,\n portRangeStart: Number.parseInt(worktreeAnswers.portRangeStart, 10),\n rangeSize: Number.parseInt(worktreeAnswers.rangeSize, 10),\n },\n ],\n };\n }\n\n return {\n projectName: answers.projectName,\n packageScope: answers.packageScope,\n template: \"default\" as const,\n authMethod: answers.authMethod,\n tools,\n setupEinjaCli: answers.setupEinjaCli,\n worktreeConfig,\n useCurrentDir: answers.useCurrentDir,\n };\n}\n","import fsExtra from \"fs-extra\";\nconst { copySync, readFileSync, writeFileSync, existsSync, removeSync } = fsExtra;\nimport { glob } from \"glob\";\nimport { dirname, join, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ProjectConfig } from \"../prompts/project.js\";\nimport { ensureDir } from \"../utils/fs.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * TemplateVariables型\n * テンプレート変数(プレースホルダー置換用)\n */\nexport interface TemplateVariables {\n projectName: string;\n packageName: string;\n description: string;\n}\n\n/**\n * テンプレートディレクトリのパスを取得\n * @param templateName - テンプレート名\n * @returns テンプレートディレクトリパス\n */\nfunction getTemplatePath(templateName: string): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n\n // バンドル後(dist/cli.js)とソース実行(src/generators/template.ts)の両方に対応\n // dist/cli.js -> ../templates/ (1階層上)\n // src/generators/template.ts -> ../../templates/ (2階層上)\n const distPath = join(__dirname, \"../templates\", templateName);\n const srcPath = join(__dirname, \"../../templates\", templateName);\n\n if (existsSync(distPath)) {\n return distPath;\n }\n if (existsSync(srcPath)) {\n return srcPath;\n }\n\n // どちらも存在しない場合はdistPathを返す(エラーメッセージ用)\n return distPath;\n}\n\n/**\n * 認証方式に応じた除外パターンを取得\n * @param authMethod - 認証方式\n * @returns 除外パターン配列\n */\nfunction getAuthExcludePatterns(authMethod: string): string[] {\n if (authMethod === \"none\") {\n return [\n \"**/api/auth/**\",\n \"**/packages/auth/**\",\n \"**/signin/**\",\n \"**/signup/**\",\n ];\n }\n return [];\n}\n\n/**\n * ファイル内容のプレースホルダー変数を置換\n * @param content - ファイル内容\n * @param variables - 置換する変数\n * @returns 置換後の内容\n */\nfunction replacePlaceholders(\n content: string,\n variables: TemplateVariables\n): string {\n let result = content;\n\n // {{projectName}} の置換\n result = result.replaceAll(\"{{projectName}}\", variables.projectName);\n\n // {{packageName}}/ の置換(長いパターンを先に置換)\n result = result.replaceAll(\"{{packageName}}/\", `${variables.packageName}/`);\n\n // {{packageName}} の置換\n result = result.replaceAll(\"{{packageName}}\", variables.packageName);\n\n // {{description}} の置換\n result = result.replaceAll(\"{{description}}\", variables.description);\n\n // @repo/ の置換(パッケージスコープ)\n result = result.replaceAll(\"@repo/\", `${variables.packageName}/`);\n\n return result;\n}\n\n/**\n * ファイルの変数置換処理\n * @param filePath - ファイルパス\n * @param variables - 置換する変数\n */\nfunction processFileVariables(\n filePath: string,\n variables: TemplateVariables\n): void {\n // バイナリファイルは処理しない\n const binaryExtensions = [\".png\", \".jpg\", \".jpeg\", \".gif\", \".ico\", \".woff\", \".woff2\", \".ttf\", \".eot\"];\n if (binaryExtensions.some((ext) => filePath.endsWith(ext))) {\n return;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const replaced = replacePlaceholders(content, variables);\n\n if (content !== replaced) {\n writeFileSync(filePath, replaced, \"utf-8\");\n }\n } catch (error) {\n // 読み込みに失敗した場合はスキップ(バイナリファイル等)\n logger.warn(`変数置換をスキップ: ${filePath}`);\n }\n}\n\n/**\n * .templateファイルのリネーム処理\n * @param targetPath - ターゲットディレクトリパス\n */\nfunction renameTemplateFiles(targetPath: string): void {\n const templateFiles = glob.sync(\"**/*.template\", {\n cwd: targetPath,\n absolute: true,\n dot: true,\n });\n\n for (const file of templateFiles) {\n const newPath = file.replace(/\\.template$/, \"\");\n copySync(file, newPath);\n removeSync(file);\n }\n}\n\n/**\n * gitignoreファイルをリネーム処理(gitignore → .gitignore)\n * @param targetPath - ターゲットディレクトリパス\n */\nfunction renameSpecialFiles(targetPath: string): void {\n const gitignoreFiles = glob.sync(\"**/gitignore\", {\n cwd: targetPath,\n absolute: true,\n dot: true,\n });\n\n for (const file of gitignoreFiles) {\n const dir = dirname(file);\n const newPath = join(dir, \".gitignore\");\n\n if (existsSync(file)) {\n copySync(file, newPath);\n removeSync(file);\n }\n }\n}\n\n/**\n * 認証方式に応じたファイル除外処理\n * @param targetPath - ターゲットディレクトリパス\n * @param authMethod - 認証方式\n */\nfunction excludeAuthFiles(targetPath: string, authMethod: string): void {\n const excludePatterns = getAuthExcludePatterns(authMethod);\n\n if (excludePatterns.length === 0) {\n return;\n }\n\n logger.info(\"認証方式に応じたファイルを除外中...\");\n\n for (const pattern of excludePatterns) {\n const files = glob.sync(pattern, {\n cwd: targetPath,\n absolute: true,\n dot: true,\n });\n\n for (const file of files) {\n removeSync(file);\n }\n }\n}\n\n/**\n * テンプレートを展開\n * @param config - プロジェクト設定\n * @param targetPath - ターゲットディレクトリパス\n */\nexport async function generateTemplate(\n config: ProjectConfig,\n targetPath: string\n): Promise<void> {\n const templatePath = getTemplatePath(config.template);\n\n // テンプレートディレクトリの存在確認\n if (!existsSync(templatePath)) {\n throw new Error(`テンプレートが見つかりません: ${config.template}`);\n }\n\n logger.info(\"テンプレートをコピー中...\");\n\n // ターゲットディレクトリの作成\n await ensureDir(targetPath);\n\n // テンプレートファイルをコピー\n copySync(templatePath, targetPath, {\n filter: (src: string): boolean => {\n const relativePath = relative(templatePath, src);\n\n // 除外パターン(ディレクトリ名やファイル名として完全一致するもの)\n // 注意: .env.*ファイルはテンプレートに含め、pnpm env:updateで再設定する\n const excludePatterns = [\n \"node_modules\",\n \".git\",\n \".next\",\n \".turbo\",\n \"out\",\n \"dist\",\n \"logs\",\n \".env\", // フェイルセーフ(暗号化キーファイル)\n \".DS_Store\",\n \"Thumbs.db\",\n \"coverage\",\n ];\n\n // ファイル拡張子パターン(*.log など)\n const excludeExtensions = [\".log\"];\n\n // パスセグメントに分割(/ または \\ で分割)\n const pathSegments = relativePath.split(/[/\\\\]/);\n\n // パスセグメント単位で完全一致チェック\n // これにより \"out\" は \"out/\" ディレクトリにマッチするが\n // \"logout-button.tsx\" にはマッチしない\n const matchesExcludePattern = excludePatterns.some((pattern) =>\n pathSegments.includes(pattern)\n );\n\n // 拡張子チェック\n const matchesExtension = excludeExtensions.some((ext) =>\n relativePath.endsWith(ext)\n );\n\n return !matchesExcludePattern && !matchesExtension;\n },\n });\n\n // 認証方式に応じたファイル除外\n excludeAuthFiles(targetPath, config.authMethod);\n\n // .templateファイルのリネーム\n renameTemplateFiles(targetPath);\n\n // gitignore → .gitignore リネーム\n renameSpecialFiles(targetPath);\n\n // 変数置換\n logger.info(\"プレースホルダー変数を置換中...\");\n\n const variables: TemplateVariables = {\n projectName: config.projectName,\n packageName: config.packageScope,\n description: `${config.projectName} - Einja Management Template`,\n };\n\n const allFiles = glob.sync(\"**/*\", {\n cwd: targetPath,\n absolute: true,\n nodir: true,\n dot: true,\n });\n\n for (const file of allFiles) {\n processFileVariables(file, variables);\n }\n\n logger.success(\"テンプレート展開完了\");\n}\n","import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport type { ConflictStrategy } from \"../types/index.js\";\n\n/**\n * 競合戦略に基づいてファイルを書き込む\n */\nexport function writeWithStrategy(\n filePath: string,\n content: string,\n strategy: ConflictStrategy\n): boolean {\n const exists = existsSync(filePath);\n\n if (!exists) {\n ensureDir(dirname(filePath));\n writeFileSync(filePath, content, \"utf-8\");\n return true;\n }\n\n switch (strategy) {\n case \"overwrite\": {\n writeFileSync(filePath, content, \"utf-8\");\n return true;\n }\n\n case \"merge\": {\n const existingContent = readFileSync(filePath, \"utf-8\");\n const mergedContent = mergeContent(existingContent, content);\n writeFileSync(filePath, mergedContent, \"utf-8\");\n return true;\n }\n\n case \"skip\": {\n return false;\n }\n\n default: {\n const _exhaustiveCheck: never = strategy;\n throw new Error(`Unknown strategy: ${_exhaustiveCheck}`);\n }\n }\n}\n\n/**\n * 既存コンテンツと新規コンテンツをマージする\n */\nfunction mergeContent(existing: string, newContent: string): string {\n if (existing.includes(newContent)) {\n return existing;\n }\n return `${existing}\\n${newContent}`;\n}\n\n/**\n * ディレクトリが存在しない場合は作成する\n */\nexport function ensureDir(dirPath: string): void {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n}\n\n/**\n * .gitignoreに行を追加する\n */\nexport function appendToGitignore(targetDir: string, line: string): void {\n const gitignorePath = join(targetDir, \".gitignore\");\n\n if (!existsSync(gitignorePath)) {\n writeFileSync(gitignorePath, `${line}\\n`, \"utf-8\");\n return;\n }\n\n const content = readFileSync(gitignorePath, \"utf-8\");\n if (content.includes(line)) {\n return;\n }\n\n appendFileSync(gitignorePath, `\\n${line}\\n`, \"utf-8\");\n}\n\n/**\n * ファイルが存在するか確認する\n */\nexport function fileExists(filePath: string): boolean {\n return existsSync(filePath);\n}\n","import chalk from \"chalk\";\n\n/**\n * 情報メッセージを出力\n * @param message - メッセージ\n */\nexport function info(message: string): void {\n console.log(chalk.blue(\"ℹ\"), message);\n}\n\n/**\n * 成功メッセージを出力(緑色)\n * @param message - メッセージ\n */\nexport function success(message: string): void {\n console.log(chalk.green(\"✔\"), message);\n}\n\n/**\n * 警告メッセージを出力(黄色)\n * @param message - メッセージ\n */\nexport function warn(message: string): void {\n console.log(chalk.yellow(\"⚠\"), message);\n}\n\n/**\n * エラーメッセージを出力(赤色)\n * @param message - メッセージ\n */\nexport function error(message: string): void {\n console.error(chalk.red(\"✖\"), message);\n}\n","import { execa, execaSync } from \"execa\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport ora from \"ora\";\nimport type { ProjectConfig } from \"../types/index.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * PostSetupOptions型\n * 生成後セットアップのオプション\n */\nexport interface PostSetupOptions {\n skipGit?: boolean;\n skipInstall?: boolean;\n}\n\n/**\n * direnvコマンドが利用可能かチェック\n * @returns direnvコマンドが利用可能な場合true\n */\nfunction isDirenvAvailable(): boolean {\n try {\n execaSync(\"which\", [\"direnv\"]);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * direnv allowの確認プロンプトを表示し、実行する\n * @param targetPath - プロジェクトディレクトリ\n */\nasync function promptAndExecuteDirenvAllow(targetPath: string): Promise<void> {\n try {\n const { shouldAllow } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"shouldAllow\",\n message: \"direnv allow を実行しますか?(環境変数を有効化します)\",\n default: true,\n },\n ]);\n\n if (shouldAllow) {\n try {\n await execa(\"direnv\", [\"allow\"], { cwd: targetPath });\n logger.success(\"direnv allow を実行しました\");\n } catch (error) {\n logger.warn(\"direnv allow の実行に失敗しました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } else {\n logger.info(\"direnv allow をスキップしました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } catch (error) {\n logger.info(\"direnv allow をスキップしました\");\n }\n}\n\n/**\n * 完了メッセージを表示\n * @param config - プロジェクト設定\n */\nfunction printCompletionMessage(config: ProjectConfig): void {\n console.log();\n logger.success(\"プロジェクトの作成が完了しました!\");\n console.log();\n console.log(chalk.bold(\"次のステップ:\"));\n console.log();\n console.log(chalk.cyan(` cd ${config.projectName}`));\n console.log(chalk.cyan(\" pnpm env:update # 環境変数を設定\"));\n console.log(chalk.cyan(\" docker-compose up -d postgres\"));\n console.log(chalk.cyan(\" pnpm dev\"));\n console.log();\n console.log(\n chalk.yellow(\"⚠ セキュリティ: テンプレートの秘密鍵をそのまま使用しないでください\")\n );\n console.log(\n chalk.gray(\" pnpm env:rotate-secrets # 秘密鍵を自分のプロジェクト用に再生成\")\n );\n console.log();\n console.log(chalk.gray(\"開発サーバー: ターミナルに表示されるURLを確認\"));\n console.log();\n console.log(chalk.gray(\"詳細は README.md をご確認ください。\"));\n console.log();\n}\n\n/**\n * 生成後セットアップを実行\n * @param config - プロジェクト設定\n * @param targetPath - プロジェクトディレクトリ\n * @param options - セットアップオプション\n */\nexport async function execPostSetup(\n config: ProjectConfig,\n targetPath: string,\n options: PostSetupOptions\n): Promise<void> {\n const { skipGit, skipInstall } = options;\n\n // Git初期化\n if (!skipGit) {\n const gitSpinner = ora(\"Gitリポジトリを初期化中...\").start();\n try {\n await execa(\"git\", [\"init\"], { cwd: targetPath });\n await execa(\"git\", [\"add\", \".\"], { cwd: targetPath });\n await execa(\"git\", [\"commit\", \"-m\", \"Initial commit\"], { cwd: targetPath });\n gitSpinner.succeed(\"Gitリポジトリを初期化しました\");\n } catch (error) {\n gitSpinner.fail(\"Gitリポジトリの初期化に失敗しました\");\n logger.warn(\"後で手動で 'git init' を実行してください\");\n }\n }\n\n // 依存関係インストール\n if (!skipInstall) {\n const installSpinner = ora(\"依存関係をインストール中...\").start();\n try {\n await execa(\"pnpm\", [\"install\"], { cwd: targetPath });\n installSpinner.succeed(\"依存関係をインストールしました\");\n\n // Prismaクライアント生成\n const prismaSpinner = ora(\"Prismaクライアントを生成中...\").start();\n try {\n await execa(\"pnpm\", [\"db:generate\"], { cwd: targetPath });\n prismaSpinner.succeed(\"Prismaクライアントを生成しました\");\n } catch (error) {\n prismaSpinner.fail(\"Prismaクライアントの生成に失敗しました\");\n logger.warn(\"後で手動で 'pnpm db:generate' を実行してください\");\n }\n } catch (error) {\n installSpinner.fail(\"依存関係のインストールに失敗しました\");\n logger.warn(\"後で手動で 'pnpm install' を実行してください\");\n }\n }\n\n // direnv allow(direnvが有効で、コマンドが利用可能な場合)\n if (config.tools.direnv && isDirenvAvailable()) {\n await promptAndExecuteDirenvAllow(targetPath);\n }\n\n // @einja/dev-cli init\n if (config.setupEinjaCli) {\n const einjaSpinner = ora(\"@einja/dev-cli を初期化中...\").start();\n try {\n await execa(\"npx\", [\"@einja/dev-cli\", \"init\", \"--force\", \"--no-backup\"], { cwd: targetPath });\n einjaSpinner.succeed(\"@einja/dev-cli を初期化しました\");\n } catch (error) {\n einjaSpinner.fail(\"@einja/dev-cli の初期化に失敗しました\");\n logger.warn(\"後で手動で 'npx @einja/dev-cli init' を実行してください\");\n }\n }\n\n // 完了メッセージ表示\n printCompletionMessage(config);\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport ora from \"ora\";\nimport { promptSetupConfig } from \"../prompts/setup.js\";\nimport {\n setupDirenv,\n setupDotenvx,\n setupVolta,\n setupBiome,\n setupHusky,\n promptDirenvAllow,\n} from \"../generators/tools/index.js\";\nimport type { ToolSetupOptions } from \"../types/index.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * setupコマンド - 既存プロジェクトへのツール追加\n *\n * US-002: 既存プロジェクトへの環境ツール追加\n * AC-002-1: `npx create-einja-app --setup` で対話式プロンプトが表示される\n * AC-002-2: 既存の設定ファイルがある場合、マージ・上書き・スキップを選択できる\n * AC-002-3: 選択したツールのみがセットアップされる\n * AC-002-4: 既存ファイルを破壊せずにツールが追加される(マージモード時)\n */\nexport async function setupCommand(): Promise<void> {\n const targetDir = process.cwd();\n\n // 1. プロジェクトディレクトリ確認(package.json存在確認)\n const packageJsonPath = join(targetDir, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n logger.error(\"エラー: package.jsonが見つかりません\");\n logger.info(\"このコマンドは既存のプロジェクトディレクトリで実行してください\");\n process.exit(1);\n }\n\n logger.info(\"既存プロジェクトへのツール追加を開始します\");\n logger.info(\"\");\n\n // 2. プロンプトで設定収集\n const config = await promptSetupConfig();\n\n logger.info(\"\");\n logger.info(\"セットアップを開始します...\");\n logger.info(\"\");\n\n const options: ToolSetupOptions = {\n targetDir,\n conflictStrategy: config.conflictStrategy,\n };\n\n // 3. 選択されたツールのセットアップ\n let setupCount = 0;\n\n if (config.tools.direnv) {\n const spin = ora(\"direnv をセットアップしています...\").start();\n try {\n setupDirenv(options);\n spin.succeed(\"direnv セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"direnv セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.dotenvx) {\n const spin = ora(\"dotenvx をセットアップしています...\").start();\n try {\n setupDotenvx(options);\n spin.succeed(\"dotenvx セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"dotenvx セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.volta) {\n const spin = ora(\"Volta をセットアップしています...\").start();\n try {\n setupVolta(options);\n spin.succeed(\"Volta セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"Volta セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.biome) {\n const spin = ora(\"Biome をセットアップしています...\").start();\n try {\n setupBiome(options);\n spin.succeed(\"Biome セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"Biome セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.husky) {\n const spin = ora(\"Husky をセットアップしています...\").start();\n try {\n setupHusky(options);\n spin.succeed(\"Husky セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"Husky セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n logger.info(\"\");\n\n // 4. direnv allowの確認プロンプト(direnvがセットアップされた場合のみ)\n if (config.tools.direnv) {\n await promptDirenvAllow(targetDir);\n logger.info(\"\");\n }\n\n // 5. 完了メッセージ\n logger.success(`✅ セットアップが完了しました!(${setupCount}個のツール)`);\n logger.info(\"\");\n logger.info(\"次のステップ:\");\n\n if (config.tools.direnv) {\n logger.info(\" 1. .envrc を編集して環境変数を設定\");\n logger.info(\" 2. direnv allow を実行(まだの場合)\");\n }\n\n if (config.tools.dotenvx) {\n logger.info(\" - .env.example をコピーして .env を作成\");\n logger.info(\" - 必要に応じて pnpm env:encrypt で暗号化\");\n }\n\n if (config.tools.biome) {\n logger.info(\" - pnpm lint でコードをチェック\");\n logger.info(\" - pnpm format:fix でフォーマット\");\n }\n\n if (config.tools.husky) {\n logger.info(\" - pnpm install でHuskyフックをインストール\");\n }\n\n logger.info(\"\");\n logger.success(\"開発を開始できます!\");\n}\n","import inquirer from \"inquirer\";\n\n/**\n * SetupConfig型\n * 既存プロジェクトへのツール追加設定\n */\nexport interface SetupConfig {\n tools: {\n direnv: boolean;\n dotenvx: boolean;\n volta: boolean;\n biome: boolean;\n husky: boolean;\n };\n conflictStrategy: \"merge\" | \"overwrite\" | \"skip\";\n}\n\n/**\n * セットアップ用プロンプトを実行\n * @returns SetupConfig - セットアップ設定\n */\nexport async function promptSetupConfig(): Promise<SetupConfig> {\n const answers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"tools\",\n message: \"セットアップするツールを選択(複数選択可):\",\n choices: [\n {\n name: \"direnv(ディレクトリごとの環境変数管理)\",\n value: \"direnv\",\n checked: true,\n },\n {\n name: \"dotenvx(.env暗号化)\",\n value: \"dotenvx\",\n checked: true,\n },\n {\n name: \"Volta(Node.jsバージョン管理)\",\n value: \"volta\",\n checked: true,\n },\n {\n name: \"Biome(Linter / Formatter)\",\n value: \"biome\",\n checked: false,\n },\n {\n name: \"Husky + lint-staged(Git hooks)\",\n value: \"husky\",\n checked: false,\n },\n ],\n },\n {\n type: \"list\",\n name: \"conflictStrategy\",\n message: \"既存ファイルがある場合の動作:\",\n choices: [\n {\n name: \"マージ(既存設定を保持しつつ追加)\",\n value: \"merge\",\n },\n {\n name: \"上書き\",\n value: \"overwrite\",\n },\n {\n name: \"スキップ\",\n value: \"skip\",\n },\n ],\n default: \"merge\",\n },\n ]);\n\n // ツール選択を boolean フラグに変換\n const toolsArray = answers.tools as string[];\n const tools = {\n direnv: toolsArray.includes(\"direnv\"),\n dotenvx: toolsArray.includes(\"dotenvx\"),\n volta: toolsArray.includes(\"volta\"),\n biome: toolsArray.includes(\"biome\"),\n husky: toolsArray.includes(\"husky\"),\n };\n\n return {\n tools,\n conflictStrategy: answers.conflictStrategy,\n };\n}\n","import { join } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport inquirer from \"inquirer\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy, appendToGitignore } from \"../../utils/fs.js\";\nimport * as logger from \"../../utils/logger.js\";\n\nconst ENVRC_CONTENT = `# direnv configuration\n# Load .env if it exists\ndotenv_if_exists\n\n# Allow local overrides\ndotenv_if_exists .env.local\n`;\n\nconst ENVRC_EXAMPLE_CONTENT = `# Example direnv configuration\n# Copy this file to .envrc and run 'direnv allow'\n\n# Load environment variables from .env\ndotenv_if_exists\n\n# Load local overrides\ndotenv_if_exists .env.local\n`;\n\n/**\n * direnvのセットアップを実行する\n *\n * AC-003-1: .envrc ファイルが生成される\n * AC-003-2: .envrc.example ファイルが生成される\n * AC-003-3: .gitignore に .envrc が追加される\n */\nexport function setupDirenv(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n const envrcPath = join(targetDir, \".envrc\");\n const envrcExamplePath = join(targetDir, \".envrc.example\");\n\n writeWithStrategy(envrcPath, ENVRC_CONTENT, conflictStrategy);\n\n writeWithStrategy(envrcExamplePath, ENVRC_EXAMPLE_CONTENT, conflictStrategy);\n\n appendToGitignore(targetDir, \".envrc\");\n}\n\n/**\n * direnv allowの確認プロンプトを表示し、実行する\n *\n * AC-003-4: 確認後 `direnv allow` が実行される\n *\n * @param targetDir - ターゲットディレクトリ\n */\nexport async function promptDirenvAllow(targetDir: string): Promise<void> {\n try {\n const { shouldAllow } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"shouldAllow\",\n message: \"direnv allow を実行しますか?(環境変数を有効化します)\",\n default: true,\n },\n ]);\n\n if (shouldAllow) {\n try {\n execSync(\"direnv allow\", { cwd: targetDir, stdio: \"inherit\" });\n logger.success(\"direnv allow を実行しました\");\n } catch (error) {\n logger.warn(\"direnv allow の実行に失敗しました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } else {\n logger.info(\"direnv allow をスキップしました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } catch (error) {\n // プロンプトがキャンセルされた場合など\n logger.info(\"direnv allow をスキップしました\");\n }\n}\n","import { join } from \"node:path\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy } from \"../../utils/fs.js\";\nimport { addDependencies, addScripts } from \"../../utils/package-json.js\";\n\nconst ENV_EXAMPLE_CONTENT = `# Environment variables template\n# Copy this file to .env and fill in the values\n\n# Database\nDATABASE_URL=\"postgresql://user:password@localhost:25432/dbname\"\n\n# NextAuth\nNEXTAUTH_URL=\"http://localhost:3000\"\nNEXTAUTH_SECRET=\"your-secret-here\"\n\n# OAuth (if using)\n# GOOGLE_CLIENT_ID=\"\"\n# GOOGLE_CLIENT_SECRET=\"\"\n# GITHUB_CLIENT_ID=\"\"\n# GITHUB_CLIENT_SECRET=\"\"\n`;\n\n/**\n * dotenvxのセットアップを実行する\n *\n * AC-004-1: package.jsonに依存関係が追加される\n * AC-004-2: npm scriptsにdotenvxコマンドが追加される\n * AC-004-3: .env.example が生成される\n */\nexport function setupDotenvx(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n addDependencies(targetDir, {\n \"@dotenvx/dotenvx\": \"^1.29.0\",\n });\n\n addScripts(targetDir, {\n \"env:encrypt\": \"dotenvx encrypt\",\n \"env:decrypt\": \"dotenvx decrypt\",\n });\n\n const envExamplePath = join(targetDir, \".env.example\");\n writeWithStrategy(envExamplePath, ENV_EXAMPLE_CONTENT, conflictStrategy);\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileExists } from \"./fs.js\";\n\ntype PackageJson = {\n name?: string;\n version?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n volta?: {\n node?: string;\n pnpm?: string;\n };\n \"lint-staged\"?: Record<string, string | string[]>;\n [key: string]: unknown;\n};\n\n/**\n * package.jsonを読み込む\n */\nexport function readPackageJson(targetDir: string): PackageJson {\n const packageJsonPath = join(targetDir, \"package.json\");\n\n if (!fileExists(packageJsonPath)) {\n return {};\n }\n\n const content = readFileSync(packageJsonPath, \"utf-8\");\n return JSON.parse(content) as PackageJson;\n}\n\n/**\n * package.jsonに書き込む\n */\nexport function writePackageJson(targetDir: string, data: PackageJson): void {\n const packageJsonPath = join(targetDir, \"package.json\");\n const content = JSON.stringify(data, null, 2);\n writeFileSync(packageJsonPath, `${content}\\n`, \"utf-8\");\n}\n\n/**\n * package.jsonにスクリプトを追加する\n */\nexport function addScripts(\n targetDir: string,\n scripts: Record<string, string>\n): void {\n const pkg = readPackageJson(targetDir);\n pkg.scripts = { ...pkg.scripts, ...scripts };\n writePackageJson(targetDir, pkg);\n}\n\n/**\n * package.jsonに依存関係を追加する\n */\nexport function addDependencies(\n targetDir: string,\n dependencies: Record<string, string>,\n dev = false\n): void {\n const pkg = readPackageJson(targetDir);\n\n if (dev) {\n pkg.devDependencies = { ...pkg.devDependencies, ...dependencies };\n } else {\n pkg.dependencies = { ...pkg.dependencies, ...dependencies };\n }\n\n writePackageJson(targetDir, pkg);\n}\n\n/**\n * package.jsonにVoltaフィールドを追加する\n */\nexport function addVoltaField(\n targetDir: string,\n nodeVersion: string,\n pnpmVersion: string\n): void {\n const pkg = readPackageJson(targetDir);\n pkg.volta = {\n node: nodeVersion,\n pnpm: pnpmVersion,\n };\n writePackageJson(targetDir, pkg);\n}\n\n/**\n * package.jsonにlint-staged設定を追加する\n */\nexport function addLintStaged(\n targetDir: string,\n config: Record<string, string | string[]>\n): void {\n const pkg = readPackageJson(targetDir);\n pkg[\"lint-staged\"] = { ...pkg[\"lint-staged\"], ...config };\n writePackageJson(targetDir, pkg);\n}\n","import { join } from \"node:path\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy } from \"../../utils/fs.js\";\nimport { addVoltaField } from \"../../utils/package-json.js\";\n\nconst NODE_VERSION = \"22.16.0\";\nconst PNPM_VERSION = \"9.15.0\";\n\nconst NODE_VERSION_CONTENT = `${NODE_VERSION}\n`;\n\n/**\n * Voltaのセットアップを実行する\n *\n * AC-005-1: package.jsonにvoltaフィールドが追加される\n * AC-005-2: .node-version ファイルが生成される\n */\nexport function setupVolta(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n addVoltaField(targetDir, NODE_VERSION, PNPM_VERSION);\n\n const nodeVersionPath = join(targetDir, \".node-version\");\n writeWithStrategy(nodeVersionPath, NODE_VERSION_CONTENT, conflictStrategy);\n}\n","import { join } from \"node:path\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy, ensureDir } from \"../../utils/fs.js\";\nimport { addDependencies, addScripts } from \"../../utils/package-json.js\";\n\nconst BIOME_CONFIG = `{\n \"$schema\": \"https://biomejs.dev/schemas/1.9.4/schema.json\",\n \"vcs\": {\n \"enabled\": true,\n \"clientKind\": \"git\",\n \"useIgnoreFile\": true\n },\n \"files\": {\n \"ignoreUnknown\": false,\n \"ignore\": [\"node_modules\", \"dist\", \".next\", \"out\", \"build\", \"coverage\"]\n },\n \"formatter\": {\n \"enabled\": true,\n \"indentStyle\": \"space\",\n \"indentWidth\": 2,\n \"lineEnding\": \"lf\",\n \"lineWidth\": 100\n },\n \"organizeImports\": {\n \"enabled\": true\n },\n \"linter\": {\n \"enabled\": true,\n \"rules\": {\n \"recommended\": true\n }\n },\n \"javascript\": {\n \"formatter\": {\n \"quoteStyle\": \"double\",\n \"trailingCommas\": \"es5\",\n \"semicolons\": \"always\",\n \"arrowParentheses\": \"always\"\n }\n }\n}\n`;\n\nconst VSCODE_SETTINGS = `{\n \"editor.defaultFormatter\": \"biomejs.biome\",\n \"editor.formatOnSave\": true,\n \"editor.codeActionsOnSave\": {\n \"quickfix.biome\": \"explicit\",\n \"source.organizeImports.biome\": \"explicit\"\n },\n \"[javascript]\": {\n \"editor.defaultFormatter\": \"biomejs.biome\"\n },\n \"[typescript]\": {\n \"editor.defaultFormatter\": \"biomejs.biome\"\n },\n \"[json]\": {\n \"editor.defaultFormatter\": \"biomejs.biome\"\n }\n}\n`;\n\n/**\n * Biomeのセットアップを実行する(--setupモードのみ)\n *\n * AC-006-1: biome.json が生成される\n * AC-006-2: package.jsonにlint/formatスクリプトが追加される\n * AC-006-3: VSCode設定が追加される\n */\nexport function setupBiome(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n const biomeConfigPath = join(targetDir, \"biome.json\");\n writeWithStrategy(biomeConfigPath, BIOME_CONFIG, conflictStrategy);\n\n addDependencies(\n targetDir,\n {\n \"@biomejs/biome\": \"^1.9.4\",\n },\n true\n );\n\n addScripts(targetDir, {\n lint: \"biome lint .\",\n \"lint:fix\": \"biome lint --write .\",\n format: \"biome format .\",\n \"format:fix\": \"biome format --write .\",\n });\n\n const vscodeDir = join(targetDir, \".vscode\");\n ensureDir(vscodeDir);\n\n const vscodeSettingsPath = join(vscodeDir, \"settings.json\");\n writeWithStrategy(vscodeSettingsPath, VSCODE_SETTINGS, conflictStrategy);\n}\n","import { join } from \"node:path\";\nimport { writeFileSync } from \"node:fs\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { ensureDir } from \"../../utils/fs.js\";\nimport { addDependencies, addScripts, addLintStaged } from \"../../utils/package-json.js\";\n\nconst PRE_COMMIT_HOOK = `#!/usr/bin/env sh\n. \"$(dirname -- \"$0\")/_/husky.sh\"\n\npnpm lint-staged\n`;\n\n/**\n * Husky + lint-stagedのセットアップを実行する(--setupモードのみ)\n *\n * AC-007-1: .husky/ ディレクトリが生成される\n * AC-007-2: pre-commitフックが設定される\n * AC-007-3: lint-staged設定が追加される\n */\nexport function setupHusky(options: ToolSetupOptions): void {\n const { targetDir } = options;\n\n addDependencies(\n targetDir,\n {\n husky: \"^9.1.7\",\n \"lint-staged\": \"^15.2.11\",\n },\n true\n );\n\n addScripts(targetDir, {\n prepare: \"husky\",\n });\n\n addLintStaged(targetDir, {\n \"*.{js,jsx,ts,tsx}\": [\"biome format --write\", \"biome lint --write\"],\n \"*.{json,md,yml,yaml}\": [\"biome format --write\"],\n });\n\n const huskyDir = join(targetDir, \".husky\");\n ensureDir(huskyDir);\n\n const preCommitPath = join(huskyDir, \"pre-commit\");\n writeFileSync(preCommitPath, PRE_COMMIT_HOOK, { mode: 0o755 });\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport ora from \"ora\";\nimport {\n promptAddConfig,\n getDefaultAddConfig,\n} from \"../prompts/add.js\";\nimport type { AddConfig, AddOptions, SyncMetadata } from \"../types/index.js\";\nimport { addPackages } from \"../generators/partials/packages.js\";\nimport { addApps } from \"../generators/partials/apps.js\";\nimport { addConfigFiles } from \"../generators/partials/config.js\";\nimport {\n loadSyncMetadata,\n saveSyncMetadata,\n} from \"../utils/merger.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * AddCommandOptions型\n * addコマンドのオプション\n */\nexport interface AddCommandOptions {\n skipPrompts: boolean;\n dryRun: boolean;\n}\n\n/**\n * テンプレートディレクトリのパスを取得\n * @param templateName - テンプレート名\n * @returns テンプレートディレクトリパス\n */\nfunction getTemplatePath(templateName: string): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n\n // バンドル後(dist/cli.js)とソース実行(src/commands/add.ts)の両方に対応\n // dist/cli.js -> ../templates/ (1階層上)\n // src/commands/add.ts -> ../../templates/ (2階層上)\n const distPath = join(__dirname, \"../templates\", templateName);\n const srcPath = join(__dirname, \"../../templates\", templateName);\n\n if (existsSync(distPath)) {\n return distPath;\n }\n if (existsSync(srcPath)) {\n return srcPath;\n }\n\n // どちらも存在しない場合はdistPathを返す(エラーメッセージ用)\n return distPath;\n}\n\n/**\n * テンプレートから.einja-sync.jsonを読み込む\n * @param templateDir - テンプレートディレクトリパス\n * @returns SyncMetadata または null(ファイルが存在しない場合)\n */\nasync function loadTemplateSyncMetadata(\n templateDir: string\n): Promise<SyncMetadata | null> {\n const syncFilePath = join(templateDir, \".einja-sync.json\");\n try {\n const content = await readFile(syncFilePath, \"utf-8\");\n return JSON.parse(content) as SyncMetadata;\n } catch {\n return null;\n }\n}\n\n/**\n * テンプレートと既存のSyncMetadataをマージ\n * @param template - テンプレートのSyncMetadata\n * @param existing - 既存のSyncMetadata\n * @returns マージされたSyncMetadata\n */\nfunction mergeSyncMetadata(\n template: SyncMetadata | null,\n existing: SyncMetadata | null\n): SyncMetadata {\n const now = new Date().toISOString();\n\n // テンプレートのjsonPathsを優先的に使用\n const jsonPaths =\n template?.jsonPaths ?? existing?.jsonPaths ?? { managed: {}, seed: {} };\n\n return {\n version: template?.version ?? existing?.version ?? \"1.0.0\",\n lastSync: now,\n templateVersion: template?.templateVersion ?? \"1.0.0\",\n files: { ...(existing?.files ?? {}), ...(template?.files ?? {}) },\n jsonPaths,\n };\n}\n\n/**\n * addコマンドの実装\n * @param options - コマンドオプション\n */\nexport async function addCommand(options: AddCommandOptions): Promise<void> {\n try {\n // Given: カレントディレクトリをターゲットとする\n const targetDir = process.cwd();\n\n // Given: プロンプトまたはデフォルト設定を取得\n let config: AddConfig;\n\n if (options.skipPrompts) {\n // When: skipPromptsが有効な場合、デフォルト設定を使用\n config = getDefaultAddConfig();\n logger.info(\"デフォルト設定を使用します(すべてのコンポーネントを選択)\");\n } else {\n // When: 対話式プロンプトを実行\n config = await promptAddConfig(options.dryRun);\n }\n\n // Given: dry-runモードかどうかを設定に反映\n config.dryRun = options.dryRun;\n\n // When: dry-runモードの場合、プレビューを表示\n if (config.dryRun) {\n logger.warn(\"dry-runモード: 実際のファイル操作は行いません\");\n logger.info(\"\\n--- 追加予定のコンポーネント ---\");\n\n if (config.components.packages) {\n logger.info(\n `- packages/: ${config.packageComponents.join(\", \")}`\n );\n }\n\n if (config.components.apps) {\n logger.info(`- apps/: ${config.appComponents.join(\", \")}`);\n }\n\n if (config.components.config) {\n logger.info(\"- 直下設定ファイル: turbo.json, pnpm-workspace.yaml 等\");\n }\n\n logger.info(\"---\\n\");\n }\n\n // Given: テンプレートディレクトリのパスを取得\n const templateDir = getTemplatePath(\"default\");\n\n // Given: テンプレートディレクトリの存在確認\n if (!existsSync(templateDir)) {\n throw new Error(\"テンプレートが見つかりません: default\");\n }\n\n // Given: テンプレートのSyncMetadataを読み込む\n const templateMetadata = await loadTemplateSyncMetadata(templateDir);\n\n // Given: 既存のSyncMetadataを読み込む\n const existingMetadata = await loadSyncMetadata(targetDir);\n\n // When: テンプレートと既存のメタデータをマージ\n const syncMetadata = mergeSyncMetadata(templateMetadata, existingMetadata);\n\n // Given: AddOptionsを構築\n const addOptions: AddOptions = {\n targetDir,\n templateDir,\n config,\n };\n\n let totalAdded = 0;\n let totalMerged = 0;\n let totalSkipped = 0;\n\n // When: packages を追加\n if (config.components.packages && config.packageComponents.length > 0) {\n const spinner = ora(\"パッケージを追加中...\").start();\n\n try {\n const result = await addPackages(\n addOptions,\n config.packageComponents,\n syncMetadata\n );\n\n totalAdded += result.added.length;\n totalMerged += result.merged.length;\n totalSkipped += result.skipped.length;\n\n spinner.succeed(\n `パッケージを追加しました(追加: ${result.added.length}, マージ: ${result.merged.length}, スキップ: ${result.skipped.length})`\n );\n } catch (error) {\n spinner.fail(\"パッケージの追加に失敗しました\");\n throw error;\n }\n }\n\n // When: apps を追加\n if (config.components.apps && config.appComponents.length > 0) {\n const spinner = ora(\"アプリを追加中...\").start();\n\n try {\n const result = await addApps(\n addOptions,\n config.appComponents,\n syncMetadata\n );\n\n totalAdded += result.added.length;\n totalMerged += result.merged.length;\n totalSkipped += result.skipped.length;\n\n spinner.succeed(\n `アプリを追加しました(追加: ${result.added.length}, マージ: ${result.merged.length}, スキップ: ${result.skipped.length})`\n );\n } catch (error) {\n spinner.fail(\"アプリの追加に失敗しました\");\n throw error;\n }\n }\n\n // When: config を追加\n if (config.components.config) {\n const spinner = ora(\"設定ファイルを追加中...\").start();\n\n try {\n const result = await addConfigFiles(addOptions, syncMetadata);\n\n totalAdded += result.added.length;\n totalMerged += result.merged.length;\n totalSkipped += result.skipped.length;\n\n spinner.succeed(\n `設定ファイルを追加しました(追加: ${result.added.length}, マージ: ${result.merged.length}, スキップ: ${result.skipped.length})`\n );\n } catch (error) {\n spinner.fail(\"設定ファイルの追加に失敗しました\");\n throw error;\n }\n }\n\n // When: SyncMetadataを更新して保存\n if (!config.dryRun) {\n syncMetadata.lastSync = new Date().toISOString();\n await saveSyncMetadata(targetDir, syncMetadata);\n }\n\n // Then: 結果サマリーを表示\n logger.success(\"\\n✓ 追加完了!\\n\");\n\n if (config.dryRun) {\n logger.info(\"(dry-runモードのため、実際の変更は行われていません)\\n\");\n }\n\n logger.info(`追加されたファイル: ${totalAdded}個`);\n logger.info(`マージされたファイル: ${totalMerged}個`);\n logger.info(`スキップされたファイル: ${totalSkipped}個\\n`);\n\n // When: @einja/cliがインストールされていない場合、案内メッセージを表示\n const packageJsonPath = join(targetDir, \"package.json\");\n if (existsSync(packageJsonPath)) {\n const packageJson = await import(packageJsonPath, {\n assert: { type: \"json\" },\n });\n\n const hasEinjaCli =\n packageJson.default?.devDependencies?.[\"@einja/dev-cli\"] ||\n packageJson.default?.dependencies?.[\"@einja/dev-cli\"];\n\n if (!hasEinjaCli) {\n logger.info(\"次のステップ:\");\n logger.info(\"1. pnpm install\");\n logger.info(\"2. pnpm dev:setup\");\n logger.info(\"\\n推奨:\");\n logger.info(\" einja開発支援CLI (@einja/dev-cli) のインストール:\");\n logger.info(\" pnpm add -D @einja/dev-cli\\n\");\n } else {\n logger.info(\"次のステップ:\");\n logger.info(\"1. pnpm install\");\n logger.info(\"2. pnpm dev:setup\\n\");\n }\n } else {\n logger.info(\"次のステップ:\");\n logger.info(\"1. pnpm install\");\n logger.info(\"2. pnpm dev:setup\\n\");\n }\n } catch (error) {\n logger.error(\"エラーが発生しました:\");\n if (error instanceof Error) {\n logger.error(error.message);\n } else {\n logger.error(String(error));\n }\n process.exit(1);\n }\n}\n","import inquirer from \"inquirer\";\nimport type {\n AddConfig,\n PackageComponent,\n AppComponent,\n} from \"../types/index.js\";\n\n/**\n * デフォルトの追加設定を取得\n * skipPrompts=true 時に使用\n */\nexport function getDefaultAddConfig(): AddConfig {\n return {\n components: {\n packages: true,\n apps: true,\n config: true,\n },\n packageComponents: [\"front-core\", \"server-core\", \"config\", \"ui\"],\n appComponents: [\"web\"],\n dryRun: false,\n };\n}\n\n/**\n * 追加用プロンプトを実行\n * @param dryRun - dry-runモードかどうか\n * @returns AddConfig - 追加設定\n */\nexport async function promptAddConfig(dryRun: boolean): Promise<AddConfig> {\n // ステージ1: コンポーネント種別選択\n const componentAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"components\",\n message: \"追加するコンポーネントを選択(Spaceで選択、Enterで確定):\",\n choices: [\n {\n name: \"packages/ - 共通パッケージ(front-core, server-core, config, ui)\",\n value: \"packages\",\n checked: true,\n },\n {\n name: \"apps/ - アプリテンプレート\",\n value: \"apps\",\n checked: true,\n },\n {\n name: \"直下設定ファイル - turbo.json, pnpm-workspace.yaml 等\",\n value: \"config\",\n checked: true,\n },\n ],\n },\n ]);\n\n const selectedComponents = componentAnswers.components as string[];\n const hasPackages = selectedComponents.includes(\"packages\");\n const hasApps = selectedComponents.includes(\"apps\");\n const hasConfig = selectedComponents.includes(\"config\");\n\n // ステージ2: packages詳細選択\n let packageComponents: PackageComponent[] = [];\n if (hasPackages) {\n const packageAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"packages\",\n message: \"追加するパッケージを選択:\",\n choices: [\n {\n name: \"front-core - フロントエンド共通層(認証設定、hooks、utils)\",\n value: \"front-core\",\n checked: true,\n },\n {\n name: \"server-core - バックエンド共通層(Prisma、ドメインロジック)\",\n value: \"server-core\",\n checked: true,\n },\n {\n name: \"config - 共通設定(Biome, TypeScript, Panda CSS)\",\n value: \"config\",\n checked: true,\n },\n {\n name: \"ui - 共通UIコンポーネント(shadcn/ui)\",\n value: \"ui\",\n checked: true,\n },\n ],\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのパッケージを選択してください\";\n }\n return true;\n },\n },\n ]);\n packageComponents = packageAnswers.packages as PackageComponent[];\n }\n\n // ステージ3: apps詳細選択\n let appComponents: AppComponent[] = [];\n if (hasApps) {\n const appAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"apps\",\n message: \"追加するアプリを選択:\",\n choices: [\n {\n name: \"web - メイン管理画面アプリ(Next.js + App Router)\",\n value: \"web\",\n checked: true,\n },\n ],\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのアプリを選択してください\";\n }\n return true;\n },\n },\n ]);\n appComponents = appAnswers.apps as AppComponent[];\n }\n\n return {\n components: {\n packages: hasPackages,\n apps: hasApps,\n config: hasConfig,\n },\n packageComponents,\n appComponents,\n dryRun,\n };\n}\n","import { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n AddOptions,\n PackageComponent,\n SyncMetadata,\n} from \"../../types/index.js\";\nimport { mergeAndWriteFile } from \"../../utils/merger.js\";\nimport * as logger from \"../../utils/logger.js\";\n\n/**\n * packages/ ディレクトリにコンポーネントを追加\n */\nexport async function addPackages(\n options: AddOptions,\n components: PackageComponent[],\n syncMetadata: SyncMetadata\n): Promise<{ added: string[]; skipped: string[]; merged: string[] }> {\n const added: string[] = [];\n const skipped: string[] = [];\n const merged: string[] = [];\n\n const { targetDir, templateDir, config } = options;\n\n for (const component of components) {\n const componentName =\n component === \"front-core\"\n ? \"front-core\"\n : component === \"server-core\"\n ? \"server-core\"\n : component === \"config\"\n ? \"config\"\n : \"ui\";\n\n const srcDir = join(templateDir, \"packages\", componentName);\n const destDir = join(targetDir, \"packages\", componentName);\n\n logger.info(`Adding package component: ${componentName}`);\n\n await copyDirectory(\n srcDir,\n destDir,\n { added, skipped, merged },\n config.dryRun,\n syncMetadata\n );\n }\n\n return { added, skipped, merged };\n}\n\n/**\n * ディレクトリを再帰的にコピー\n */\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n result: { added: string[]; skipped: string[]; merged: string[] },\n dryRun: boolean,\n syncMetadata: SyncMetadata\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath, result, dryRun, syncMetadata);\n } else {\n if (!dryRun) {\n const mergeResult = await mergeAndWriteFile(\n srcPath,\n destPath,\n syncMetadata\n );\n\n if (mergeResult.action === \"created\") {\n result.added.push(destPath);\n } else if (mergeResult.action === \"skipped\") {\n result.skipped.push(destPath);\n } else if (mergeResult.action === \"merged\") {\n result.merged.push(destPath);\n }\n } else {\n // dry-runモードではスキップ\n result.skipped.push(destPath);\n }\n }\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport type { SyncMetadata, JsonPathsConfig } from \"../types/index.js\";\nimport { ensureDir } from \"./fs.js\";\nimport { mergePackageJsonDependencies } from \"./package-json-merger.js\";\nimport * as logger from \"./logger.js\";\n\n/**\n * マーカーベースのテキストマージを行う\n *\n * @param templateContent - テンプレートファイルの内容\n * @param existingContent - 既存ファイルの内容(存在しない場合はnull)\n * @returns マージ後の内容\n */\nexport function mergeTextWithMarkers(\n templateContent: string,\n existingContent: string | null\n): string {\n // Given: 既存ファイルが存在しない場合\n if (existingContent === null) {\n // When: テンプレートをそのまま使用\n return templateContent;\n }\n\n // Given: 既存ファイルとテンプレートの両方が存在する場合\n const templateSections = parseMarkers(templateContent);\n const localSections = parseMarkers(existingContent);\n\n // マーカーがなければ既存優先\n const hasMarkers = templateSections.some(\n (s) => s.type === \"managed\" || s.type === \"seed\"\n );\n if (!hasMarkers) {\n return existingContent;\n }\n\n // When: ID付きmanagedセクションとseedセクションをMapで管理\n const templateManagedById = new Map<string, MarkerSection>();\n const templateSeedById = new Map<string, MarkerSection>();\n const processedTemplateIds = new Set<string>();\n\n for (const section of templateSections) {\n if (section.type === \"managed\" && section.id) {\n templateManagedById.set(section.id, section);\n } else if (section.type === \"seed\" && section.id) {\n templateSeedById.set(section.id, section);\n }\n }\n\n // When: ローカルセクションを処理(ローカル側の順序を基準にする)\n const result: string[] = [];\n\n for (const localSection of localSections) {\n if (localSection.type === \"managed\") {\n const match = localSection.id ? templateManagedById.get(localSection.id) : undefined;\n if (localSection.id && match) {\n // IDマッチ → テンプレートで上書き\n processedTemplateIds.add(localSection.id);\n result.push(match.content);\n } else if (!localSection.id) {\n // IDなし → ローカル内容を保持(安全策)\n result.push(localSection.content);\n }\n // ID付きでテンプレートにマッチなし → 削除(resultに追加しない)\n } else if (localSection.type === \"seed\") {\n // seed: ローカル優先\n if (localSection.id) {\n processedTemplateIds.add(localSection.id);\n }\n result.push(localSection.content);\n } else {\n // unmanaged: ローカル優先\n result.push(localSection.content);\n }\n }\n\n // When: テンプレートにのみ存在するID付きmanagedセクションを末尾に追加\n for (const [id, section] of templateManagedById) {\n if (!processedTemplateIds.has(id)) {\n // テンプレートにのみ存在するID付きmanagedセクションを追加\n result.push(section.content);\n }\n }\n\n // When: テンプレートにのみ存在するID付きseedセクションを末尾に追加\n for (const [id, section] of templateSeedById) {\n if (!processedTemplateIds.has(id)) {\n // テンプレートにのみ存在するID付きseedセクションを追加\n result.push(section.content);\n }\n }\n\n // Then: ファイル先頭の空セクションのみ除去(セクション間の空行は保持)\n const firstElement = result[0];\n if (result.length > 0 && firstElement !== undefined && firstElement.length === 0) {\n result.shift();\n }\n return result.join(\"\\n\");\n}\n\n/**\n * JSONのディープマージを行う\n *\n * @param templateJson - テンプレートのJSON\n * @param existingJson - 既存のJSON(存在しない場合はnull)\n * @param jsonPaths - managed/seedパスの設定\n * @param filePath - ファイルパス(例: \"package.json\")\n * @returns マージ後のJSON\n */\nexport function mergeJson(\n templateJson: Record<string, unknown>,\n existingJson: Record<string, unknown> | null,\n jsonPaths: JsonPathsConfig,\n filePath = \"package.json\"\n): Record<string, unknown> {\n // Given: 既存JSONが存在しない場合\n if (existingJson === null) {\n // When: テンプレートをディープコピーして使用\n return JSON.parse(JSON.stringify(templateJson));\n }\n\n // When: ディープマージを実行\n return deepMergeWithPaths(\n templateJson,\n existingJson,\n jsonPaths,\n filePath,\n \"\"\n );\n}\n\n/**\n * パスを考慮したディープマージを行う\n *\n * @param template - テンプレートオブジェクト\n * @param existing - 既存オブジェクト\n * @param jsonPaths - managed/seedパスの設定\n * @param filePath - ファイルパス\n * @param currentPath - 現在のキーパス(例: \"scripts.dev\")\n * @returns マージ後のオブジェクト\n */\nfunction deepMergeWithPaths(\n template: Record<string, unknown>,\n existing: Record<string, unknown>,\n jsonPaths: JsonPathsConfig,\n filePath: string,\n currentPath: string\n): Record<string, unknown> {\n // 既存オブジェクトをディープコピー(参照を共有しないように)\n const result = JSON.parse(JSON.stringify(existing)) as Record<string, unknown>;\n\n for (const [key, templateValue] of Object.entries(template)) {\n const keyPath = currentPath ? `${currentPath}.${key}` : key;\n const existingValue = existing[key];\n\n // Given: このパスがmanagedに含まれるか確認\n if (isPathManaged(filePath, keyPath, jsonPaths)) {\n // Then: managedパスはテンプレート値でディープコピーして上書き\n result[key] = deepClone(templateValue);\n }\n // Given: このパスがseedに含まれるか確認\n else if (isPathSeed(filePath, keyPath, jsonPaths)) {\n // Given: seedパスでオブジェクトの場合、子キーもディープマージ\n if (\n typeof templateValue === \"object\" &&\n templateValue !== null &&\n !Array.isArray(templateValue) &&\n typeof existingValue === \"object\" &&\n existingValue !== null &&\n !Array.isArray(existingValue)\n ) {\n // Then: seedパス内でもディープマージ(既存にないキーのみ追加)\n result[key] = deepMergeWithPaths(\n templateValue as Record<string, unknown>,\n existingValue as Record<string, unknown>,\n jsonPaths,\n filePath,\n keyPath\n );\n } else if (!(key in existing)) {\n // Then: seedパスはローカル優先(キーが存在しない場合のみディープコピーして追加)\n result[key] = deepClone(templateValue);\n }\n // 既存値がある場合は何もしない(既存値を保持)\n }\n // Given: 両方がオブジェクトの場合\n else if (\n typeof templateValue === \"object\" &&\n templateValue !== null &&\n !Array.isArray(templateValue) &&\n typeof existingValue === \"object\" &&\n existingValue !== null &&\n !Array.isArray(existingValue)\n ) {\n // Then: 再帰的にディープマージ\n result[key] = deepMergeWithPaths(\n templateValue as Record<string, unknown>,\n existingValue as Record<string, unknown>,\n jsonPaths,\n filePath,\n keyPath\n );\n }\n // Given: それ以外のパス(テンプレートにのみ存在する場合)\n else if (!(key in existing)) {\n // Then: テンプレートの値をディープコピーして追加\n result[key] = deepClone(templateValue);\n }\n // 既存値がある場合は何もしない(既存値を保持)\n }\n\n return result;\n}\n\n/**\n * 値をディープコピーする(undefinedも正しく扱う)\n *\n * @param value - コピーする値\n * @returns ディープコピーされた値\n */\nfunction deepClone(value: unknown): unknown {\n if (value === undefined) {\n return undefined;\n }\n return JSON.parse(JSON.stringify(value));\n}\n\n/**\n * .einja-sync.json を読み込む\n *\n * @param targetDir - ターゲットディレクトリ\n * @returns メタデータ(存在しない場合はnull)\n */\nexport async function loadSyncMetadata(\n targetDir: string\n): Promise<SyncMetadata | null> {\n const metadataPath = `${targetDir}/.einja-sync.json`;\n\n if (!existsSync(metadataPath)) {\n return null;\n }\n\n try {\n const content = readFileSync(metadataPath, \"utf-8\");\n return JSON.parse(content) as SyncMetadata;\n } catch {\n return null;\n }\n}\n\n/**\n * .einja-sync.json を保存する\n *\n * @param targetDir - ターゲットディレクトリ\n * @param metadata - メタデータ\n */\nexport async function saveSyncMetadata(\n targetDir: string,\n metadata: SyncMetadata\n): Promise<void> {\n const metadataPath = `${targetDir}/.einja-sync.json`;\n ensureDir(dirname(metadataPath));\n writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), \"utf-8\");\n}\n\n/**\n * package.json の特殊マージ処理\n *\n * @param existingContent - 既存の package.json の内容\n * @param templateContent - テンプレートの package.json の内容\n * @param packageJsonSections - 同期対象のセクション(指定がない場合は全セクション)\n * @returns マージ後の package.json の内容\n */\nasync function mergePackageJson(\n existingContent: string,\n templateContent: string,\n packageJsonSections?: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"engines\">\n): Promise<string> {\n // Given: JSON をパース\n const existingPkg = JSON.parse(existingContent) as Record<string, unknown>;\n const templatePkg = JSON.parse(templateContent) as Record<string, unknown>;\n\n // When: 既存の内容をベースにする\n const result = { ...existingPkg };\n\n // When: scripts をマージ(セクション指定がない、またはscriptsが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"scripts\")) && templatePkg.scripts && typeof templatePkg.scripts === \"object\") {\n result.scripts = {\n ...(existingPkg.scripts && typeof existingPkg.scripts === \"object\"\n ? existingPkg.scripts\n : {}),\n ...templatePkg.scripts,\n };\n }\n\n // When: dependencies をバージョン競合処理付きでマージ(セクション指定がない、またはdependenciesが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"dependencies\")) && templatePkg.dependencies && typeof templatePkg.dependencies === \"object\") {\n result.dependencies = await mergePackageJsonDependencies(\n (existingPkg.dependencies && typeof existingPkg.dependencies === \"object\"\n ? existingPkg.dependencies\n : {}) as Record<string, string>,\n templatePkg.dependencies as Record<string, string>,\n false\n );\n }\n\n // When: devDependencies をバージョン競合処理付きでマージ(セクション指定がない、またはdevDependenciesが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"devDependencies\")) && templatePkg.devDependencies && typeof templatePkg.devDependencies === \"object\") {\n result.devDependencies = await mergePackageJsonDependencies(\n (existingPkg.devDependencies && typeof existingPkg.devDependencies === \"object\"\n ? existingPkg.devDependencies\n : {}) as Record<string, string>,\n templatePkg.devDependencies as Record<string, string>,\n false\n );\n }\n\n // When: engines を完全置換(セクション指定がない、またはenginesが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"engines\")) && templatePkg.engines && typeof templatePkg.engines === \"object\") {\n if (\n existingPkg.engines &&\n JSON.stringify(existingPkg.engines) !== JSON.stringify(templatePkg.engines)\n ) {\n logger.warn(\"⚠️ engines を置換します:\");\n logger.warn(` 既存: ${JSON.stringify(existingPkg.engines)}`);\n logger.warn(` 新規: ${JSON.stringify(templatePkg.engines)}`);\n }\n result.engines = templatePkg.engines;\n }\n\n // Then: JSON 文字列として返す\n return `${JSON.stringify(result, null, 2)}\\n`;\n}\n\n/**\n * ファイルマージの実行(テキスト/JSON自動判定)\n *\n * @param templatePath - テンプレートファイルのパス\n * @param targetPath - ターゲットファイルのパス\n * @param syncMetadata - 同期メタデータ\n * @param packageJsonSections - 同期対象のpackage.jsonセクション(指定がない場合は全セクション)\n * @returns マージ結果\n */\nexport async function mergeAndWriteFile(\n templatePath: string,\n targetPath: string,\n syncMetadata: SyncMetadata,\n packageJsonSections?: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"engines\">\n): Promise<{\n action: \"created\" | \"merged\" | \"skipped\" | \"overwritten\";\n path: string;\n}> {\n const templateContent = readFileSync(templatePath, \"utf-8\");\n const targetExists = existsSync(targetPath);\n const existingContent = targetExists ? readFileSync(targetPath, \"utf-8\") : null;\n\n // Given: ファイルがJSONかどうか判定\n const isJsonFile = targetPath.endsWith(\".json\");\n const isPackageJson = basename(targetPath) === \"package.json\";\n\n let mergedContent: string;\n let action: \"created\" | \"merged\" | \"skipped\" | \"overwritten\";\n\n if (!targetExists) {\n // When: ファイルが存在しない場合は新規作成\n mergedContent = templateContent;\n action = \"created\";\n } else if (isPackageJson && existingContent) {\n // When: package.json の特殊処理\n try {\n mergedContent = await mergePackageJson(existingContent, templateContent, packageJsonSections);\n action = \"merged\";\n } catch {\n // Then: パースエラーの場合はテンプレートで上書き\n mergedContent = templateContent;\n action = \"overwritten\";\n }\n } else if (isJsonFile) {\n // When: JSONファイルの場合はディープマージ\n try {\n const templateJson = JSON.parse(templateContent) as Record<string, unknown>;\n const existingJson = existingContent\n ? (JSON.parse(existingContent) as Record<string, unknown>)\n : null;\n const jsonPaths = syncMetadata.jsonPaths || { managed: {}, seed: {} };\n // ファイルパスからファイル名を抽出(例: \"/path/to/package.json\" → \"package.json\")\n const fileName = targetPath.split(\"/\").pop() || \"package.json\";\n const mergedJson = mergeJson(templateJson, existingJson, jsonPaths, fileName);\n mergedContent = JSON.stringify(mergedJson, null, 2);\n action = \"merged\";\n } catch {\n // Then: パースエラーの場合はテンプレートで上書き\n mergedContent = templateContent;\n action = \"overwritten\";\n }\n } else {\n // When: テキストファイルの場合はマーカーベースマージ\n mergedContent = mergeTextWithMarkers(templateContent, existingContent);\n\n // Then: 内容が変更されたかチェック\n if (mergedContent === existingContent) {\n action = \"skipped\";\n } else {\n action = \"merged\";\n }\n }\n\n // Then: ファイルに書き込み\n if (action !== \"skipped\") {\n ensureDir(dirname(targetPath));\n writeFileSync(targetPath, mergedContent, \"utf-8\");\n }\n\n return { action, path: targetPath };\n}\n\n/**\n * マーカーセクションの型定義\n */\ninterface MarkerSection {\n type: \"managed\" | \"seed\" | \"unmanaged\";\n startLine: number;\n endLine: number;\n content: string;\n id?: string;\n}\n\n/**\n * ファイル内容をパースしてマーカーセクションに分離する\n *\n * @param content - ファイル内容\n * @returns セクション配列\n */\nfunction parseMarkers(content: string): MarkerSection[] {\n const lines = content.split(\"\\n\");\n const sections: MarkerSection[] = [];\n let currentType: \"managed\" | \"seed\" | \"unmanaged\" = \"unmanaged\";\n let currentStartLine = 1;\n let currentContent: string[] = [];\n let currentId: string | undefined;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] as string;\n const lineNumber = i + 1;\n\n // Given: マーカー開始を検出\n const startMarker = parseStartMarker(line);\n if (startMarker) {\n if (currentType !== \"unmanaged\") {\n // Then: 入れ子のマーカーは無視\n currentContent.push(line);\n continue;\n }\n\n // When: 現在のunmanagedセクションを保存\n if (currentContent.length > 0 || sections.length === 0) {\n sections.push({\n type: \"unmanaged\",\n startLine: currentStartLine,\n endLine: lineNumber - 1,\n content: currentContent.join(\"\\n\"),\n });\n }\n\n // When: managed/seedセクション開始\n currentType = startMarker.type;\n currentId = startMarker.id;\n currentStartLine = lineNumber;\n currentContent = [line];\n }\n // Given: マーカー終了を検出\n else if (parseEndMarker(line)) {\n if (currentType === \"unmanaged\") {\n // Then: 対応するstartがない場合は無視\n currentContent.push(line);\n continue;\n }\n\n // When: マーカー終了行を追加\n currentContent.push(line);\n\n // When: managed/seedセクションを保存\n sections.push({\n type: currentType,\n startLine: currentStartLine,\n endLine: lineNumber,\n content: currentContent.join(\"\\n\"),\n id: currentId,\n });\n\n // When: unmanagedセクション開始\n currentType = \"unmanaged\";\n currentId = undefined;\n currentStartLine = lineNumber + 1;\n currentContent = [];\n }\n // Given: 通常行\n else {\n currentContent.push(line);\n }\n }\n\n // Then: 最後のセクションを保存\n if (currentContent.length > 0 || sections.length === 0) {\n sections.push({\n type: currentType,\n startLine: currentStartLine,\n endLine: lines.length,\n content: currentContent.join(\"\\n\"),\n id: currentId,\n });\n }\n\n return sections;\n}\n\n/**\n * 行がマーカー開始かどうかを判定し、種別とIDを返す\n *\n * @param line - 行内容\n * @returns マーカー情報またはnull\n */\nfunction parseStartMarker(\n line: string\n): { type: \"managed\" | \"seed\"; id?: string } | null {\n // Markdown managed\n const markdownManagedPattern =\n /^<!--\\s*@einja:managed:start(?:\\s+id=\"([^\"]+)\")?\\s*-->$/;\n let match = line.match(markdownManagedPattern);\n if (match) {\n return { type: \"managed\", id: match[1] || undefined };\n }\n\n // Markdown seed\n const markdownSeedPattern =\n /^<!--\\s*@einja:seed:start(?:\\s+id=\"([^\"]+)\")?\\s*-->$/;\n match = line.match(markdownSeedPattern);\n if (match) {\n return { type: \"seed\", id: match[1] || undefined };\n }\n\n // YAML/JSON managed\n const yamlManagedPattern = /^\\s*#\\s*@einja:managed:start(?:\\s+id=\"([^\"]+)\")?\\s*$/;\n match = line.match(yamlManagedPattern);\n if (match) {\n return { type: \"managed\", id: match[1] || undefined };\n }\n\n // YAML/JSON seed\n const yamlSeedPattern = /^\\s*#\\s*@einja:seed:start(?:\\s+id=\"([^\"]+)\")?\\s*$/;\n match = line.match(yamlSeedPattern);\n if (match) {\n return { type: \"seed\", id: match[1] || undefined };\n }\n\n return null;\n}\n\n/**\n * 行がマーカー終了かどうかを判定し、種別を返す\n *\n * @param line - 行内容\n * @returns マーカー種別またはnull\n */\nfunction parseEndMarker(line: string): \"managed\" | \"seed\" | null {\n // Markdown managed\n if (/^<!--\\s*@einja:managed:end\\s*-->$/.test(line)) {\n return \"managed\";\n }\n\n // Markdown seed\n if (/^<!--\\s*@einja:seed:end\\s*-->$/.test(line)) {\n return \"seed\";\n }\n\n // YAML/JSON managed\n if (/^\\s*#\\s*@einja:managed:end\\s*$/.test(line)) {\n return \"managed\";\n }\n\n // YAML/JSON seed\n if (/^\\s*#\\s*@einja:seed:end\\s*$/.test(line)) {\n return \"seed\";\n }\n\n return null;\n}\n\n/**\n * パスがmanagedに含まれるかチェック\n *\n * @param filePath - ファイルパス(例: \"package.json\")\n * @param keyPath - チェックするキーパス(例: \"scripts.dev\")\n * @param jsonPaths - JSONパス設定\n * @returns managedに含まれる場合true\n */\nfunction isPathManaged(\n filePath: string,\n keyPath: string,\n jsonPaths: JsonPathsConfig\n): boolean {\n const managedPaths = jsonPaths.managed[filePath] || [];\n // keyPath が managedPaths のいずれかで始まるかチェック\n // 例: keyPath=\"scripts.dev\" が managedPaths=[\"scripts.dev\"] にマッチ\n // または keyPath=\"scripts.dev\" が managedPaths=[\"scripts\"] にマッチ\n return managedPaths.some(\n (p) => keyPath === p || keyPath.startsWith(`${p}.`)\n );\n}\n\n/**\n * パスがseedに含まれるかチェック\n *\n * @param filePath - ファイルパス(例: \"package.json\")\n * @param keyPath - チェックするキーパス(例: \"scripts.custom\")\n * @param jsonPaths - JSONパス設定\n * @returns seedに含まれる場合true\n */\nfunction isPathSeed(\n filePath: string,\n keyPath: string,\n jsonPaths: JsonPathsConfig\n): boolean {\n const seedPaths = jsonPaths.seed[filePath] || [];\n // keyPath が seedPaths のいずれかで始まるかチェック\n return seedPaths.some((p) => keyPath === p || keyPath.startsWith(`${p}.`));\n}\n","import inquirer from \"inquirer\";\nimport * as logger from \"./logger.js\";\n\n/**\n * package.json の依存関係の型\n */\nexport interface PackageJsonDependencies {\n [key: string]: string;\n}\n\n/**\n * バージョン競合の情報\n */\nexport interface VersionConflict {\n packageName: string;\n existingVersion: string;\n templateVersion: string;\n}\n\n/**\n * マージ結果の型\n */\nexport interface PackageJsonMergeResult {\n merged: PackageJsonDependencies;\n conflicts: VersionConflict[];\n}\n\n/**\n * バージョンが異なるかチェック\n *\n * @param existingVersion - 既存のバージョン\n * @param templateVersion - テンプレートのバージョン\n * @returns バージョン競合がある場合 true\n */\nfunction hasVersionConflict(\n existingVersion: string,\n templateVersion: string\n): boolean {\n // Given: 完全一致の場合\n if (existingVersion === templateVersion) {\n // Then: 競合なし\n return false;\n }\n\n // Given: 範囲指定の正規化(^1.0.0 と 1.0.0 は同一とみなす等)\n const normalize = (v: string) => v.replace(/^[\\^~]/, \"\");\n\n // When: 正規化したバージョンを比較\n // Then: 異なる場合は競合あり\n return normalize(existingVersion) !== normalize(templateVersion);\n}\n\n/**\n * 依存関係をマージし、バージョン競合を検出\n *\n * @param existing - 既存の依存関係\n * @param template - テンプレートの依存関係\n * @returns マージ結果と競合リスト\n */\nexport async function mergeDependenciesWithConflictDetection(\n existing: PackageJsonDependencies,\n template: PackageJsonDependencies\n): Promise<PackageJsonMergeResult> {\n // Given: マージ結果と競合リストを初期化\n const merged: PackageJsonDependencies = { ...existing };\n const conflicts: VersionConflict[] = [];\n\n // When: テンプレートの各パッケージを処理\n for (const [packageName, templateVersion] of Object.entries(template)) {\n if (packageName in existing) {\n // Given: 既存パッケージが存在する場合\n const existingVersion = existing[packageName];\n\n if (existingVersion && hasVersionConflict(existingVersion, templateVersion)) {\n // When: バージョン競合が発生\n // Then: 競合リストに追加(この時点ではマージしない)\n conflicts.push({\n packageName,\n existingVersion,\n templateVersion,\n });\n } else {\n // When: バージョンが一致または正規化後一致\n // Then: テンプレートのバージョンを使用\n merged[packageName] = templateVersion;\n }\n } else {\n // Given: 新規パッケージの場合\n // Then: 無条件で追加\n merged[packageName] = templateVersion;\n }\n }\n\n // Then: マージ結果と競合リストを返す\n return { merged, conflicts };\n}\n\n/**\n * ユーザーにバージョン競合の解決方法を尋ねる\n *\n * @param conflicts - 競合リスト\n * @returns パッケージ名とバージョンのマップ\n */\nexport async function resolveVersionConflicts(\n conflicts: VersionConflict[]\n): Promise<Map<string, string>> {\n // Given: 解決結果を格納するマップ\n const resolutions = new Map<string, string>();\n\n // When: 競合が存在する場合\n logger.warn(`\\n⚠️ ${conflicts.length}個のパッケージでバージョン競合が検出されました:\\n`);\n\n // When: 各競合について順次処理\n for (const conflict of conflicts) {\n logger.warn(`📦 ${conflict.packageName}`);\n logger.warn(` 既存: ${conflict.existingVersion}`);\n logger.warn(` テンプレート: ${conflict.templateVersion}\\n`);\n\n // When: ユーザーに選択を求める\n const answer = await inquirer.prompt([\n {\n type: \"list\",\n name: \"version\",\n message: \"どちらのバージョンを使用しますか?\",\n choices: [\n {\n name: `テンプレート (${conflict.templateVersion})`,\n value: \"template\",\n },\n {\n name: `既存 (${conflict.existingVersion})`,\n value: \"existing\",\n },\n {\n name: \"スキップ(既存を維持)\",\n value: \"skip\",\n },\n ],\n },\n ]);\n\n // Then: ユーザーの選択に応じて解決結果を記録\n if (answer.version === \"template\") {\n resolutions.set(conflict.packageName, conflict.templateVersion);\n } else if (answer.version === \"existing\") {\n resolutions.set(conflict.packageName, conflict.existingVersion);\n }\n // skip の場合は何もしない(既存を維持)\n }\n\n // Then: 解決結果を返す\n return resolutions;\n}\n\n/**\n * 依存関係を完全にマージ(競合解決含む)\n *\n * @param existingDeps - 既存の依存関係\n * @param templateDeps - テンプレートの依存関係\n * @param skipPrompts - プロンプトをスキップするかどうか\n * @returns マージされた依存関係\n */\nexport async function mergePackageJsonDependencies(\n existingDeps: PackageJsonDependencies,\n templateDeps: PackageJsonDependencies,\n skipPrompts = false\n): Promise<PackageJsonDependencies> {\n // Given: 依存関係をマージして競合を検出\n const { merged, conflicts } = await mergeDependenciesWithConflictDetection(\n existingDeps,\n templateDeps\n );\n\n // Given: 競合がない場合\n if (conflicts.length === 0) {\n // Then: マージ結果をそのまま返す\n return merged;\n }\n\n // Given: プロンプトをスキップする場合\n if (skipPrompts) {\n // Then: 既存バージョンを優先(競合分は merged に含まれていない)\n logger.info(\n `バージョン競合が${conflicts.length}個ありますが、既存バージョンを維持します`\n );\n return merged;\n }\n\n // When: ユーザーに競合解決を尋ねる\n const resolutions = await resolveVersionConflicts(conflicts);\n\n // When: 解決結果をマージ結果に反映\n for (const [packageName, version] of resolutions.entries()) {\n merged[packageName] = version;\n }\n\n // Then: 最終的なマージ結果を返す\n return merged;\n}\n","import { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n AddOptions,\n AppComponent,\n SyncMetadata,\n} from \"../../types/index.js\";\nimport { mergeAndWriteFile } from \"../../utils/merger.js\";\nimport * as logger from \"../../utils/logger.js\";\n\n/**\n * apps/ ディレクトリにコンポーネントを追加\n */\nexport async function addApps(\n options: AddOptions,\n components: AppComponent[],\n syncMetadata: SyncMetadata\n): Promise<{ added: string[]; skipped: string[]; merged: string[] }> {\n const added: string[] = [];\n const skipped: string[] = [];\n const merged: string[] = [];\n\n const { targetDir, templateDir, config } = options;\n\n for (const component of components) {\n const componentName = component === \"web\" ? \"web\" : component;\n\n const srcDir = join(templateDir, \"apps\", componentName);\n const destDir = join(targetDir, \"apps\", componentName);\n\n logger.info(`Adding app component: ${componentName}`);\n\n await copyDirectory(\n srcDir,\n destDir,\n { added, skipped, merged },\n config.dryRun,\n syncMetadata\n );\n }\n\n return { added, skipped, merged };\n}\n\n/**\n * ディレクトリを再帰的にコピー\n */\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n result: { added: string[]; skipped: string[]; merged: string[] },\n dryRun: boolean,\n syncMetadata: SyncMetadata\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath, result, dryRun, syncMetadata);\n } else {\n if (!dryRun) {\n const mergeResult = await mergeAndWriteFile(\n srcPath,\n destPath,\n syncMetadata\n );\n\n if (mergeResult.action === \"created\") {\n result.added.push(destPath);\n } else if (mergeResult.action === \"skipped\") {\n result.skipped.push(destPath);\n } else if (mergeResult.action === \"merged\") {\n result.merged.push(destPath);\n }\n } else {\n // dry-runモードではスキップ\n result.skipped.push(destPath);\n }\n }\n }\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport type { AddOptions, SyncMetadata } from \"../../types/index.js\";\nimport { mergeAndWriteFile } from \"../../utils/merger.js\";\nimport * as logger from \"../../utils/logger.js\";\n\n/**\n * プロジェクト直下の設定ファイルを追加\n */\nexport async function addConfigFiles(\n options: AddOptions,\n syncMetadata: SyncMetadata\n): Promise<{ added: string[]; skipped: string[]; merged: string[] }> {\n const added: string[] = [];\n const skipped: string[] = [];\n const merged: string[] = [];\n\n const { targetDir, templateDir, config } = options;\n\n logger.info(\"Adding config files from template root\");\n\n // 除外パターン\n const excludedPaths = new Set([\n \".claude\",\n \"docs/einja\",\n \"CLAUDE.md\",\n \".mcp.json\",\n \"node_modules\",\n \".turbo\",\n \"next-env.d.ts\",\n \"styled-system\",\n \"pnpm-lock.yaml\",\n \"package-lock.json\",\n \"packages\",\n \"apps\",\n ]);\n\n // .gitignore のパターンを読み込み\n const gitignorePatterns = await loadGitignorePatterns(templateDir);\n\n await copyConfigDirectory(\n templateDir,\n targetDir,\n templateDir, // rootDir として templateDir を渡す\n { added, skipped, merged },\n config.dryRun,\n excludedPaths,\n gitignorePatterns,\n syncMetadata\n );\n\n return { added, skipped, merged };\n}\n\n/**\n * .gitignore のパターンを読み込み\n */\nasync function loadGitignorePatterns(templateDir: string): Promise<Set<string>> {\n const patterns = new Set<string>();\n const gitignorePath = join(templateDir, \".gitignore\");\n\n try {\n const content = await readFile(gitignorePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n\n for (const line of lines) {\n const trimmed = line.trim();\n // コメントと空行を除外\n if (trimmed && !trimmed.startsWith(\"#\")) {\n // 先頭の / を削除\n const pattern = trimmed.startsWith(\"/\") ? trimmed.slice(1) : trimmed;\n patterns.add(pattern);\n }\n }\n } catch {\n // .gitignore が存在しない場合は無視\n }\n\n return patterns;\n}\n\n/**\n * 設定ファイルのディレクトリを再帰的にコピー\n */\nasync function copyConfigDirectory(\n srcDir: string,\n destDir: string,\n rootDir: string, // テンプレートルートディレクトリ\n result: { added: string[]; skipped: string[]; merged: string[] },\n dryRun: boolean,\n excludedPaths: Set<string>,\n gitignorePatterns: Set<string>,\n syncMetadata: SyncMetadata\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n // rootDir からの相対パスを計算(一貫性を保つ)\n const rawRelativePath = relative(rootDir, srcPath);\n // Windows対応: パス区切り文字をPOSIX形式(/)に正規化\n const relativePath = rawRelativePath.split(sep).join(\"/\");\n\n // 除外パターンに一致するかチェック\n if (shouldExclude(relativePath, excludedPaths, gitignorePatterns)) {\n continue;\n }\n\n if (entry.isDirectory()) {\n await copyConfigDirectory(\n srcPath,\n destPath,\n rootDir, // rootDir を引き継ぐ\n result,\n dryRun,\n excludedPaths,\n gitignorePatterns,\n syncMetadata\n );\n } else {\n if (!dryRun) {\n const mergeResult = await mergeAndWriteFile(\n srcPath,\n destPath,\n syncMetadata\n );\n\n if (mergeResult.action === \"created\") {\n result.added.push(destPath);\n } else if (mergeResult.action === \"skipped\") {\n result.skipped.push(destPath);\n } else if (mergeResult.action === \"merged\") {\n result.merged.push(destPath);\n }\n } else {\n // dry-runモードではスキップ\n result.skipped.push(destPath);\n }\n }\n }\n}\n\n/**\n * パスを除外すべきか判定\n */\nfunction shouldExclude(\n relativePath: string,\n excludedPaths: Set<string>,\n gitignorePatterns: Set<string>\n): boolean {\n // 除外パスに完全一致または部分一致\n for (const excluded of excludedPaths) {\n if (relativePath === excluded || relativePath.startsWith(`${excluded}/`)) {\n return true;\n }\n }\n\n // .gitignore パターンに一致\n for (const pattern of gitignorePatterns) {\n // シンプルなパターンマッチング(ワイルドカード対応)\n if (matchPattern(relativePath, pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * シンプルなパターンマッチング\n */\nfunction matchPattern(path: string, pattern: string): boolean {\n // パターンの最後が / の場合、ディレクトリのみ一致\n if (pattern.endsWith(\"/\")) {\n const dirPattern = pattern.slice(0, -1);\n return path === dirPattern || path.startsWith(`${dirPattern}/`);\n }\n\n // * を含むパターン\n if (pattern.includes(\"*\")) {\n const regexPattern = pattern\n .replace(/\\./g, \"\\\\.\")\n .replace(/\\*/g, \".*\");\n return new RegExp(`^${regexPattern}$`).test(path);\n }\n\n // 完全一致または部分一致\n return path === pattern || path.startsWith(`${pattern}/`);\n}\n","import { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport fsExtra from \"fs-extra\";\nimport inquirer from \"inquirer\";\nimport { collectSyncFiles } from \"../generators/sync.js\";\nimport { promptSyncCategories } from \"../prompts/sync.js\";\nimport type { SyncCategory, SyncMetadata, SyncOptions, SyncResult } from \"../types/index.js\";\nimport { createBackup, getLatestBackup, restoreFromBackup } from \"../utils/backup.js\";\nimport { checkGitStatusForSync } from \"../utils/git.js\";\nimport * as logger from \"../utils/logger.js\";\nimport { mergeAndWriteFile } from \"../utils/merger.js\";\n\n// 同期処理中のバックアップ情報を保持\nlet currentBackupDir: string | undefined;\nlet isSyncing = false;\n\n/**\n * 中断時のクリーンアップ処理\n */\nasync function handleInterrupt(): Promise<void> {\n if (!isSyncing) {\n // 同期処理開始前の中断は単純に終了\n logger.info(\"\\n\\n処理を中断しました\");\n process.exit(0);\n }\n\n logger.info(\"\\n\\n🛑 同期処理を中断しています...\");\n\n if (!currentBackupDir) {\n logger.info(\"バックアップが作成されていないため、クリーンアップは不要です\");\n process.exit(0);\n }\n\n // バックアップからのロールバック確認\n const answer = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"rollback\",\n message: \"変更をロールバックしますか?\",\n default: true,\n },\n ]);\n\n if (answer.rollback) {\n logger.info(\"バックアップから復元中...\");\n const targetDir = process.cwd();\n const success = await restoreFromBackup(currentBackupDir, targetDir);\n\n if (success) {\n logger.success(\"✓ ロールバック完了\");\n } else {\n logger.error(\"❌ ロールバック失敗\");\n logger.info(`手動で復元: cp -r ${currentBackupDir}/* .`);\n }\n }\n\n process.exit(0);\n}\n\n/**\n * テンプレートパスを取得\n */\nfunction getTemplatePath(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const { existsSync } = fsExtra;\n\n // dist/cli.js → ../templates/default (1階層上)\n // src/commands/sync.ts → ../../templates/default (2階層上)\n const distPath = join(__dirname, \"../templates/default\");\n const srcPath = join(__dirname, \"../../templates/default\");\n\n if (existsSync(distPath)) {\n return distPath;\n }\n if (existsSync(srcPath)) {\n return srcPath;\n }\n\n throw new Error(\"テンプレートディレクトリが見つかりません\");\n}\n\n/**\n * sync コマンドのメイン関数\n */\nexport async function syncCommand(options: SyncOptions): Promise<void> {\n const { existsSync } = fsExtra;\n // Ctrl+C (SIGINT) ハンドラーを登録\n const sigintHandler = () => {\n handleInterrupt().catch((error) => {\n logger.error(`クリーンアップ中にエラー: ${error}`);\n process.exit(1);\n });\n };\n\n process.on(\"SIGINT\", sigintHandler);\n\n // 関数終了時にハンドラーを削除(正常終了時)\n const cleanup = () => {\n process.off(\"SIGINT\", sigintHandler);\n };\n\n try {\n // ========================================\n // a) Rollback モード\n // ========================================\n if (options.rollback) {\n logger.info(\"🔄 バックアップからロールバック中...\");\n\n const targetDir = process.cwd();\n const latestBackup = await getLatestBackup(targetDir);\n\n if (!latestBackup) {\n logger.error(\"❌ バックアップが見つかりません\");\n process.exit(1);\n }\n\n logger.info(`バックアップ: ${latestBackup.name}`);\n\n const success = await restoreFromBackup(latestBackup.path, targetDir);\n if (success) {\n logger.success(\"✓ ロールバック完了\");\n } else {\n logger.error(\"❌ ロールバック失敗\");\n process.exit(1);\n }\n\n return;\n }\n\n // ========================================\n // b) Git チェック\n // ========================================\n const targetDir = process.cwd();\n checkGitStatusForSync(options.force || false, targetDir);\n\n // ========================================\n // c) プロンプトまたはデフォルト設定\n // ========================================\n const templatePath = getTemplatePath();\n\n let categories: SyncCategory[];\n let appsDetail: string[] | undefined;\n let packagesDetail: string[] | undefined;\n let conflictStrategy: \"merge\" | \"overwrite\" | \"skip\";\n let packageJsonSections: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"engines\"> | undefined;\n\n if (options.all) {\n // デフォルト: 全カテゴリ選択\n categories = [\n \"env\",\n \"tools\",\n \"git\",\n \"git-hooks\",\n \"github\",\n \"docker\",\n \"monorepo\",\n \"root-config\",\n \"apps\",\n \"packages\",\n \"docs\",\n ];\n appsDetail = undefined; // 全apps\n packagesDetail = undefined; // 全packages\n conflictStrategy = \"merge\";\n\n logger.info(\"全カテゴリを同期対象に設定しました\");\n } else if (options.categories) {\n // コマンドラインで指定されたカテゴリのみ\n categories = options.categories as SyncCategory[];\n appsDetail = undefined;\n packagesDetail = undefined;\n conflictStrategy = \"merge\";\n\n logger.info(`指定されたカテゴリ: ${categories.join(\", \")}`);\n } else {\n // 対話式プロンプト\n const promptResult = await promptSyncCategories(templatePath);\n categories = promptResult.categories;\n appsDetail = promptResult.appsDetail;\n packagesDetail = promptResult.packagesDetail;\n conflictStrategy = promptResult.conflictStrategy;\n packageJsonSections = promptResult.packageJsonSections;\n }\n\n // ========================================\n // d) ファイル収集\n // ========================================\n logger.info(\"📁 同期対象ファイルを収集中...\");\n\n const filesToSync = await collectSyncFiles(templatePath, categories, appsDetail, packagesDetail);\n\n if (filesToSync.length === 0) {\n logger.warn(\"⚠️ 同期対象のファイルが見つかりません\");\n return;\n }\n\n logger.info(`同期対象: ${filesToSync.length}個のファイル`);\n\n // ========================================\n // e) Dry-run モード\n // ========================================\n if (options.dryRun) {\n logger.info(\"\\n📋 同期プレビュー (--dry-run)\\n\");\n\n for (const file of filesToSync) {\n logger.info(` ✓ ${file}`);\n }\n\n logger.info(`\\n合計: ${filesToSync.length}ファイル`);\n logger.info(\"--dry-run モードのため、実際のファイル変更は行われません\");\n return;\n }\n\n // ========================================\n // f) バックアップ作成\n // ========================================\n let backupDir: string | undefined;\n\n if (options.backup !== false) {\n logger.info(\"💾 バックアップ作成中...\");\n\n // 既存ファイルのみバックアップ\n const existingFiles = filesToSync.filter((file) => existsSync(join(targetDir, file)));\n\n if (existingFiles.length > 0) {\n backupDir = await createBackup(targetDir, existingFiles);\n currentBackupDir = backupDir; // グローバル変数に設定\n } else {\n logger.info(\"既存ファイルがないため、バックアップをスキップします\");\n }\n }\n\n // ========================================\n // g) ファイル同期処理\n // ========================================\n logger.info(\"🔄 ファイル同期中...\");\n\n isSyncing = true; // 同期処理開始をマーク\n\n // SyncMetadata の準備(conflictStrategy に基づく)\n const syncMetadata: SyncMetadata = {\n version: \"1.0.0\",\n lastSync: new Date().toISOString(),\n templateVersion: \"0.2.9\",\n files: {},\n jsonPaths: {\n managed: {},\n seed: {},\n },\n };\n\n const result: SyncResult = {\n success: 0,\n skipped: 0,\n errors: 0,\n conflicts: 0,\n files: [],\n };\n\n for (const file of filesToSync) {\n try {\n const sourcePath = join(templatePath, file);\n const targetPath = join(targetDir, file);\n\n if (!existsSync(sourcePath)) {\n logger.warn(`スキップ: ${file} (テンプレートファイルが存在しません)`);\n result.skipped++;\n result.files.push({\n path: file,\n action: \"skipped\",\n reason: \"テンプレートファイルが存在しません\",\n });\n continue;\n }\n\n // マージまたはコピー(packageJsonSections を渡す)\n const mergeResult = await mergeAndWriteFile(\n sourcePath,\n targetPath,\n syncMetadata,\n packageJsonSections\n );\n\n // アクションをマッピング(mergeAndWriteFile の戻り値を SyncResult の型に変換)\n const mappedAction: \"copied\" | \"merged\" | \"skipped\" =\n mergeResult.action === \"created\" || mergeResult.action === \"overwritten\"\n ? \"copied\"\n : mergeResult.action;\n\n result.success++;\n result.files.push({\n path: file,\n action: mappedAction,\n });\n\n logger.info(` ✓ ${file}`);\n } catch (error) {\n result.errors++;\n result.files.push({\n path: file,\n action: \"error\",\n reason: error instanceof Error ? error.message : \"不明なエラー\",\n });\n logger.error(` ✗ ${file}: ${error}`);\n }\n }\n\n // ========================================\n // h) 結果レポート\n // ========================================\n logger.info(\"\\n📊 同期結果:\");\n logger.info(` 成功: ${result.success}ファイル`);\n if (result.skipped > 0) {\n logger.info(` スキップ: ${result.skipped}ファイル`);\n }\n if (result.errors > 0) {\n logger.error(` エラー: ${result.errors}ファイル`);\n }\n\n if (result.errors > 0) {\n isSyncing = false; // エラー時もフラグをクリア\n\n logger.error(\"\\n❌ 同期中にエラーが発生しました\");\n if (backupDir) {\n logger.info(\"バックアップから復元: npx create-einja-app sync --rollback\");\n }\n process.exit(1);\n }\n\n logger.success(\"\\n✓ 同期完了\");\n\n // 正常終了時はグローバル変数をクリア\n isSyncing = false;\n currentBackupDir = undefined;\n\n if (backupDir) {\n logger.info(`\\nバックアップ: ${backupDir}`);\n logger.info(\"復元方法: npx create-einja-app sync --rollback\");\n }\n } finally {\n cleanup();\n }\n}\n","import { glob } from \"glob\";\nimport type { SyncCategory } from \"../types/index.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * カテゴリとファイルパターンのマッピング\n * prompts/sync.ts の CATEGORY_CONFIGS と同じ定義\n */\nconst CATEGORY_PATTERNS: Record<SyncCategory, string[]> = {\n env: [\".env*\", \".envrc\", \".volta\", \".node-version\"],\n tools: [\"biome.json\", \".prettierrc*\", \".editorconfig\", \".vscode/**\"],\n git: [\".gitignore\", \".gitattributes\"],\n \"git-hooks\": [\".husky/**\"],\n github: [\".github/workflows/**\", \".github/actions/**\", \".github/dependabot.yml\"],\n docker: [\"Dockerfile*\", \"docker-compose*.yml\", \".dockerignore\"],\n monorepo: [\"turbo.json\", \"pnpm-workspace.yaml\"],\n \"root-config\": [\"package.json\", \"tsconfig.json\"],\n apps: [\"apps/**\"],\n packages: [\"packages/**\"],\n docs: [\"README.md\", \"docs/**\"],\n};\n\n/**\n * envファイル保護ルール\n * これらのファイルは同期対象外(暗号化キーと個人設定)\n */\nconst ENV_FILE_PROTECTION = {\n protected: [\".env.keys\", \".env.personal\"],\n};\n\n/**\n * envファイルが保護対象かチェック\n * @param filePath - ファイルパス\n * @returns 保護対象の場合 true\n */\nfunction isProtectedEnvFile(filePath: string): boolean {\n return ENV_FILE_PROTECTION.protected.some((pattern) =>\n filePath.endsWith(pattern)\n );\n}\n\n/**\n * apps/packagesの詳細フィルタリング\n * @param files - 全ファイルリスト\n * @param detail - 選択された詳細項目\n * @param prefix - \"apps\" or \"packages\"\n * @returns フィルタリング後のファイルリスト\n */\nfunction filterDetailFiles(\n files: string[],\n detail: string[] | undefined,\n prefix: string\n): string[] {\n if (!detail || detail.length === 0) {\n // 詳細指定なしの場合は全て含める\n return files;\n }\n\n // 選択されたアイテムのみをフィルタリング\n return files.filter((file) =>\n detail.some((item) => file.startsWith(`${prefix}/${item}/`))\n );\n}\n\n/**\n * カテゴリからglobパターンを抽出\n * @param categories - 選択されたカテゴリ\n * @param appsDetail - apps詳細選択(オプション)\n * @param packagesDetail - packages詳細選択(オプション)\n * @returns globパターン配列\n */\nfunction extractPatternsFromCategories(\n categories: SyncCategory[],\n appsDetail?: string[],\n packagesDetail?: string[]\n): string[] {\n const patterns: string[] = [];\n\n for (const category of categories) {\n const categoryPatterns = CATEGORY_PATTERNS[category];\n\n if (!categoryPatterns) {\n logger.warn(`不明なカテゴリ: ${category}`);\n continue;\n }\n\n // apps/packages は詳細選択に応じてパターンを調整\n if (category === \"apps\" && appsDetail && appsDetail.length > 0) {\n // 例: [\"web\"] → [\"apps/web/**\"]\n patterns.push(...appsDetail.map((app) => `apps/${app}/**`));\n } else if (category === \"packages\" && packagesDetail && packagesDetail.length > 0) {\n // 例: [\"server-core\"] → [\"packages/server-core/**\"]\n patterns.push(...packagesDetail.map((pkg) => `packages/${pkg}/**`));\n } else {\n // 通常のパターンをそのまま追加\n patterns.push(...categoryPatterns);\n }\n }\n\n return patterns;\n}\n\n/**\n * 同期対象ファイルを収集\n * @param templateDir - テンプレートディレクトリパス\n * @param categories - 選択されたカテゴリ\n * @param appsDetail - apps詳細選択(オプション)\n * @param packagesDetail - packages詳細選択(オプション)\n * @returns 収集されたファイルパスの配列\n */\nexport async function collectSyncFiles(\n templateDir: string,\n categories: SyncCategory[],\n appsDetail?: string[],\n packagesDetail?: string[]\n): Promise<string[]> {\n try {\n logger.info(\"同期対象ファイルを収集中...\");\n\n // 1. カテゴリからパターン抽出\n const patterns = extractPatternsFromCategories(\n categories,\n appsDetail,\n packagesDetail\n );\n\n if (patterns.length === 0) {\n logger.warn(\"同期対象のパターンがありません\");\n return [];\n }\n\n // 2. globによるファイル収集(Set で重複除去)\n const fileSet = new Set<string>();\n\n for (const pattern of patterns) {\n try {\n const files = await glob(pattern, {\n cwd: templateDir,\n dot: true, // .で始まるファイルも含める\n nodir: true, // ディレクトリは除外\n });\n\n for (const file of files) {\n fileSet.add(file);\n }\n } catch (error) {\n logger.warn(`パターン ${pattern} の処理中にエラー: ${error}`);\n }\n }\n\n // 3. 保護対象ファイルを除外\n const allFiles = Array.from(fileSet);\n const filteredFiles = allFiles.filter((file) => {\n // 保護対象envファイルを除外\n if (isProtectedEnvFile(file)) {\n logger.info(`保護対象ファイルを除外: ${file}`);\n return false;\n }\n\n return true;\n });\n\n logger.success(`${filteredFiles.length}個のファイルを収集しました`);\n\n return filteredFiles.sort(); // ソートして返却\n } catch (error) {\n logger.error(`ファイル収集中にエラーが発生しました: ${error}`);\n throw error;\n }\n}\n","import inquirer from \"inquirer\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { SyncCategory, SyncCategoryConfig } from \"../types/index.js\";\n\n/**\n * 同期プロンプト結果の型定義\n */\nexport type SyncPromptResult = {\n categories: SyncCategory[];\n appsDetail?: string[];\n packagesDetail?: string[];\n packageJsonSections?: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"engines\">;\n conflictStrategy: \"merge\" | \"overwrite\" | \"skip\";\n};\n\n/**\n * カテゴリとファイルパターンのマッピング\n */\nconst CATEGORY_CONFIGS: Record<SyncCategory, SyncCategoryConfig> = {\n env: {\n name: \"環境設定\",\n description: \".env*, .envrc, .volta, .node-version\",\n patterns: [\".env*\", \".envrc\", \".volta\", \".node-version\"],\n defaultChecked: true,\n },\n tools: {\n name: \"開発ツール\",\n description: \"biome.json, .prettierrc, .editorconfig, .vscode/\",\n patterns: [\"biome.json\", \".prettierrc*\", \".editorconfig\", \".vscode/\"],\n defaultChecked: true,\n },\n git: {\n name: \"Git設定\",\n description: \".gitignore, .gitattributes\",\n patterns: [\".gitignore\", \".gitattributes\"],\n defaultChecked: false,\n },\n \"git-hooks\": {\n name: \"Git Hooks\",\n description: \".husky/\",\n patterns: [\".husky/\"],\n defaultChecked: false,\n },\n github: {\n name: \"CI/CD\",\n description: \".github/workflows/, .github/actions/\",\n patterns: [\".github/workflows/\", \".github/actions/\", \".github/dependabot.yml\"],\n defaultChecked: false,\n },\n docker: {\n name: \"コンテナ\",\n description: \"Dockerfile*, docker-compose.yml, .dockerignore\",\n patterns: [\"Dockerfile*\", \"docker-compose*.yml\", \".dockerignore\"],\n defaultChecked: false,\n },\n monorepo: {\n name: \"モノレポ構成\",\n description: \"turbo.json, pnpm-workspace.yaml\",\n patterns: [\"turbo.json\", \"pnpm-workspace.yaml\"],\n defaultChecked: false,\n },\n \"root-config\": {\n name: \"ルート設定\",\n description: \"package.json, tsconfig.json\",\n patterns: [\"package.json\", \"tsconfig.json\"],\n defaultChecked: false,\n },\n apps: {\n name: \"アプリケーション\",\n description: \"apps/ 配下(次の画面で個別選択)\",\n patterns: [\"apps/**\"],\n defaultChecked: false,\n requiresDetailSelection: true,\n },\n packages: {\n name: \"共通パッケージ\",\n description: \"packages/ 配下(次の画面で個別選択)\",\n patterns: [\"packages/**\"],\n defaultChecked: false,\n requiresDetailSelection: true,\n },\n docs: {\n name: \"ドキュメント\",\n description: \"README.md, docs/\",\n patterns: [\"README.md\", \"docs/**\"],\n defaultChecked: false,\n },\n};\n\n/**\n * デフォルトの同期カテゴリを取得\n * skipPrompts=true 時に使用\n */\nexport function getDefaultSyncCategories(): SyncCategory[] {\n return Object.entries(CATEGORY_CONFIGS)\n .filter(([_key, config]) => config.defaultChecked)\n .map(([key, _config]) => key as SyncCategory);\n}\n\n/**\n * テンプレートディレクトリからアプリ一覧を取得\n * @param templateDir - テンプレートディレクトリのパス\n * @returns アプリ名の配列\n */\nfunction getAvailableApps(templateDir: string): string[] {\n const appsDir = path.join(templateDir, \"apps\");\n try {\n if (!fs.existsSync(appsDir)) {\n return [];\n }\n return fs\n .readdirSync(appsDir, { withFileTypes: true })\n .filter((dirent) => dirent.isDirectory())\n .map((dirent) => dirent.name);\n } catch (error) {\n console.error(`Error reading apps directory: ${error}`);\n return [];\n }\n}\n\n/**\n * テンプレートディレクトリからパッケージ一覧を取得\n * @param templateDir - テンプレートディレクトリのパス\n * @returns パッケージ名の配列\n */\nfunction getAvailablePackages(templateDir: string): string[] {\n const packagesDir = path.join(templateDir, \"packages\");\n try {\n if (!fs.existsSync(packagesDir)) {\n return [];\n }\n return fs\n .readdirSync(packagesDir, { withFileTypes: true })\n .filter((dirent) => dirent.isDirectory())\n .map((dirent) => dirent.name);\n } catch (error) {\n console.error(`Error reading packages directory: ${error}`);\n return [];\n }\n}\n\n/**\n * カテゴリ選択プロンプトを実行(5段階)\n * @param templateDir - テンプレートディレクトリのパス\n * @returns SyncPromptResult - 同期設定\n */\nexport async function promptSyncCategories(\n templateDir: string,\n): Promise<SyncPromptResult> {\n // ステージ1: 大カテゴリ選択\n const categoryAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"categories\",\n message: \"同期する項目を選択してください(Spaceで選択、Enterで確定):\",\n choices: Object.entries(CATEGORY_CONFIGS).map(([key, config]) => ({\n name: `${config.name} - ${config.description}`,\n value: key,\n checked: config.defaultChecked ?? false,\n })),\n },\n ]);\n\n const selectedCategories = categoryAnswers.categories as SyncCategory[];\n const hasApps = selectedCategories.includes(\"apps\");\n const hasPackages = selectedCategories.includes(\"packages\");\n const hasRootConfig = selectedCategories.includes(\"root-config\");\n\n let appsDetail: string[] | undefined;\n let packagesDetail: string[] | undefined;\n let packageJsonSections: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"engines\"> | undefined;\n let conflictStrategy: \"merge\" | \"overwrite\" | \"skip\" = \"merge\";\n\n // ステージ2: apps詳細選択(appsが選択された場合のみ)\n if (hasApps) {\n const availableApps = getAvailableApps(templateDir);\n if (availableApps.length > 0) {\n const appsAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"apps\",\n message: \"同期するアプリケーションを選択:\",\n choices: availableApps.map((app) => ({\n name: app,\n value: app,\n checked: true,\n })),\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのアプリを選択してください\";\n }\n return true;\n },\n },\n ]);\n appsDetail = appsAnswers.apps as string[];\n } else {\n console.warn(\"警告: apps/ ディレクトリが見つからないか、アプリが存在しません\");\n appsDetail = [];\n }\n }\n\n // ステージ3: packages詳細選択(packagesが選択された場合のみ)\n if (hasPackages) {\n const availablePackages = getAvailablePackages(templateDir);\n if (availablePackages.length > 0) {\n const packagesAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"packages\",\n message: \"同期するパッケージを選択:\",\n choices: availablePackages.map((pkg) => ({\n name: pkg,\n value: pkg,\n checked: true,\n })),\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのパッケージを選択してください\";\n }\n return true;\n },\n },\n ]);\n packagesDetail = packagesAnswers.packages as string[];\n } else {\n console.warn(\"警告: packages/ ディレクトリが見つからないか、パッケージが存在しません\");\n packagesDetail = [];\n }\n }\n\n // ステージ4: package.json セクション選択(root-configが選択された場合のみ)\n if (hasRootConfig) {\n const packageJsonAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"sections\",\n message: \"package.jsonの同期セクションを選択:\",\n choices: [\n { name: \"scripts(推奨)\", value: \"scripts\", checked: true },\n { name: \"engines(推奨)\", value: \"engines\", checked: true },\n { name: \"dependencies\", value: \"dependencies\", checked: false },\n { name: \"devDependencies\", value: \"devDependencies\", checked: false },\n ],\n },\n ]);\n packageJsonSections = packageJsonAnswers.sections as Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"engines\">;\n }\n\n // ステージ5: 競合解決戦略選択\n const strategyAnswers = await inquirer.prompt([\n {\n type: \"list\",\n name: \"conflictStrategy\",\n message: \"競合解決戦略を選択してください:\",\n choices: [\n { name: \"マーカーベースマージ(推奨)\", value: \"merge\" },\n { name: \"テンプレートで上書き\", value: \"overwrite\" },\n { name: \"既存ファイル優先\", value: \"skip\" },\n ],\n default: \"merge\",\n },\n ]);\n conflictStrategy = strategyAnswers.conflictStrategy as \"merge\" | \"overwrite\" | \"skip\";\n\n return {\n categories: selectedCategories,\n appsDetail,\n packagesDetail,\n packageJsonSections,\n conflictStrategy,\n };\n}\n","import fsExtra from \"fs-extra\";\nimport { join, dirname, relative } from \"node:path\";\nimport * as logger from \"./logger.js\";\n\n/**\n * バックアップ情報\n */\nexport interface BackupInfo {\n /** バックアップディレクトリパス */\n path: string;\n /** バックアップディレクトリ名 */\n name: string;\n /** 作成日時 */\n timestamp: Date;\n}\n\nconst { copy, ensureDir, readdir, remove, pathExists } = fsExtra;\n\n/**\n * 現在のタイムスタンプを取得(YYYY-MM-DD_HH-mm-ss形式)\n * @returns タイムスタンプ文字列\n */\nfunction getTimestamp(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, \"0\");\n const day = String(now.getDate()).padStart(2, \"0\");\n const hours = String(now.getHours()).padStart(2, \"0\");\n const minutes = String(now.getMinutes()).padStart(2, \"0\");\n const seconds = String(now.getSeconds()).padStart(2, \"0\");\n return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;\n}\n\n/**\n * バックアップディレクトリ名からタイムスタンプを抽出\n * @param dirName - バックアップディレクトリ名\n * @returns タイムスタンプのDate オブジェクト(失敗時は null)\n */\nfunction parseBackupTimestamp(dirName: string): Date | null {\n const match = dirName.match(/^\\.einja-sync-backup-(\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2})$/);\n if (!match || !match[1]) {\n return null;\n }\n\n const timestampStr = match[1];\n const parts = timestampStr.split(\"_\");\n if (parts.length !== 2) {\n return null;\n }\n\n const [datePart, timePart] = parts;\n if (!datePart || !timePart) {\n return null;\n }\n\n const dateParts = datePart.split(\"-\").map(Number);\n const timeParts = timePart.split(\"-\").map(Number);\n\n if (dateParts.length !== 3 || timeParts.length !== 3) {\n return null;\n }\n\n const [year, month, day] = dateParts;\n const [hours, minutes, seconds] = timeParts;\n\n if (\n year === undefined || month === undefined || day === undefined ||\n hours === undefined || minutes === undefined || seconds === undefined\n ) {\n return null;\n }\n\n return new Date(year, month - 1, day, hours, minutes, seconds);\n}\n\n/**\n * 同期前のバックアップを作成\n * @param targetDir - 対象ディレクトリ\n * @param filesToBackup - バックアップするファイルのリスト\n * @returns バックアップディレクトリパス\n */\nexport async function createBackup(\n targetDir: string,\n filesToBackup: string[]\n): Promise<string> {\n const timestamp = getTimestamp();\n const backupDirName = `.einja-sync-backup-${timestamp}`;\n const backupDir = join(targetDir, backupDirName);\n\n try {\n // バックアップディレクトリを作成\n await ensureDir(backupDir);\n\n // ファイルをバックアップ\n for (const file of filesToBackup) {\n const sourcePath = join(targetDir, file);\n const destPath = join(backupDir, file);\n\n // ファイルが存在するか確認\n if (!(await pathExists(sourcePath))) {\n continue;\n }\n\n // 宛先ディレクトリを作成\n await ensureDir(dirname(destPath));\n\n // ファイルをコピー\n await copy(sourcePath, destPath);\n }\n\n return backupDir;\n } catch (error) {\n logger.error(`バックアップの作成に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n}\n\n/**\n * バックアップから復元\n * @param backupDir - バックアップディレクトリパス\n * @param targetDir - 復元先ディレクトリ\n * @returns 成功の場合 true\n */\nexport async function restoreFromBackup(\n backupDir: string,\n targetDir: string\n): Promise<boolean> {\n try {\n // バックアップディレクトリの存在確認\n if (!(await pathExists(backupDir))) {\n logger.error(`バックアップディレクトリが見つかりません: ${backupDir}`);\n return false;\n }\n\n // バックアップ内のファイル一覧を取得\n const files = await getAllFiles(backupDir);\n\n // ファイルを復元\n for (const file of files) {\n const sourcePath = join(backupDir, file);\n const destPath = join(targetDir, file);\n\n // 宛先ディレクトリを作成\n await ensureDir(dirname(destPath));\n\n // ファイルをコピー(上書き)\n await copy(sourcePath, destPath, { overwrite: true });\n }\n\n return true;\n } catch (error) {\n logger.error(`バックアップからの復元に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n}\n\n/**\n * ディレクトリ内のすべてのファイルを再帰的に取得\n * @param dirPath - ディレクトリパス\n * @param baseDir - ベースディレクトリ(相対パス計算用)\n * @returns ファイルパスの配列(相対パス)\n */\nasync function getAllFiles(dirPath: string, baseDir?: string): Promise<string[]> {\n const base = baseDir ?? dirPath;\n const entries = await readdir(dirPath, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const fullPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n const subFiles = await getAllFiles(fullPath, base);\n files.push(...subFiles);\n } else {\n files.push(relative(base, fullPath));\n }\n }\n\n return files;\n}\n\n/**\n * 利用可能なバックアップ一覧を取得\n * @param targetDir - 対象ディレクトリ\n * @returns バックアップ情報の配列\n */\nexport async function listBackups(targetDir: string): Promise<BackupInfo[]> {\n try {\n // ディレクトリの存在確認\n if (!(await pathExists(targetDir))) {\n return [];\n }\n\n const entries = await readdir(targetDir, { withFileTypes: true });\n const backups: BackupInfo[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) {\n continue;\n }\n\n const timestamp = parseBackupTimestamp(entry.name);\n if (!timestamp) {\n continue;\n }\n\n backups.push({\n path: join(targetDir, entry.name),\n name: entry.name,\n timestamp,\n });\n }\n\n // タイムスタンプでソート(新しい順)\n backups.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n\n return backups;\n } catch (error) {\n logger.error(`バックアップ一覧の取得に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n return [];\n }\n}\n\n/**\n * 古いバックアップを削除\n * @param targetDir - 対象ディレクトリ\n * @param retentionDays - 保持日数(デフォルト: 7)\n * @returns 削除したバックアップ数\n */\nexport async function cleanOldBackups(\n targetDir: string,\n retentionDays = 7\n): Promise<number> {\n try {\n const backups = await listBackups(targetDir);\n const now = Date.now();\n const retentionMs = retentionDays * 24 * 60 * 60 * 1000;\n let deletedCount = 0;\n\n for (const backup of backups) {\n const age = now - backup.timestamp.getTime();\n if (age > retentionMs) {\n await remove(backup.path);\n deletedCount++;\n logger.info(`古いバックアップを削除しました: ${backup.name}`);\n }\n }\n\n return deletedCount;\n } catch (error) {\n logger.error(`バックアップの削除に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n return 0;\n }\n}\n\n/**\n * 最新のバックアップを取得\n * @param targetDir - 対象ディレクトリ\n * @returns 最新のバックアップ情報(存在しない場合は null)\n */\nexport async function getLatestBackup(targetDir: string): Promise<BackupInfo | null> {\n const backups = await listBackups(targetDir);\n return backups.length > 0 ? backups[0] ?? null : null;\n}\n","import { execSync } from \"node:child_process\";\nimport * as logger from \"./logger.js\";\n\n/**\n * カレントディレクトリがGitリポジトリかチェック\n * @param targetDir - 対象ディレクトリ(省略時はカレント)\n * @returns Gitリポジトリの場合 true\n */\nexport function isGitRepository(targetDir?: string): boolean {\n try {\n const cwd = targetDir || process.cwd();\n execSync(\"git rev-parse --is-inside-work-tree\", {\n cwd,\n stdio: \"ignore\",\n });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 未コミットの変更があるかチェック\n * @param targetDir - 対象ディレクトリ(省略時はカレント)\n * @returns 未コミットの変更がある場合 true\n */\nexport function hasUncommittedChanges(targetDir?: string): boolean {\n if (!isGitRepository(targetDir)) {\n logger.warn(\"⚠️ このディレクトリはGitリポジトリではありません\");\n return false;\n }\n\n try {\n const cwd = targetDir || process.cwd();\n const output = execSync(\"git status --porcelain\", {\n cwd,\n encoding: \"utf-8\",\n });\n return output.trim().length > 0;\n } catch (error) {\n logger.warn(`⚠️ Gitステータス確認中にエラーが発生しました: ${error}`);\n return false;\n }\n}\n\n/**\n * sync コマンド実行前のGitステータスチェック\n * @param force - --forceフラグ\n * @param targetDir - 対象ディレクトリ(省略時はカレント)\n * @returns チェック通過の場合 true、ブロックの場合 process.exit(1)\n */\nexport function checkGitStatusForSync(\n force: boolean,\n targetDir?: string,\n): boolean {\n // 1. Gitリポジトリかチェック\n if (!isGitRepository(targetDir)) {\n logger.warn(\"⚠️ このディレクトリはGitリポジトリではありません\");\n logger.warn(\n \" sync実行後の差分確認は `git diff` で行うことを推奨します\",\n );\n // 処理は続行(警告のみ)\n return true;\n }\n\n // 2. 未コミット変更チェック\n if (hasUncommittedChanges(targetDir)) {\n if (!force) {\n // デフォルトでブロック\n logger.error(\"❌ 未コミットの変更があります\");\n logger.error(\n \" 変更をコミットしてから実行するか、--force フラグを使用してください\",\n );\n process.exit(1);\n }\n\n // --force 指定時は警告のみ\n logger.warn(\"⚠️ 未コミットの変更がありますが、--force により続行します\");\n logger.warn(\n \" 問題が発生した場合は `git checkout .` で復元できます\",\n );\n }\n\n return true;\n}\n"],"mappings":"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","names":["readFileSync","fileURLToPath","dirname","join","existsSync","ora","dirname","join","readFileSync","writeFileSync","existsSync","__filename","__dirname","dirname","join","error","chalk","inquirer","inquirer","error","chalk","existsSync","error","ora","existsSync","join","ora","inquirer","join","inquirer","join","inquirer","error","join","readFileSync","writeFileSync","join","packageJsonPath","join","readFileSync","writeFileSync","join","join","join","join","join","join","writeFileSync","join","writeFileSync","packageJsonPath","join","existsSync","ora","error","existsSync","readFile","dirname","join","fileURLToPath","ora","inquirer","join","readFileSync","writeFileSync","existsSync","dirname","inquirer","inquirer","existsSync","readFileSync","dirname","writeFileSync","join","readdir","join","join","copyDirectory","readdir","readdir","join","relative","join","readdir","relative","path","getTemplatePath","__filename","fileURLToPath","__dirname","dirname","join","existsSync","readFile","ora","error","packageJsonPath","packageJson","dirname","join","fileURLToPath","fsExtra","inquirer","glob","glob","error","inquirer","error","inquirer","fsExtra","join","dirname","relative","ensureDir","readdir","fsExtra","join","dirname","error","relative","execSync","execSync","error","inquirer","success","getTemplatePath","__filename","fileURLToPath","__dirname","dirname","existsSync","fsExtra","join","error","targetDir","__filename","fileURLToPath","__dirname","dirname","join","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/project.ts","../src/generators/template.ts","../src/utils/fs.ts","../src/utils/logger.ts","../src/generators/post-setup.ts","../src/commands/setup.ts","../src/prompts/setup.ts","../src/generators/tools/direnv.ts","../src/generators/tools/dotenvx.ts","../src/utils/package-json.ts","../src/generators/tools/volta.ts","../src/generators/tools/biome.ts","../src/generators/tools/husky.ts","../src/commands/add.ts","../src/prompts/add.ts","../src/generators/partials/packages.ts","../src/utils/merger.ts","../src/utils/package-json-merger.ts","../src/generators/partials/apps.ts","../src/generators/partials/config.ts","../src/commands/sync.ts","../src/generators/sync.ts","../src/prompts/sync.ts","../src/utils/backup.ts","../src/utils/git.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { createCommand } from \"./commands/create.js\";\nimport { setupCommand } from \"./commands/setup.js\";\nimport { addCommand } from \"./commands/add.js\";\nimport { syncCommand } from \"./commands/sync.js\";\n\n// package.jsonからバージョン情報を読み込み\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJsonPath = join(__dirname, \"../package.json\");\nconst packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n\nconst program = new Command();\n\nprogram\n .name(\"create-einja-app\")\n .description(\"CLI tool to create new projects with Einja Management Template\")\n .version(packageJson.version);\n\n// createコマンド\nprogram\n .argument(\"[project-name]\", \"Project name\")\n .option(\"--skip-git\", \"Skip git initialization\")\n .option(\"--skip-install\", \"Skip package installation\")\n .action(\n async (\n projectName: string | undefined,\n options: {\n skipGit?: boolean;\n skipInstall?: boolean;\n }\n ) => {\n await createCommand(projectName, options);\n }\n );\n\n// setupコマンド\nprogram\n .command(\"setup\")\n .description(\"Setup tools for existing project\")\n .action(async () => {\n await setupCommand();\n });\n\n// addコマンド\nprogram\n .command(\"add\")\n .description(\"Add einja components to existing monorepo\")\n .option(\"--all\", \"Select all components\")\n .option(\"--dry-run\", \"Preview changes without making them\")\n .action(\n async (options: { all?: boolean; dryRun?: boolean }) => {\n await addCommand({\n skipPrompts: options.all || false,\n dryRun: options.dryRun || false,\n });\n }\n );\n\n// syncコマンド\nprogram\n .command(\"sync\")\n .description(\"Sync template files to existing project\")\n .option(\"--categories <categories>\", \"Comma-separated list of categories to sync\")\n .option(\"--all\", \"Sync all categories\")\n .option(\"--dry-run\", \"Preview changes without making them\")\n .option(\"--backup\", \"Create backup before syncing (default: true)\", true)\n .option(\"--rollback\", \"Rollback to previous backup\")\n .option(\"--force\", \"Force sync even with uncommitted changes\")\n .action(\n async (options: {\n categories?: string;\n all?: boolean;\n dryRun?: boolean;\n backup?: boolean;\n rollback?: boolean;\n force?: boolean;\n }) => {\n await syncCommand({\n categories: options.categories?.split(\",\"),\n all: options.all || false,\n dryRun: options.dryRun || false,\n backup: options.backup !== false, // デフォルトtrue\n rollback: options.rollback || false,\n force: options.force || false,\n });\n }\n );\n\nprogram.parse();\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport ora from \"ora\";\nimport { promptProjectConfig, type ProjectConfig } from \"../prompts/project.js\";\nimport { generateTemplate } from \"../generators/template.js\";\nimport { execPostSetup } from \"../generators/post-setup.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * ディレクトリが空かどうかを確認\n * @param dirPath - ディレクトリパス\n * @returns 空の場合true、存在しないかファイルがある場合false\n */\nfunction isDirectoryEmpty(dirPath: string): boolean {\n if (!existsSync(dirPath)) {\n return true;\n }\n const files = readdirSync(dirPath);\n // .git, .DS_Store などの隠しファイルは無視(空のGitリポジトリは空とみなす)\n const significantFiles = files.filter(\n (f) => !f.startsWith(\".\")\n );\n return significantFiles.length === 0;\n}\n\n/**\n * CreateOptions型\n * createコマンドのオプション\n */\ninterface CreateOptions {\n skipGit?: boolean;\n skipInstall?: boolean;\n yes?: boolean;\n}\n\n/**\n * プロジェクト名のバリデーション\n * @param projectName - プロジェクト名\n * @returns エラーメッセージ(問題なければundefined)\n */\nfunction validateProjectName(projectName: string): string | undefined {\n const regex = /^[a-zA-Z][a-zA-Z0-9_-]{0,49}$/;\n if (!regex.test(projectName)) {\n return \"プロジェクト名は英字で始まり、英数字・ハイフン・アンダースコアのみ使用できます(1〜50文字)\";\n }\n return undefined;\n}\n\n/**\n * プロジェクトディレクトリの存在確認\n * @param targetPath - ターゲットパス\n * @returns 存在する場合true\n */\nfunction checkProjectExists(targetPath: string): boolean {\n return existsSync(targetPath);\n}\n\n\n/**\n * createコマンドの実装\n * @param projectName - プロジェクト名(オプション)\n * @param options - コマンドオプション\n */\nexport async function createCommand(\n projectName: string | undefined,\n options: CreateOptions\n): Promise<void> {\n try {\n // プロンプトで設定収集\n let config: ProjectConfig;\n\n if (options.yes && projectName) {\n // --yes オプション: デフォルト値を使用\n const error = validateProjectName(projectName);\n if (error) {\n logger.error(error);\n process.exit(1);\n }\n\n config = {\n projectName,\n packageScope: \"@repo\",\n template: \"default\",\n authMethod: \"default\",\n tools: {\n direnv: true,\n dotenvx: true,\n volta: true,\n biome: true,\n husky: true,\n },\n setupEinjaCli: true,\n worktreeConfig: undefined,\n useCurrentDir: false,\n };\n\n logger.info(`プロジェクト名: ${config.projectName}`);\n logger.info(`テンプレート: ${config.template}`);\n logger.info(`認証方式: ${config.authMethod}`);\n } else {\n // 対話式プロンプト\n config = await promptProjectConfig(projectName);\n }\n\n // ターゲットパスの解決\n const targetPath = config.useCurrentDir\n ? process.cwd()\n : resolve(process.cwd(), config.projectName);\n\n // ディレクトリの確認\n if (config.useCurrentDir) {\n // カレントディレクトリに展開する場合、空かどうか確認\n if (!isDirectoryEmpty(targetPath)) {\n logger.error(\"現在のディレクトリにファイルが存在します\");\n logger.info(\"空のディレクトリで実行するか、サブディレクトリを作成してください\");\n process.exit(1);\n }\n } else {\n // サブディレクトリを作成する場合、存在確認\n if (checkProjectExists(targetPath)) {\n logger.error(`ディレクトリ '${config.projectName}' は既に存在します`);\n logger.info(\"別の名前を指定するか、既存ディレクトリを削除してください\");\n process.exit(1);\n }\n }\n\n // テンプレート展開\n const spinner = ora(\"プロジェクトを作成中...\").start();\n\n try {\n await generateTemplate(config, targetPath);\n spinner.succeed(\"プロジェクトを作成しました\");\n } catch (error) {\n spinner.fail(\"プロジェクトの作成に失敗しました\");\n throw error;\n }\n\n // 生成後セットアップ実行\n await execPostSetup(config, targetPath, {\n skipGit: options.skipGit,\n skipInstall: options.skipInstall,\n });\n } catch (error) {\n logger.error(\"エラーが発生しました:\");\n if (error instanceof Error) {\n logger.error(error.message);\n } else {\n logger.error(String(error));\n }\n process.exit(1);\n }\n}\n","import inquirer from \"inquirer\";\nimport type { ProjectConfig, WorktreeConfig, App } from \"../types/index.js\";\n\nexport type { ProjectConfig, WorktreeConfig, App };\n\n/**\n * プロジェクト作成用プロンプトを実行\n * @param defaultProjectName - デフォルトのプロジェクト名\n * @returns ProjectConfig - プロジェクト設定\n */\nexport async function promptProjectConfig(\n defaultProjectName?: string\n): Promise<ProjectConfig> {\n const answers = await inquirer.prompt([\n {\n type: \"input\",\n name: \"projectName\",\n message: \"プロジェクト名:\",\n default: defaultProjectName || \"my-project\",\n validate: (input: string): boolean | string => {\n // 英数字・ハイフン・アンダースコアのみ許可、先頭は英字、1〜50文字\n const regex = /^[a-zA-Z][a-zA-Z0-9_-]{0,49}$/;\n if (!regex.test(input)) {\n return \"プロジェクト名は英字で始まり、英数字・ハイフン・アンダースコアのみ使用できます(1〜50文字)\";\n }\n return true;\n },\n },\n {\n type: \"confirm\",\n name: \"useCurrentDir\",\n message: \"今いるディレクトリに直接作成しますか?(Noならサブディレクトリを作成)\",\n default: false,\n },\n {\n type: \"input\",\n name: \"packageScope\",\n message: \"パッケージスコープ:\",\n default: \"@repo\",\n validate: (input: string): boolean | string => {\n // @で始まり、英数字・ハイフン・アンダースコアのみ許可\n const regex = /^@[a-zA-Z][a-zA-Z0-9_-]{0,49}$/;\n if (!regex.test(input)) {\n return \"パッケージスコープは@で始まり、英数字・ハイフン・アンダースコアのみ使用できます\";\n }\n return true;\n },\n },\n {\n type: \"list\",\n name: \"authMethod\",\n message: \"認証機能:\",\n choices: [\n { name: \"NextAuth.js を使用\", value: \"default\" },\n { name: \"なし(認証ファイルを除外)\", value: \"none\" },\n ],\n default: \"default\",\n },\n {\n type: \"confirm\",\n name: \"setupEinjaCli\",\n message: \"@einja/dev-cli を自動セットアップしますか?\",\n default: true,\n },\n {\n type: \"confirm\",\n name: \"customizeWorktree\",\n message: \"Worktree設定をカスタマイズしますか?\",\n default: false,\n },\n ]);\n\n // ツールは全て有効(固定)\n const tools = {\n direnv: true,\n dotenvx: true,\n volta: true,\n biome: true,\n husky: true,\n };\n\n let worktreeConfig: WorktreeConfig | undefined;\n\n // Worktree設定カスタマイズ\n if (answers.customizeWorktree) {\n const worktreeAnswers = await inquirer.prompt([\n {\n type: \"input\",\n name: \"postgresPort\",\n message: \"PostgreSQLポート番号:\",\n default: \"25432\",\n validate: (input: string): boolean | string => {\n const port = Number.parseInt(input, 10);\n if (Number.isNaN(port) || port < 1024 || port > 65535) {\n return \"ポート番号は1024〜65535の範囲で指定してください\";\n }\n return true;\n },\n },\n {\n type: \"input\",\n name: \"containerName\",\n message: \"Dockerコンテナ名:\",\n default: `${answers.projectName}-postgres`,\n },\n {\n type: \"input\",\n name: \"appId\",\n message: \"アプリケーションID:\",\n default: \"web\",\n },\n {\n type: \"input\",\n name: \"portRangeStart\",\n message: \"アプリポート範囲開始:\",\n default: \"3000\",\n validate: (input: string): boolean | string => {\n const port = Number.parseInt(input, 10);\n if (Number.isNaN(port) || port < 1024 || port > 65535) {\n return \"ポート番号は1024〜65535の範囲で指定してください\";\n }\n return true;\n },\n },\n {\n type: \"input\",\n name: \"rangeSize\",\n message: \"ポート範囲サイズ:\",\n default: \"1000\",\n validate: (input: string): boolean | string => {\n const size = Number.parseInt(input, 10);\n if (Number.isNaN(size) || size < 1 || size > 10000) {\n return \"範囲サイズは1〜10000の範囲で指定してください\";\n }\n return true;\n },\n },\n ]);\n\n worktreeConfig = {\n postgres: {\n port: Number.parseInt(worktreeAnswers.postgresPort, 10),\n containerName: worktreeAnswers.containerName,\n },\n apps: [\n {\n id: worktreeAnswers.appId,\n portRangeStart: Number.parseInt(worktreeAnswers.portRangeStart, 10),\n rangeSize: Number.parseInt(worktreeAnswers.rangeSize, 10),\n },\n ],\n };\n }\n\n return {\n projectName: answers.projectName,\n packageScope: answers.packageScope,\n template: \"default\" as const,\n authMethod: answers.authMethod,\n tools,\n setupEinjaCli: answers.setupEinjaCli,\n worktreeConfig,\n useCurrentDir: answers.useCurrentDir,\n };\n}\n","import fsExtra from \"fs-extra\";\nconst { copySync, readFileSync, writeFileSync, existsSync, removeSync } = fsExtra;\nimport { glob } from \"glob\";\nimport { dirname, join, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ProjectConfig } from \"../prompts/project.js\";\nimport { ensureDir } from \"../utils/fs.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * TemplateVariables型\n * テンプレート変数(プレースホルダー置換用)\n */\nexport interface TemplateVariables {\n projectName: string;\n packageName: string;\n description: string;\n}\n\n/**\n * テンプレートディレクトリのパスを取得\n * @param templateName - テンプレート名\n * @returns テンプレートディレクトリパス\n */\nfunction getTemplatePath(templateName: string): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n\n // バンドル後(dist/cli.js)とソース実行(src/generators/template.ts)の両方に対応\n // dist/cli.js -> ../templates/ (1階層上)\n // src/generators/template.ts -> ../../templates/ (2階層上)\n const distPath = join(__dirname, \"../templates\", templateName);\n const srcPath = join(__dirname, \"../../templates\", templateName);\n\n if (existsSync(distPath)) {\n return distPath;\n }\n if (existsSync(srcPath)) {\n return srcPath;\n }\n\n // どちらも存在しない場合はdistPathを返す(エラーメッセージ用)\n return distPath;\n}\n\n/**\n * 認証方式に応じた除外パターンを取得\n * @param authMethod - 認証方式\n * @returns 除外パターン配列\n */\nfunction getAuthExcludePatterns(authMethod: string): string[] {\n if (authMethod === \"none\") {\n return [\n \"**/api/auth/**\",\n \"**/packages/auth/**\",\n \"**/signin/**\",\n \"**/signup/**\",\n ];\n }\n return [];\n}\n\n/**\n * ファイル内容のプレースホルダー変数を置換\n * @param content - ファイル内容\n * @param variables - 置換する変数\n * @returns 置換後の内容\n */\nfunction replacePlaceholders(\n content: string,\n variables: TemplateVariables\n): string {\n let result = content;\n\n // {{projectName}} の置換\n result = result.replaceAll(\"{{projectName}}\", variables.projectName);\n\n // {{packageName}}/ の置換(長いパターンを先に置換)\n result = result.replaceAll(\"{{packageName}}/\", `${variables.packageName}/`);\n\n // {{packageName}} の置換\n result = result.replaceAll(\"{{packageName}}\", variables.packageName);\n\n // {{description}} の置換\n result = result.replaceAll(\"{{description}}\", variables.description);\n\n // @repo/ の置換(パッケージスコープ)\n result = result.replaceAll(\"@repo/\", `${variables.packageName}/`);\n\n return result;\n}\n\n/**\n * ファイルの変数置換処理\n * @param filePath - ファイルパス\n * @param variables - 置換する変数\n */\nfunction processFileVariables(\n filePath: string,\n variables: TemplateVariables\n): void {\n // バイナリファイルは処理しない\n const binaryExtensions = [\".png\", \".jpg\", \".jpeg\", \".gif\", \".ico\", \".woff\", \".woff2\", \".ttf\", \".eot\"];\n if (binaryExtensions.some((ext) => filePath.endsWith(ext))) {\n return;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const replaced = replacePlaceholders(content, variables);\n\n if (content !== replaced) {\n writeFileSync(filePath, replaced, \"utf-8\");\n }\n } catch (error) {\n // 読み込みに失敗した場合はスキップ(バイナリファイル等)\n logger.warn(`変数置換をスキップ: ${filePath}`);\n }\n}\n\n/**\n * .templateファイルのリネーム処理\n * @param targetPath - ターゲットディレクトリパス\n */\nfunction renameTemplateFiles(targetPath: string): void {\n const templateFiles = glob.sync(\"**/*.template\", {\n cwd: targetPath,\n absolute: true,\n dot: true,\n });\n\n for (const file of templateFiles) {\n const newPath = file.replace(/\\.template$/, \"\");\n copySync(file, newPath);\n removeSync(file);\n }\n}\n\n/**\n * gitignoreファイルをリネーム処理(gitignore → .gitignore)\n * @param targetPath - ターゲットディレクトリパス\n */\nfunction renameSpecialFiles(targetPath: string): void {\n const gitignoreFiles = glob.sync(\"**/gitignore\", {\n cwd: targetPath,\n absolute: true,\n dot: true,\n });\n\n for (const file of gitignoreFiles) {\n const dir = dirname(file);\n const newPath = join(dir, \".gitignore\");\n\n if (existsSync(file)) {\n copySync(file, newPath);\n removeSync(file);\n }\n }\n}\n\n/**\n * 認証方式に応じたファイル除外処理\n * @param targetPath - ターゲットディレクトリパス\n * @param authMethod - 認証方式\n */\nfunction excludeAuthFiles(targetPath: string, authMethod: string): void {\n const excludePatterns = getAuthExcludePatterns(authMethod);\n\n if (excludePatterns.length === 0) {\n return;\n }\n\n logger.info(\"認証方式に応じたファイルを除外中...\");\n\n for (const pattern of excludePatterns) {\n const files = glob.sync(pattern, {\n cwd: targetPath,\n absolute: true,\n dot: true,\n });\n\n for (const file of files) {\n removeSync(file);\n }\n }\n}\n\n/**\n * テンプレートを展開\n * @param config - プロジェクト設定\n * @param targetPath - ターゲットディレクトリパス\n */\nexport async function generateTemplate(\n config: ProjectConfig,\n targetPath: string\n): Promise<void> {\n const templatePath = getTemplatePath(config.template);\n\n // テンプレートディレクトリの存在確認\n if (!existsSync(templatePath)) {\n throw new Error(`テンプレートが見つかりません: ${config.template}`);\n }\n\n logger.info(\"テンプレートをコピー中...\");\n\n // ターゲットディレクトリの作成\n await ensureDir(targetPath);\n\n // テンプレートファイルをコピー\n copySync(templatePath, targetPath, {\n filter: (src: string): boolean => {\n const relativePath = relative(templatePath, src);\n\n // 除外パターン(ディレクトリ名やファイル名として完全一致するもの)\n // 注意: .env.*ファイルはテンプレートに含め、pnpm env:updateで再設定する\n const excludePatterns = [\n \"node_modules\",\n \".git\",\n \".next\",\n \".turbo\",\n \"out\",\n \"dist\",\n \"logs\",\n \".env\", // フェイルセーフ(暗号化キーファイル)\n \".DS_Store\",\n \"Thumbs.db\",\n \"coverage\",\n ];\n\n // ファイル拡張子パターン(*.log など)\n const excludeExtensions = [\".log\"];\n\n // パスセグメントに分割(/ または \\ で分割)\n const pathSegments = relativePath.split(/[/\\\\]/);\n\n // パスセグメント単位で完全一致チェック\n // これにより \"out\" は \"out/\" ディレクトリにマッチするが\n // \"logout-button.tsx\" にはマッチしない\n const matchesExcludePattern = excludePatterns.some((pattern) =>\n pathSegments.includes(pattern)\n );\n\n // 拡張子チェック\n const matchesExtension = excludeExtensions.some((ext) =>\n relativePath.endsWith(ext)\n );\n\n return !matchesExcludePattern && !matchesExtension;\n },\n });\n\n // 認証方式に応じたファイル除外\n excludeAuthFiles(targetPath, config.authMethod);\n\n // .templateファイルのリネーム\n renameTemplateFiles(targetPath);\n\n // gitignore → .gitignore リネーム\n renameSpecialFiles(targetPath);\n\n // 変数置換\n logger.info(\"プレースホルダー変数を置換中...\");\n\n const variables: TemplateVariables = {\n projectName: config.projectName,\n packageName: config.packageScope,\n description: `${config.projectName} - Einja Management Template`,\n };\n\n const allFiles = glob.sync(\"**/*\", {\n cwd: targetPath,\n absolute: true,\n nodir: true,\n dot: true,\n });\n\n for (const file of allFiles) {\n processFileVariables(file, variables);\n }\n\n logger.success(\"テンプレート展開完了\");\n}\n","import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport type { ConflictStrategy } from \"../types/index.js\";\n\n/**\n * 競合戦略に基づいてファイルを書き込む\n */\nexport function writeWithStrategy(\n filePath: string,\n content: string,\n strategy: ConflictStrategy\n): boolean {\n const exists = existsSync(filePath);\n\n if (!exists) {\n ensureDir(dirname(filePath));\n writeFileSync(filePath, content, \"utf-8\");\n return true;\n }\n\n switch (strategy) {\n case \"overwrite\": {\n writeFileSync(filePath, content, \"utf-8\");\n return true;\n }\n\n case \"merge\": {\n const existingContent = readFileSync(filePath, \"utf-8\");\n const mergedContent = mergeContent(existingContent, content);\n writeFileSync(filePath, mergedContent, \"utf-8\");\n return true;\n }\n\n case \"skip\": {\n return false;\n }\n\n default: {\n const _exhaustiveCheck: never = strategy;\n throw new Error(`Unknown strategy: ${_exhaustiveCheck}`);\n }\n }\n}\n\n/**\n * 既存コンテンツと新規コンテンツをマージする\n */\nfunction mergeContent(existing: string, newContent: string): string {\n if (existing.includes(newContent)) {\n return existing;\n }\n return `${existing}\\n${newContent}`;\n}\n\n/**\n * ディレクトリが存在しない場合は作成する\n */\nexport function ensureDir(dirPath: string): void {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n}\n\n/**\n * .gitignoreに行を追加する\n */\nexport function appendToGitignore(targetDir: string, line: string): void {\n const gitignorePath = join(targetDir, \".gitignore\");\n\n if (!existsSync(gitignorePath)) {\n writeFileSync(gitignorePath, `${line}\\n`, \"utf-8\");\n return;\n }\n\n const content = readFileSync(gitignorePath, \"utf-8\");\n if (content.includes(line)) {\n return;\n }\n\n appendFileSync(gitignorePath, `\\n${line}\\n`, \"utf-8\");\n}\n\n/**\n * ファイルが存在するか確認する\n */\nexport function fileExists(filePath: string): boolean {\n return existsSync(filePath);\n}\n","import chalk from \"chalk\";\n\n/**\n * 情報メッセージを出力\n * @param message - メッセージ\n */\nexport function info(message: string): void {\n console.log(chalk.blue(\"ℹ\"), message);\n}\n\n/**\n * 成功メッセージを出力(緑色)\n * @param message - メッセージ\n */\nexport function success(message: string): void {\n console.log(chalk.green(\"✔\"), message);\n}\n\n/**\n * 警告メッセージを出力(黄色)\n * @param message - メッセージ\n */\nexport function warn(message: string): void {\n console.log(chalk.yellow(\"⚠\"), message);\n}\n\n/**\n * エラーメッセージを出力(赤色)\n * @param message - メッセージ\n */\nexport function error(message: string): void {\n console.error(chalk.red(\"✖\"), message);\n}\n","import { execa, execaSync } from \"execa\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport ora from \"ora\";\nimport type { ProjectConfig } from \"../types/index.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * PostSetupOptions型\n * 生成後セットアップのオプション\n */\nexport interface PostSetupOptions {\n skipGit?: boolean;\n skipInstall?: boolean;\n}\n\n/**\n * direnvコマンドが利用可能かチェック\n * @returns direnvコマンドが利用可能な場合true\n */\nfunction isDirenvAvailable(): boolean {\n try {\n execaSync(\"which\", [\"direnv\"]);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * direnv allowの確認プロンプトを表示し、実行する\n * @param targetPath - プロジェクトディレクトリ\n */\nasync function promptAndExecuteDirenvAllow(targetPath: string): Promise<void> {\n try {\n const { shouldAllow } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"shouldAllow\",\n message: \"direnv allow を実行しますか?(環境変数を有効化します)\",\n default: true,\n },\n ]);\n\n if (shouldAllow) {\n try {\n await execa(\"direnv\", [\"allow\"], { cwd: targetPath });\n logger.success(\"direnv allow を実行しました\");\n } catch (error) {\n logger.warn(\"direnv allow の実行に失敗しました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } else {\n logger.info(\"direnv allow をスキップしました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } catch (error) {\n logger.info(\"direnv allow をスキップしました\");\n }\n}\n\n/**\n * 完了メッセージを表示\n * @param config - プロジェクト設定\n */\nfunction printCompletionMessage(config: ProjectConfig): void {\n console.log();\n logger.success(\"プロジェクトの作成が完了しました!\");\n console.log();\n console.log(chalk.bold(\"次のステップ:\"));\n console.log();\n console.log(chalk.cyan(` cd ${config.projectName}`));\n console.log(chalk.cyan(\" pnpm env:update # 環境変数を設定\"));\n console.log(chalk.cyan(\" docker-compose up -d postgres\"));\n console.log(chalk.cyan(\" pnpm dev\"));\n console.log();\n console.log(\n chalk.yellow(\"⚠ セキュリティ: テンプレートの秘密鍵をそのまま使用しないでください\")\n );\n console.log(\n chalk.gray(\" pnpm env:rotate-secrets # 秘密鍵を自分のプロジェクト用に再生成\")\n );\n console.log();\n console.log(chalk.gray(\"開発サーバー: ターミナルに表示されるURLを確認\"));\n console.log();\n console.log(chalk.gray(\"詳細は README.md をご確認ください。\"));\n console.log();\n}\n\n/**\n * 生成後セットアップを実行\n * @param config - プロジェクト設定\n * @param targetPath - プロジェクトディレクトリ\n * @param options - セットアップオプション\n */\nexport async function execPostSetup(\n config: ProjectConfig,\n targetPath: string,\n options: PostSetupOptions\n): Promise<void> {\n const { skipGit, skipInstall } = options;\n\n // Git初期化\n if (!skipGit) {\n const gitSpinner = ora(\"Gitリポジトリを初期化中...\").start();\n try {\n await execa(\"git\", [\"init\"], { cwd: targetPath });\n await execa(\"git\", [\"add\", \".\"], { cwd: targetPath });\n await execa(\"git\", [\"commit\", \"-m\", \"Initial commit\"], { cwd: targetPath });\n gitSpinner.succeed(\"Gitリポジトリを初期化しました\");\n } catch (error) {\n gitSpinner.fail(\"Gitリポジトリの初期化に失敗しました\");\n logger.warn(\"後で手動で 'git init' を実行してください\");\n }\n }\n\n // 依存関係インストール\n if (!skipInstall) {\n const installSpinner = ora(\"依存関係をインストール中...\").start();\n try {\n await execa(\"pnpm\", [\"install\"], { cwd: targetPath });\n installSpinner.succeed(\"依存関係をインストールしました\");\n\n // Prismaクライアント生成\n const prismaSpinner = ora(\"Prismaクライアントを生成中...\").start();\n try {\n await execa(\"pnpm\", [\"db:generate\"], { cwd: targetPath });\n prismaSpinner.succeed(\"Prismaクライアントを生成しました\");\n } catch (error) {\n prismaSpinner.fail(\"Prismaクライアントの生成に失敗しました\");\n logger.warn(\"後で手動で 'pnpm db:generate' を実行してください\");\n }\n } catch (error) {\n installSpinner.fail(\"依存関係のインストールに失敗しました\");\n logger.warn(\"後で手動で 'pnpm install' を実行してください\");\n }\n }\n\n // direnv allow(direnvが有効で、コマンドが利用可能な場合)\n if (config.tools.direnv && isDirenvAvailable()) {\n await promptAndExecuteDirenvAllow(targetPath);\n }\n\n // @einja/dev-cli init\n if (config.setupEinjaCli) {\n const einjaSpinner = ora(\"@einja/dev-cli を初期化中...\").start();\n try {\n await execa(\"npx\", [\"@einja/dev-cli\", \"init\", \"--force\", \"--no-backup\"], { cwd: targetPath });\n einjaSpinner.succeed(\"@einja/dev-cli を初期化しました\");\n } catch (error) {\n einjaSpinner.fail(\"@einja/dev-cli の初期化に失敗しました\");\n logger.warn(\"後で手動で 'npx @einja/dev-cli init' を実行してください\");\n }\n }\n\n // 完了メッセージ表示\n printCompletionMessage(config);\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport ora from \"ora\";\nimport { promptSetupConfig } from \"../prompts/setup.js\";\nimport {\n setupDirenv,\n setupDotenvx,\n setupVolta,\n setupBiome,\n setupHusky,\n promptDirenvAllow,\n} from \"../generators/tools/index.js\";\nimport type { ToolSetupOptions } from \"../types/index.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * setupコマンド - 既存プロジェクトへのツール追加\n *\n * US-002: 既存プロジェクトへの環境ツール追加\n * AC-002-1: `npx create-einja-app --setup` で対話式プロンプトが表示される\n * AC-002-2: 既存の設定ファイルがある場合、マージ・上書き・スキップを選択できる\n * AC-002-3: 選択したツールのみがセットアップされる\n * AC-002-4: 既存ファイルを破壊せずにツールが追加される(マージモード時)\n */\nexport async function setupCommand(): Promise<void> {\n const targetDir = process.cwd();\n\n // 1. プロジェクトディレクトリ確認(package.json存在確認)\n const packageJsonPath = join(targetDir, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n logger.error(\"エラー: package.jsonが見つかりません\");\n logger.info(\"このコマンドは既存のプロジェクトディレクトリで実行してください\");\n process.exit(1);\n }\n\n logger.info(\"既存プロジェクトへのツール追加を開始します\");\n logger.info(\"\");\n\n // 2. プロンプトで設定収集\n const config = await promptSetupConfig();\n\n logger.info(\"\");\n logger.info(\"セットアップを開始します...\");\n logger.info(\"\");\n\n const options: ToolSetupOptions = {\n targetDir,\n conflictStrategy: config.conflictStrategy,\n };\n\n // 3. 選択されたツールのセットアップ\n let setupCount = 0;\n\n if (config.tools.direnv) {\n const spin = ora(\"direnv をセットアップしています...\").start();\n try {\n setupDirenv(options);\n spin.succeed(\"direnv セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"direnv セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.dotenvx) {\n const spin = ora(\"dotenvx をセットアップしています...\").start();\n try {\n setupDotenvx(options);\n spin.succeed(\"dotenvx セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"dotenvx セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.volta) {\n const spin = ora(\"Volta をセットアップしています...\").start();\n try {\n setupVolta(options);\n spin.succeed(\"Volta セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"Volta セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.biome) {\n const spin = ora(\"Biome をセットアップしています...\").start();\n try {\n setupBiome(options);\n spin.succeed(\"Biome セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"Biome セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n if (config.tools.husky) {\n const spin = ora(\"Husky をセットアップしています...\").start();\n try {\n setupHusky(options);\n spin.succeed(\"Husky セットアップ完了\");\n setupCount++;\n } catch (error) {\n spin.fail(\"Husky セットアップ失敗\");\n logger.error(\n error instanceof Error ? error.message : \"予期しないエラーが発生しました\"\n );\n }\n }\n\n logger.info(\"\");\n\n // 4. direnv allowの確認プロンプト(direnvがセットアップされた場合のみ)\n if (config.tools.direnv) {\n await promptDirenvAllow(targetDir);\n logger.info(\"\");\n }\n\n // 5. 完了メッセージ\n logger.success(`✅ セットアップが完了しました!(${setupCount}個のツール)`);\n logger.info(\"\");\n logger.info(\"次のステップ:\");\n\n if (config.tools.direnv) {\n logger.info(\" 1. .envrc を編集して環境変数を設定\");\n logger.info(\" 2. direnv allow を実行(まだの場合)\");\n }\n\n if (config.tools.dotenvx) {\n logger.info(\" - .env.example をコピーして .env を作成\");\n logger.info(\" - 必要に応じて pnpm env:encrypt で暗号化\");\n }\n\n if (config.tools.biome) {\n logger.info(\" - pnpm lint でコードをチェック\");\n logger.info(\" - pnpm format:fix でフォーマット\");\n }\n\n if (config.tools.husky) {\n logger.info(\" - pnpm install でHuskyフックをインストール\");\n }\n\n logger.info(\"\");\n logger.success(\"開発を開始できます!\");\n}\n","import inquirer from \"inquirer\";\n\n/**\n * SetupConfig型\n * 既存プロジェクトへのツール追加設定\n */\nexport interface SetupConfig {\n tools: {\n direnv: boolean;\n dotenvx: boolean;\n volta: boolean;\n biome: boolean;\n husky: boolean;\n };\n conflictStrategy: \"merge\" | \"overwrite\" | \"skip\";\n}\n\n/**\n * セットアップ用プロンプトを実行\n * @returns SetupConfig - セットアップ設定\n */\nexport async function promptSetupConfig(): Promise<SetupConfig> {\n const answers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"tools\",\n message: \"セットアップするツールを選択(複数選択可):\",\n choices: [\n {\n name: \"direnv(ディレクトリごとの環境変数管理)\",\n value: \"direnv\",\n checked: true,\n },\n {\n name: \"dotenvx(.env暗号化)\",\n value: \"dotenvx\",\n checked: true,\n },\n {\n name: \"Volta(Node.jsバージョン管理)\",\n value: \"volta\",\n checked: true,\n },\n {\n name: \"Biome(Linter / Formatter)\",\n value: \"biome\",\n checked: false,\n },\n {\n name: \"Husky + lint-staged(Git hooks)\",\n value: \"husky\",\n checked: false,\n },\n ],\n },\n {\n type: \"list\",\n name: \"conflictStrategy\",\n message: \"既存ファイルがある場合の動作:\",\n choices: [\n {\n name: \"マージ(既存設定を保持しつつ追加)\",\n value: \"merge\",\n },\n {\n name: \"上書き\",\n value: \"overwrite\",\n },\n {\n name: \"スキップ\",\n value: \"skip\",\n },\n ],\n default: \"merge\",\n },\n ]);\n\n // ツール選択を boolean フラグに変換\n const toolsArray = answers.tools as string[];\n const tools = {\n direnv: toolsArray.includes(\"direnv\"),\n dotenvx: toolsArray.includes(\"dotenvx\"),\n volta: toolsArray.includes(\"volta\"),\n biome: toolsArray.includes(\"biome\"),\n husky: toolsArray.includes(\"husky\"),\n };\n\n return {\n tools,\n conflictStrategy: answers.conflictStrategy,\n };\n}\n","import { join } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport inquirer from \"inquirer\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy, appendToGitignore } from \"../../utils/fs.js\";\nimport * as logger from \"../../utils/logger.js\";\n\nconst ENVRC_CONTENT = `# direnv configuration\n# Load .env if it exists\ndotenv_if_exists\n\n# Allow local overrides\ndotenv_if_exists .env.local\n`;\n\nconst ENVRC_EXAMPLE_CONTENT = `# Example direnv configuration\n# Copy this file to .envrc and run 'direnv allow'\n\n# Load environment variables from .env\ndotenv_if_exists\n\n# Load local overrides\ndotenv_if_exists .env.local\n`;\n\n/**\n * direnvのセットアップを実行する\n *\n * AC-003-1: .envrc ファイルが生成される\n * AC-003-2: .envrc.example ファイルが生成される\n * AC-003-3: .gitignore に .envrc が追加される\n */\nexport function setupDirenv(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n const envrcPath = join(targetDir, \".envrc\");\n const envrcExamplePath = join(targetDir, \".envrc.example\");\n\n writeWithStrategy(envrcPath, ENVRC_CONTENT, conflictStrategy);\n\n writeWithStrategy(envrcExamplePath, ENVRC_EXAMPLE_CONTENT, conflictStrategy);\n\n appendToGitignore(targetDir, \".envrc\");\n}\n\n/**\n * direnv allowの確認プロンプトを表示し、実行する\n *\n * AC-003-4: 確認後 `direnv allow` が実行される\n *\n * @param targetDir - ターゲットディレクトリ\n */\nexport async function promptDirenvAllow(targetDir: string): Promise<void> {\n try {\n const { shouldAllow } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"shouldAllow\",\n message: \"direnv allow を実行しますか?(環境変数を有効化します)\",\n default: true,\n },\n ]);\n\n if (shouldAllow) {\n try {\n execSync(\"direnv allow\", { cwd: targetDir, stdio: \"inherit\" });\n logger.success(\"direnv allow を実行しました\");\n } catch (error) {\n logger.warn(\"direnv allow の実行に失敗しました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } else {\n logger.info(\"direnv allow をスキップしました\");\n logger.info(\"後で手動で 'direnv allow' を実行してください\");\n }\n } catch (error) {\n // プロンプトがキャンセルされた場合など\n logger.info(\"direnv allow をスキップしました\");\n }\n}\n","import { join } from \"node:path\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy } from \"../../utils/fs.js\";\nimport { addDependencies, addScripts } from \"../../utils/package-json.js\";\n\nconst ENV_EXAMPLE_CONTENT = `# Environment variables template\n# Copy this file to .env and fill in the values\n\n# Database\nDATABASE_URL=\"postgresql://user:password@localhost:25432/dbname\"\n\n# NextAuth\nNEXTAUTH_URL=\"http://localhost:3000\"\nNEXTAUTH_SECRET=\"your-secret-here\"\n\n# OAuth (if using)\n# GOOGLE_CLIENT_ID=\"\"\n# GOOGLE_CLIENT_SECRET=\"\"\n# GITHUB_CLIENT_ID=\"\"\n# GITHUB_CLIENT_SECRET=\"\"\n`;\n\n/**\n * dotenvxのセットアップを実行する\n *\n * AC-004-1: package.jsonに依存関係が追加される\n * AC-004-2: npm scriptsにdotenvxコマンドが追加される\n * AC-004-3: .env.example が生成される\n */\nexport function setupDotenvx(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n addDependencies(targetDir, {\n \"@dotenvx/dotenvx\": \"^1.29.0\",\n });\n\n addScripts(targetDir, {\n \"env:encrypt\": \"dotenvx encrypt\",\n \"env:decrypt\": \"dotenvx decrypt\",\n });\n\n const envExamplePath = join(targetDir, \".env.example\");\n writeWithStrategy(envExamplePath, ENV_EXAMPLE_CONTENT, conflictStrategy);\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileExists } from \"./fs.js\";\n\ntype PackageJson = {\n name?: string;\n version?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n volta?: {\n node?: string;\n pnpm?: string;\n };\n \"lint-staged\"?: Record<string, string | string[]>;\n [key: string]: unknown;\n};\n\n/**\n * package.jsonを読み込む\n */\nexport function readPackageJson(targetDir: string): PackageJson {\n const packageJsonPath = join(targetDir, \"package.json\");\n\n if (!fileExists(packageJsonPath)) {\n return {};\n }\n\n const content = readFileSync(packageJsonPath, \"utf-8\");\n return JSON.parse(content) as PackageJson;\n}\n\n/**\n * package.jsonに書き込む\n */\nexport function writePackageJson(targetDir: string, data: PackageJson): void {\n const packageJsonPath = join(targetDir, \"package.json\");\n const content = JSON.stringify(data, null, 2);\n writeFileSync(packageJsonPath, `${content}\\n`, \"utf-8\");\n}\n\n/**\n * package.jsonにスクリプトを追加する\n */\nexport function addScripts(\n targetDir: string,\n scripts: Record<string, string>\n): void {\n const pkg = readPackageJson(targetDir);\n pkg.scripts = { ...pkg.scripts, ...scripts };\n writePackageJson(targetDir, pkg);\n}\n\n/**\n * package.jsonに依存関係を追加する\n */\nexport function addDependencies(\n targetDir: string,\n dependencies: Record<string, string>,\n dev = false\n): void {\n const pkg = readPackageJson(targetDir);\n\n if (dev) {\n pkg.devDependencies = { ...pkg.devDependencies, ...dependencies };\n } else {\n pkg.dependencies = { ...pkg.dependencies, ...dependencies };\n }\n\n writePackageJson(targetDir, pkg);\n}\n\n/**\n * package.jsonにVoltaフィールドを追加する\n */\nexport function addVoltaField(\n targetDir: string,\n nodeVersion: string,\n pnpmVersion: string\n): void {\n const pkg = readPackageJson(targetDir);\n pkg.volta = {\n node: nodeVersion,\n pnpm: pnpmVersion,\n };\n writePackageJson(targetDir, pkg);\n}\n\n/**\n * package.jsonにlint-staged設定を追加する\n */\nexport function addLintStaged(\n targetDir: string,\n config: Record<string, string | string[]>\n): void {\n const pkg = readPackageJson(targetDir);\n pkg[\"lint-staged\"] = { ...pkg[\"lint-staged\"], ...config };\n writePackageJson(targetDir, pkg);\n}\n","import { join } from \"node:path\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy } from \"../../utils/fs.js\";\nimport { addVoltaField } from \"../../utils/package-json.js\";\n\nconst NODE_VERSION = \"22.16.0\";\nconst PNPM_VERSION = \"9.15.0\";\n\nconst NODE_VERSION_CONTENT = `${NODE_VERSION}\n`;\n\n/**\n * Voltaのセットアップを実行する\n *\n * AC-005-1: package.jsonにvoltaフィールドが追加される\n * AC-005-2: .node-version ファイルが生成される\n */\nexport function setupVolta(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n addVoltaField(targetDir, NODE_VERSION, PNPM_VERSION);\n\n const nodeVersionPath = join(targetDir, \".node-version\");\n writeWithStrategy(nodeVersionPath, NODE_VERSION_CONTENT, conflictStrategy);\n}\n","import { join } from \"node:path\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { writeWithStrategy, ensureDir } from \"../../utils/fs.js\";\nimport { addDependencies, addScripts } from \"../../utils/package-json.js\";\n\nconst BIOME_CONFIG = `{\n \"$schema\": \"https://biomejs.dev/schemas/1.9.4/schema.json\",\n \"vcs\": {\n \"enabled\": true,\n \"clientKind\": \"git\",\n \"useIgnoreFile\": true\n },\n \"files\": {\n \"ignoreUnknown\": false,\n \"ignore\": [\"node_modules\", \"dist\", \".next\", \"out\", \"build\", \"coverage\"]\n },\n \"formatter\": {\n \"enabled\": true,\n \"indentStyle\": \"space\",\n \"indentWidth\": 2,\n \"lineEnding\": \"lf\",\n \"lineWidth\": 100\n },\n \"organizeImports\": {\n \"enabled\": true\n },\n \"linter\": {\n \"enabled\": true,\n \"rules\": {\n \"recommended\": true\n }\n },\n \"javascript\": {\n \"formatter\": {\n \"quoteStyle\": \"double\",\n \"trailingCommas\": \"es5\",\n \"semicolons\": \"always\",\n \"arrowParentheses\": \"always\"\n }\n }\n}\n`;\n\nconst VSCODE_SETTINGS = `{\n \"editor.defaultFormatter\": \"biomejs.biome\",\n \"editor.formatOnSave\": true,\n \"editor.codeActionsOnSave\": {\n \"quickfix.biome\": \"explicit\",\n \"source.organizeImports.biome\": \"explicit\"\n },\n \"[javascript]\": {\n \"editor.defaultFormatter\": \"biomejs.biome\"\n },\n \"[typescript]\": {\n \"editor.defaultFormatter\": \"biomejs.biome\"\n },\n \"[json]\": {\n \"editor.defaultFormatter\": \"biomejs.biome\"\n }\n}\n`;\n\n/**\n * Biomeのセットアップを実行する(--setupモードのみ)\n *\n * AC-006-1: biome.json が生成される\n * AC-006-2: package.jsonにlint/formatスクリプトが追加される\n * AC-006-3: VSCode設定が追加される\n */\nexport function setupBiome(options: ToolSetupOptions): void {\n const { targetDir, conflictStrategy } = options;\n\n const biomeConfigPath = join(targetDir, \"biome.json\");\n writeWithStrategy(biomeConfigPath, BIOME_CONFIG, conflictStrategy);\n\n addDependencies(\n targetDir,\n {\n \"@biomejs/biome\": \"^1.9.4\",\n },\n true\n );\n\n addScripts(targetDir, {\n lint: \"biome lint .\",\n \"lint:fix\": \"biome lint --write .\",\n format: \"biome format .\",\n \"format:fix\": \"biome format --write .\",\n });\n\n const vscodeDir = join(targetDir, \".vscode\");\n ensureDir(vscodeDir);\n\n const vscodeSettingsPath = join(vscodeDir, \"settings.json\");\n writeWithStrategy(vscodeSettingsPath, VSCODE_SETTINGS, conflictStrategy);\n}\n","import { join } from \"node:path\";\nimport { writeFileSync } from \"node:fs\";\nimport type { ToolSetupOptions } from \"../../types/index.js\";\nimport { ensureDir } from \"../../utils/fs.js\";\nimport { addDependencies, addScripts, addLintStaged } from \"../../utils/package-json.js\";\n\nconst PRE_COMMIT_HOOK = `#!/usr/bin/env sh\n. \"$(dirname -- \"$0\")/_/husky.sh\"\n\npnpm lint-staged\n`;\n\n/**\n * Husky + lint-stagedのセットアップを実行する(--setupモードのみ)\n *\n * AC-007-1: .husky/ ディレクトリが生成される\n * AC-007-2: pre-commitフックが設定される\n * AC-007-3: lint-staged設定が追加される\n */\nexport function setupHusky(options: ToolSetupOptions): void {\n const { targetDir } = options;\n\n addDependencies(\n targetDir,\n {\n husky: \"^9.1.7\",\n \"lint-staged\": \"^15.2.11\",\n },\n true\n );\n\n addScripts(targetDir, {\n prepare: \"husky\",\n });\n\n addLintStaged(targetDir, {\n \"*.{js,jsx,ts,tsx}\": [\"biome format --write\", \"biome lint --write\"],\n \"*.{json,md,yml,yaml}\": [\"biome format --write\"],\n });\n\n const huskyDir = join(targetDir, \".husky\");\n ensureDir(huskyDir);\n\n const preCommitPath = join(huskyDir, \"pre-commit\");\n writeFileSync(preCommitPath, PRE_COMMIT_HOOK, { mode: 0o755 });\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport ora from \"ora\";\nimport {\n promptAddConfig,\n getDefaultAddConfig,\n} from \"../prompts/add.js\";\nimport type { AddConfig, AddOptions, SyncMetadata } from \"../types/index.js\";\nimport { addPackages } from \"../generators/partials/packages.js\";\nimport { addApps } from \"../generators/partials/apps.js\";\nimport { addConfigFiles } from \"../generators/partials/config.js\";\nimport {\n loadSyncMetadata,\n saveSyncMetadata,\n} from \"../utils/merger.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * AddCommandOptions型\n * addコマンドのオプション\n */\nexport interface AddCommandOptions {\n skipPrompts: boolean;\n dryRun: boolean;\n}\n\n/**\n * テンプレートディレクトリのパスを取得\n * @param templateName - テンプレート名\n * @returns テンプレートディレクトリパス\n */\nfunction getTemplatePath(templateName: string): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n\n // バンドル後(dist/cli.js)とソース実行(src/commands/add.ts)の両方に対応\n // dist/cli.js -> ../templates/ (1階層上)\n // src/commands/add.ts -> ../../templates/ (2階層上)\n const distPath = join(__dirname, \"../templates\", templateName);\n const srcPath = join(__dirname, \"../../templates\", templateName);\n\n if (existsSync(distPath)) {\n return distPath;\n }\n if (existsSync(srcPath)) {\n return srcPath;\n }\n\n // どちらも存在しない場合はdistPathを返す(エラーメッセージ用)\n return distPath;\n}\n\n/**\n * テンプレートから.einja-sync.jsonを読み込む\n * @param templateDir - テンプレートディレクトリパス\n * @returns SyncMetadata または null(ファイルが存在しない場合)\n */\nasync function loadTemplateSyncMetadata(\n templateDir: string\n): Promise<SyncMetadata | null> {\n const syncFilePath = join(templateDir, \".einja-sync.json\");\n try {\n const content = await readFile(syncFilePath, \"utf-8\");\n return JSON.parse(content) as SyncMetadata;\n } catch {\n return null;\n }\n}\n\n/**\n * テンプレートと既存のSyncMetadataをマージ\n * @param template - テンプレートのSyncMetadata\n * @param existing - 既存のSyncMetadata\n * @returns マージされたSyncMetadata\n */\nfunction mergeSyncMetadata(\n template: SyncMetadata | null,\n existing: SyncMetadata | null\n): SyncMetadata {\n const now = new Date().toISOString();\n\n // テンプレートのjsonPathsを優先的に使用\n const jsonPaths =\n template?.jsonPaths ?? existing?.jsonPaths ?? { managed: {}, seed: {} };\n\n return {\n version: template?.version ?? existing?.version ?? \"1.0.0\",\n lastSync: now,\n templateVersion: template?.templateVersion ?? \"1.0.0\",\n files: { ...(existing?.files ?? {}), ...(template?.files ?? {}) },\n jsonPaths,\n };\n}\n\n/**\n * addコマンドの実装\n * @param options - コマンドオプション\n */\nexport async function addCommand(options: AddCommandOptions): Promise<void> {\n try {\n // Given: カレントディレクトリをターゲットとする\n const targetDir = process.cwd();\n\n // Given: プロンプトまたはデフォルト設定を取得\n let config: AddConfig;\n\n if (options.skipPrompts) {\n // When: skipPromptsが有効な場合、デフォルト設定を使用\n config = getDefaultAddConfig();\n logger.info(\"デフォルト設定を使用します(すべてのコンポーネントを選択)\");\n } else {\n // When: 対話式プロンプトを実行\n config = await promptAddConfig(options.dryRun);\n }\n\n // Given: dry-runモードかどうかを設定に反映\n config.dryRun = options.dryRun;\n\n // When: dry-runモードの場合、プレビューを表示\n if (config.dryRun) {\n logger.warn(\"dry-runモード: 実際のファイル操作は行いません\");\n logger.info(\"\\n--- 追加予定のコンポーネント ---\");\n\n if (config.components.packages) {\n logger.info(\n `- packages/: ${config.packageComponents.join(\", \")}`\n );\n }\n\n if (config.components.apps) {\n logger.info(`- apps/: ${config.appComponents.join(\", \")}`);\n }\n\n if (config.components.config) {\n logger.info(\"- 直下設定ファイル: turbo.json, pnpm-workspace.yaml 等\");\n }\n\n logger.info(\"---\\n\");\n }\n\n // Given: テンプレートディレクトリのパスを取得\n const templateDir = getTemplatePath(\"default\");\n\n // Given: テンプレートディレクトリの存在確認\n if (!existsSync(templateDir)) {\n throw new Error(\"テンプレートが見つかりません: default\");\n }\n\n // Given: テンプレートのSyncMetadataを読み込む\n const templateMetadata = await loadTemplateSyncMetadata(templateDir);\n\n // Given: 既存のSyncMetadataを読み込む\n const existingMetadata = await loadSyncMetadata(targetDir);\n\n // When: テンプレートと既存のメタデータをマージ\n const syncMetadata = mergeSyncMetadata(templateMetadata, existingMetadata);\n\n // Given: AddOptionsを構築\n const addOptions: AddOptions = {\n targetDir,\n templateDir,\n config,\n };\n\n let totalAdded = 0;\n let totalMerged = 0;\n let totalSkipped = 0;\n\n // When: packages を追加\n if (config.components.packages && config.packageComponents.length > 0) {\n const spinner = ora(\"パッケージを追加中...\").start();\n\n try {\n const result = await addPackages(\n addOptions,\n config.packageComponents,\n syncMetadata\n );\n\n totalAdded += result.added.length;\n totalMerged += result.merged.length;\n totalSkipped += result.skipped.length;\n\n spinner.succeed(\n `パッケージを追加しました(追加: ${result.added.length}, マージ: ${result.merged.length}, スキップ: ${result.skipped.length})`\n );\n } catch (error) {\n spinner.fail(\"パッケージの追加に失敗しました\");\n throw error;\n }\n }\n\n // When: apps を追加\n if (config.components.apps && config.appComponents.length > 0) {\n const spinner = ora(\"アプリを追加中...\").start();\n\n try {\n const result = await addApps(\n addOptions,\n config.appComponents,\n syncMetadata\n );\n\n totalAdded += result.added.length;\n totalMerged += result.merged.length;\n totalSkipped += result.skipped.length;\n\n spinner.succeed(\n `アプリを追加しました(追加: ${result.added.length}, マージ: ${result.merged.length}, スキップ: ${result.skipped.length})`\n );\n } catch (error) {\n spinner.fail(\"アプリの追加に失敗しました\");\n throw error;\n }\n }\n\n // When: config を追加\n if (config.components.config) {\n const spinner = ora(\"設定ファイルを追加中...\").start();\n\n try {\n const result = await addConfigFiles(addOptions, syncMetadata);\n\n totalAdded += result.added.length;\n totalMerged += result.merged.length;\n totalSkipped += result.skipped.length;\n\n spinner.succeed(\n `設定ファイルを追加しました(追加: ${result.added.length}, マージ: ${result.merged.length}, スキップ: ${result.skipped.length})`\n );\n } catch (error) {\n spinner.fail(\"設定ファイルの追加に失敗しました\");\n throw error;\n }\n }\n\n // When: SyncMetadataを更新して保存\n if (!config.dryRun) {\n syncMetadata.lastSync = new Date().toISOString();\n await saveSyncMetadata(targetDir, syncMetadata);\n }\n\n // Then: 結果サマリーを表示\n logger.success(\"\\n✓ 追加完了!\\n\");\n\n if (config.dryRun) {\n logger.info(\"(dry-runモードのため、実際の変更は行われていません)\\n\");\n }\n\n logger.info(`追加されたファイル: ${totalAdded}個`);\n logger.info(`マージされたファイル: ${totalMerged}個`);\n logger.info(`スキップされたファイル: ${totalSkipped}個\\n`);\n\n // When: @einja/cliがインストールされていない場合、案内メッセージを表示\n const packageJsonPath = join(targetDir, \"package.json\");\n if (existsSync(packageJsonPath)) {\n const packageJson = await import(packageJsonPath, {\n assert: { type: \"json\" },\n });\n\n const hasEinjaCli =\n packageJson.default?.devDependencies?.[\"@einja/dev-cli\"] ||\n packageJson.default?.dependencies?.[\"@einja/dev-cli\"];\n\n if (!hasEinjaCli) {\n logger.info(\"次のステップ:\");\n logger.info(\"1. pnpm install\");\n logger.info(\"2. pnpm dev:setup\");\n logger.info(\"\\n推奨:\");\n logger.info(\" einja開発支援CLI (@einja/dev-cli) のインストール:\");\n logger.info(\" pnpm add -D @einja/dev-cli\\n\");\n } else {\n logger.info(\"次のステップ:\");\n logger.info(\"1. pnpm install\");\n logger.info(\"2. pnpm dev:setup\\n\");\n }\n } else {\n logger.info(\"次のステップ:\");\n logger.info(\"1. pnpm install\");\n logger.info(\"2. pnpm dev:setup\\n\");\n }\n } catch (error) {\n logger.error(\"エラーが発生しました:\");\n if (error instanceof Error) {\n logger.error(error.message);\n } else {\n logger.error(String(error));\n }\n process.exit(1);\n }\n}\n","import inquirer from \"inquirer\";\nimport type {\n AddConfig,\n PackageComponent,\n AppComponent,\n} from \"../types/index.js\";\n\n/**\n * デフォルトの追加設定を取得\n * skipPrompts=true 時に使用\n */\nexport function getDefaultAddConfig(): AddConfig {\n return {\n components: {\n packages: true,\n apps: true,\n config: true,\n },\n packageComponents: [\"front-core\", \"server-core\", \"config\", \"ui\"],\n appComponents: [\"web\"],\n dryRun: false,\n };\n}\n\n/**\n * 追加用プロンプトを実行\n * @param dryRun - dry-runモードかどうか\n * @returns AddConfig - 追加設定\n */\nexport async function promptAddConfig(dryRun: boolean): Promise<AddConfig> {\n // ステージ1: コンポーネント種別選択\n const componentAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"components\",\n message: \"追加するコンポーネントを選択(Spaceで選択、Enterで確定):\",\n choices: [\n {\n name: \"packages/ - 共通パッケージ(front-core, server-core, config, ui)\",\n value: \"packages\",\n checked: true,\n },\n {\n name: \"apps/ - アプリテンプレート\",\n value: \"apps\",\n checked: true,\n },\n {\n name: \"直下設定ファイル - turbo.json, pnpm-workspace.yaml 等\",\n value: \"config\",\n checked: true,\n },\n ],\n },\n ]);\n\n const selectedComponents = componentAnswers.components as string[];\n const hasPackages = selectedComponents.includes(\"packages\");\n const hasApps = selectedComponents.includes(\"apps\");\n const hasConfig = selectedComponents.includes(\"config\");\n\n // ステージ2: packages詳細選択\n let packageComponents: PackageComponent[] = [];\n if (hasPackages) {\n const packageAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"packages\",\n message: \"追加するパッケージを選択:\",\n choices: [\n {\n name: \"front-core - フロントエンド共通層(認証設定、hooks、utils)\",\n value: \"front-core\",\n checked: true,\n },\n {\n name: \"server-core - バックエンド共通層(Prisma、ドメインロジック)\",\n value: \"server-core\",\n checked: true,\n },\n {\n name: \"config - 共通設定(Biome, TypeScript, Panda CSS)\",\n value: \"config\",\n checked: true,\n },\n {\n name: \"ui - 共通UIコンポーネント(shadcn/ui)\",\n value: \"ui\",\n checked: true,\n },\n ],\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのパッケージを選択してください\";\n }\n return true;\n },\n },\n ]);\n packageComponents = packageAnswers.packages as PackageComponent[];\n }\n\n // ステージ3: apps詳細選択\n let appComponents: AppComponent[] = [];\n if (hasApps) {\n const appAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"apps\",\n message: \"追加するアプリを選択:\",\n choices: [\n {\n name: \"web - メイン管理画面アプリ(Next.js + App Router)\",\n value: \"web\",\n checked: true,\n },\n ],\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのアプリを選択してください\";\n }\n return true;\n },\n },\n ]);\n appComponents = appAnswers.apps as AppComponent[];\n }\n\n return {\n components: {\n packages: hasPackages,\n apps: hasApps,\n config: hasConfig,\n },\n packageComponents,\n appComponents,\n dryRun,\n };\n}\n","import { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n AddOptions,\n PackageComponent,\n SyncMetadata,\n} from \"../../types/index.js\";\nimport { mergeAndWriteFile } from \"../../utils/merger.js\";\nimport * as logger from \"../../utils/logger.js\";\n\n/**\n * packages/ ディレクトリにコンポーネントを追加\n */\nexport async function addPackages(\n options: AddOptions,\n components: PackageComponent[],\n syncMetadata: SyncMetadata\n): Promise<{ added: string[]; skipped: string[]; merged: string[] }> {\n const added: string[] = [];\n const skipped: string[] = [];\n const merged: string[] = [];\n\n const { targetDir, templateDir, config } = options;\n\n for (const component of components) {\n const componentName =\n component === \"front-core\"\n ? \"front-core\"\n : component === \"server-core\"\n ? \"server-core\"\n : component === \"config\"\n ? \"config\"\n : \"ui\";\n\n const srcDir = join(templateDir, \"packages\", componentName);\n const destDir = join(targetDir, \"packages\", componentName);\n\n logger.info(`Adding package component: ${componentName}`);\n\n await copyDirectory(\n srcDir,\n destDir,\n { added, skipped, merged },\n config.dryRun,\n syncMetadata\n );\n }\n\n return { added, skipped, merged };\n}\n\n/**\n * ディレクトリを再帰的にコピー\n */\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n result: { added: string[]; skipped: string[]; merged: string[] },\n dryRun: boolean,\n syncMetadata: SyncMetadata\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath, result, dryRun, syncMetadata);\n } else {\n if (!dryRun) {\n const mergeResult = await mergeAndWriteFile(\n srcPath,\n destPath,\n syncMetadata\n );\n\n if (mergeResult.action === \"created\") {\n result.added.push(destPath);\n } else if (mergeResult.action === \"skipped\") {\n result.skipped.push(destPath);\n } else if (mergeResult.action === \"merged\") {\n result.merged.push(destPath);\n }\n } else {\n // dry-runモードではスキップ\n result.skipped.push(destPath);\n }\n }\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport type { SyncMetadata, JsonPathsConfig } from \"../types/index.js\";\nimport { ensureDir } from \"./fs.js\";\nimport { mergePackageJsonDependencies } from \"./package-json-merger.js\";\nimport * as logger from \"./logger.js\";\n\n/**\n * マーカーベースのテキストマージを行う\n *\n * @param templateContent - テンプレートファイルの内容\n * @param existingContent - 既存ファイルの内容(存在しない場合はnull)\n * @returns マージ後の内容\n */\nexport function mergeTextWithMarkers(\n templateContent: string,\n existingContent: string | null\n): string {\n // Given: 既存ファイルが存在しない場合\n if (existingContent === null) {\n // When: テンプレートをそのまま使用\n return templateContent;\n }\n\n // Given: 既存ファイルとテンプレートの両方が存在する場合\n const templateSections = parseMarkers(templateContent);\n const localSections = parseMarkers(existingContent);\n\n // マーカーがなければ既存優先\n const hasMarkers = templateSections.some(\n (s) => s.type === \"managed\" || s.type === \"seed\"\n );\n if (!hasMarkers) {\n return existingContent;\n }\n\n // When: ID付きmanaged/seedセクションをMapで管理\n const templateManagedById = new Map<string, MarkerSection>();\n const templateSeedById = new Map<string, MarkerSection>();\n const templateManagedWithoutId: MarkerSection[] = [];\n const processedTemplateIds = new Set<string>();\n\n for (const section of templateSections) {\n if (section.type === \"managed\" && section.id) {\n templateManagedById.set(section.id, section);\n } else if (section.type === \"managed\") {\n templateManagedWithoutId.push(section);\n } else if (section.type === \"seed\" && section.id) {\n templateSeedById.set(section.id, section);\n }\n }\n\n // When: ローカルセクションを処理(ローカル側の順序を基準にする)\n const result: string[] = [];\n let managedWithoutIdIndex = 0;\n\n for (const localSection of localSections) {\n if (localSection.type === \"managed\") {\n const match = localSection.id ? templateManagedById.get(localSection.id) : undefined;\n if (localSection.id && match) {\n // IDマッチ → テンプレートで上書き\n processedTemplateIds.add(localSection.id);\n result.push(match.content);\n } else if (!localSection.id) {\n // IDなし → テンプレートの順序で上書き(残りがあれば使用)\n const noIdMatch = templateManagedWithoutId[managedWithoutIdIndex];\n if (noIdMatch) {\n result.push(noIdMatch.content);\n managedWithoutIdIndex += 1;\n } else {\n result.push(localSection.content);\n }\n }\n // ID付きでテンプレートにマッチなし → 削除(resultに追加しない)\n } else if (localSection.type === \"seed\") {\n // seed: ローカル優先\n if (localSection.id) {\n processedTemplateIds.add(localSection.id);\n }\n result.push(localSection.content);\n } else {\n // unmanaged: ローカル優先\n result.push(localSection.content);\n }\n }\n\n // When: テンプレートにのみ存在するID付きmanagedセクションを末尾に追加\n for (const [id, section] of templateManagedById) {\n if (!processedTemplateIds.has(id)) {\n // テンプレートにのみ存在するID付きmanagedセクションを追加\n result.push(section.content);\n }\n }\n\n // When: テンプレートにのみ存在するIDなしmanagedセクションを末尾に追加\n for (const section of templateManagedWithoutId.slice(managedWithoutIdIndex)) {\n result.push(section.content);\n }\n\n // When: テンプレートにのみ存在するID付きseedセクションを末尾に追加\n for (const [id, section] of templateSeedById) {\n if (!processedTemplateIds.has(id)) {\n // テンプレートにのみ存在するID付きseedセクションを追加\n result.push(section.content);\n }\n }\n\n // Then: ファイル先頭の空セクションのみ除去(セクション間の空行は保持)\n const firstElement = result[0];\n if (result.length > 0 && firstElement !== undefined && firstElement.length === 0) {\n result.shift();\n }\n return result.join(\"\\n\");\n}\n\n/**\n * JSONのディープマージを行う\n *\n * @param templateJson - テンプレートのJSON\n * @param existingJson - 既存のJSON(存在しない場合はnull)\n * @param jsonPaths - managed/seedパスの設定\n * @param filePath - ファイルパス(例: \"package.json\")\n * @returns マージ後のJSON\n */\nexport function mergeJson(\n templateJson: Record<string, unknown>,\n existingJson: Record<string, unknown> | null,\n jsonPaths: JsonPathsConfig,\n filePath = \"package.json\"\n): Record<string, unknown> {\n // Given: 既存JSONが存在しない場合\n if (existingJson === null) {\n // When: テンプレートをディープコピーして使用\n return JSON.parse(JSON.stringify(templateJson));\n }\n\n // When: ディープマージを実行\n return deepMergeWithPaths(\n templateJson,\n existingJson,\n jsonPaths,\n filePath,\n \"\"\n );\n}\n\n/**\n * パスを考慮したディープマージを行う\n *\n * @param template - テンプレートオブジェクト\n * @param existing - 既存オブジェクト\n * @param jsonPaths - managed/seedパスの設定\n * @param filePath - ファイルパス\n * @param currentPath - 現在のキーパス(例: \"scripts.dev\")\n * @returns マージ後のオブジェクト\n */\nfunction deepMergeWithPaths(\n template: Record<string, unknown>,\n existing: Record<string, unknown>,\n jsonPaths: JsonPathsConfig,\n filePath: string,\n currentPath: string\n): Record<string, unknown> {\n // 既存オブジェクトをディープコピー(参照を共有しないように)\n const result = JSON.parse(JSON.stringify(existing)) as Record<string, unknown>;\n\n for (const [key, templateValue] of Object.entries(template)) {\n const keyPath = currentPath ? `${currentPath}.${key}` : key;\n const existingValue = existing[key];\n\n // Given: このパスがmanagedに含まれるか確認\n if (isPathManaged(filePath, keyPath, jsonPaths)) {\n // Then: managedパスはテンプレート値でディープコピーして上書き\n result[key] = deepClone(templateValue);\n }\n // Given: このパスがseedに含まれるか確認\n else if (isPathSeed(filePath, keyPath, jsonPaths)) {\n // Given: seedパスでオブジェクトの場合、子キーもディープマージ\n if (\n typeof templateValue === \"object\" &&\n templateValue !== null &&\n !Array.isArray(templateValue) &&\n typeof existingValue === \"object\" &&\n existingValue !== null &&\n !Array.isArray(existingValue)\n ) {\n // Then: seedパス内でもディープマージ(既存にないキーのみ追加)\n result[key] = deepMergeWithPaths(\n templateValue as Record<string, unknown>,\n existingValue as Record<string, unknown>,\n jsonPaths,\n filePath,\n keyPath\n );\n } else if (!(key in existing)) {\n // Then: seedパスはローカル優先(キーが存在しない場合のみディープコピーして追加)\n result[key] = deepClone(templateValue);\n }\n // 既存値がある場合は何もしない(既存値を保持)\n }\n // Given: 両方がオブジェクトの場合\n else if (\n typeof templateValue === \"object\" &&\n templateValue !== null &&\n !Array.isArray(templateValue) &&\n typeof existingValue === \"object\" &&\n existingValue !== null &&\n !Array.isArray(existingValue)\n ) {\n // Then: 再帰的にディープマージ\n result[key] = deepMergeWithPaths(\n templateValue as Record<string, unknown>,\n existingValue as Record<string, unknown>,\n jsonPaths,\n filePath,\n keyPath\n );\n }\n // Given: それ以外のパス(テンプレートにのみ存在する場合)\n else if (!(key in existing)) {\n // Then: テンプレートの値をディープコピーして追加\n result[key] = deepClone(templateValue);\n }\n // 既存値がある場合は何もしない(既存値を保持)\n }\n\n return result;\n}\n\n/**\n * 値をディープコピーする(undefinedも正しく扱う)\n *\n * @param value - コピーする値\n * @returns ディープコピーされた値\n */\nfunction deepClone(value: unknown): unknown {\n if (value === undefined) {\n return undefined;\n }\n return JSON.parse(JSON.stringify(value));\n}\n\n/**\n * .einja-sync.json を読み込む\n *\n * @param targetDir - ターゲットディレクトリ\n * @returns メタデータ(存在しない場合はnull)\n */\nexport async function loadSyncMetadata(\n targetDir: string\n): Promise<SyncMetadata | null> {\n const metadataPath = `${targetDir}/.einja-sync.json`;\n\n if (!existsSync(metadataPath)) {\n return null;\n }\n\n try {\n const content = readFileSync(metadataPath, \"utf-8\");\n return JSON.parse(content) as SyncMetadata;\n } catch {\n return null;\n }\n}\n\n/**\n * .einja-sync.json を保存する\n *\n * @param targetDir - ターゲットディレクトリ\n * @param metadata - メタデータ\n */\nexport async function saveSyncMetadata(\n targetDir: string,\n metadata: SyncMetadata\n): Promise<void> {\n const metadataPath = `${targetDir}/.einja-sync.json`;\n ensureDir(dirname(metadataPath));\n writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), \"utf-8\");\n}\n\n/**\n * package.json の特殊マージ処理\n *\n * @param existingContent - 既存の package.json の内容\n * @param templateContent - テンプレートの package.json の内容\n * @param packageJsonSections - 同期対象のセクション(指定がない場合は全セクション)\n * @returns マージ後の package.json の内容\n */\nasync function mergePackageJson(\n existingContent: string,\n templateContent: string,\n packageJsonSections?: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"engines\">\n): Promise<string> {\n // Given: JSON をパース\n const existingPkg = JSON.parse(existingContent) as Record<string, unknown>;\n const templatePkg = JSON.parse(templateContent) as Record<string, unknown>;\n\n // When: 既存の内容をベースにする\n const result = { ...existingPkg };\n\n // When: scripts をマージ(セクション指定がない、またはscriptsが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"scripts\")) && templatePkg.scripts && typeof templatePkg.scripts === \"object\") {\n result.scripts = {\n ...(existingPkg.scripts && typeof existingPkg.scripts === \"object\"\n ? existingPkg.scripts\n : {}),\n ...templatePkg.scripts,\n };\n }\n\n // When: dependencies をバージョン競合処理付きでマージ(セクション指定がない、またはdependenciesが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"dependencies\")) && templatePkg.dependencies && typeof templatePkg.dependencies === \"object\") {\n result.dependencies = await mergePackageJsonDependencies(\n (existingPkg.dependencies && typeof existingPkg.dependencies === \"object\"\n ? existingPkg.dependencies\n : {}) as Record<string, string>,\n templatePkg.dependencies as Record<string, string>,\n false\n );\n }\n\n // When: devDependencies をバージョン競合処理付きでマージ(セクション指定がない、またはdevDependenciesが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"devDependencies\")) && templatePkg.devDependencies && typeof templatePkg.devDependencies === \"object\") {\n result.devDependencies = await mergePackageJsonDependencies(\n (existingPkg.devDependencies && typeof existingPkg.devDependencies === \"object\"\n ? existingPkg.devDependencies\n : {}) as Record<string, string>,\n templatePkg.devDependencies as Record<string, string>,\n false\n );\n }\n\n // When: engines を完全置換(セクション指定がない、またはenginesが含まれる場合のみ)\n if ((!packageJsonSections || packageJsonSections.includes(\"engines\")) && templatePkg.engines && typeof templatePkg.engines === \"object\") {\n if (\n existingPkg.engines &&\n JSON.stringify(existingPkg.engines) !== JSON.stringify(templatePkg.engines)\n ) {\n logger.warn(\"⚠️ engines を置換します:\");\n logger.warn(` 既存: ${JSON.stringify(existingPkg.engines)}`);\n logger.warn(` 新規: ${JSON.stringify(templatePkg.engines)}`);\n }\n result.engines = templatePkg.engines;\n }\n\n // Then: JSON 文字列として返す\n return `${JSON.stringify(result, null, 2)}\\n`;\n}\n\n/**\n * ファイルマージの実行(テキスト/JSON自動判定)\n *\n * @param templatePath - テンプレートファイルのパス\n * @param targetPath - ターゲットファイルのパス\n * @param syncMetadata - 同期メタデータ\n * @param packageJsonSections - 同期対象のpackage.jsonセクション(指定がない場合は全セクション)\n * @returns マージ結果\n */\nexport async function mergeAndWriteFile(\n templatePath: string,\n targetPath: string,\n syncMetadata: SyncMetadata,\n packageJsonSections?: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"engines\">\n): Promise<{\n action: \"created\" | \"merged\" | \"skipped\" | \"overwritten\";\n path: string;\n}> {\n const templateContent = readFileSync(templatePath, \"utf-8\");\n const targetExists = existsSync(targetPath);\n const existingContent = targetExists ? readFileSync(targetPath, \"utf-8\") : null;\n\n // Given: ファイルがJSONかどうか判定\n const isJsonFile = targetPath.endsWith(\".json\");\n const isPackageJson = basename(targetPath) === \"package.json\";\n\n let mergedContent: string;\n let action: \"created\" | \"merged\" | \"skipped\" | \"overwritten\";\n\n if (!targetExists) {\n // When: ファイルが存在しない場合は新規作成\n mergedContent = templateContent;\n action = \"created\";\n } else if (isPackageJson && existingContent) {\n // When: package.json の特殊処理\n try {\n mergedContent = await mergePackageJson(existingContent, templateContent, packageJsonSections);\n action = \"merged\";\n } catch {\n // Then: パースエラーの場合はテンプレートで上書き\n mergedContent = templateContent;\n action = \"overwritten\";\n }\n } else if (isJsonFile) {\n // When: JSONファイルの場合はディープマージ\n try {\n const templateJson = JSON.parse(templateContent) as Record<string, unknown>;\n const existingJson = existingContent\n ? (JSON.parse(existingContent) as Record<string, unknown>)\n : null;\n const jsonPaths = syncMetadata.jsonPaths || { managed: {}, seed: {} };\n // ファイルパスからファイル名を抽出(例: \"/path/to/package.json\" → \"package.json\")\n const fileName = targetPath.split(\"/\").pop() || \"package.json\";\n const mergedJson = mergeJson(templateJson, existingJson, jsonPaths, fileName);\n mergedContent = JSON.stringify(mergedJson, null, 2);\n action = \"merged\";\n } catch {\n // Then: パースエラーの場合はテンプレートで上書き\n mergedContent = templateContent;\n action = \"overwritten\";\n }\n } else {\n // When: テキストファイルの場合はマーカーベースマージ\n mergedContent = mergeTextWithMarkers(templateContent, existingContent);\n\n // Then: 内容が変更されたかチェック\n if (mergedContent === existingContent) {\n action = \"skipped\";\n } else {\n action = \"merged\";\n }\n }\n\n // Then: ファイルに書き込み\n if (action !== \"skipped\") {\n ensureDir(dirname(targetPath));\n writeFileSync(targetPath, mergedContent, \"utf-8\");\n }\n\n return { action, path: targetPath };\n}\n\n/**\n * マーカーセクションの型定義\n */\ninterface MarkerSection {\n type: \"managed\" | \"seed\" | \"unmanaged\";\n startLine: number;\n endLine: number;\n content: string;\n id?: string;\n}\n\n/**\n * ファイル内容をパースしてマーカーセクションに分離する\n *\n * @param content - ファイル内容\n * @returns セクション配列\n */\nfunction parseMarkers(content: string): MarkerSection[] {\n const lines = content.split(\"\\n\");\n const sections: MarkerSection[] = [];\n let currentType: \"managed\" | \"seed\" | \"unmanaged\" = \"unmanaged\";\n let currentStartLine = 1;\n let currentContent: string[] = [];\n let currentId: string | undefined;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] as string;\n const lineNumber = i + 1;\n\n // Given: マーカー開始を検出\n const startMarker = parseStartMarker(line);\n if (startMarker) {\n if (currentType !== \"unmanaged\") {\n // Then: 入れ子のマーカーは無視\n currentContent.push(line);\n continue;\n }\n\n // When: 現在のunmanagedセクションを保存\n if (currentContent.length > 0 || sections.length === 0) {\n sections.push({\n type: \"unmanaged\",\n startLine: currentStartLine,\n endLine: lineNumber - 1,\n content: currentContent.join(\"\\n\"),\n });\n }\n\n // When: managed/seedセクション開始\n currentType = startMarker.type;\n currentId = startMarker.id;\n currentStartLine = lineNumber;\n currentContent = [line];\n }\n // Given: マーカー終了を検出\n else if (parseEndMarker(line)) {\n if (currentType === \"unmanaged\") {\n // Then: 対応するstartがない場合は無視\n currentContent.push(line);\n continue;\n }\n\n // When: マーカー終了行を追加\n currentContent.push(line);\n\n // When: managed/seedセクションを保存\n sections.push({\n type: currentType,\n startLine: currentStartLine,\n endLine: lineNumber,\n content: currentContent.join(\"\\n\"),\n id: currentId,\n });\n\n // When: unmanagedセクション開始\n currentType = \"unmanaged\";\n currentId = undefined;\n currentStartLine = lineNumber + 1;\n currentContent = [];\n }\n // Given: 通常行\n else {\n currentContent.push(line);\n }\n }\n\n // Then: 最後のセクションを保存\n if (currentContent.length > 0 || sections.length === 0) {\n sections.push({\n type: currentType,\n startLine: currentStartLine,\n endLine: lines.length,\n content: currentContent.join(\"\\n\"),\n id: currentId,\n });\n }\n\n return sections;\n}\n\n/**\n * 行がマーカー開始かどうかを判定し、種別とIDを返す\n *\n * @param line - 行内容\n * @returns マーカー情報またはnull\n */\nfunction parseStartMarker(\n line: string\n): { type: \"managed\" | \"seed\"; id?: string } | null {\n // Markdown managed\n const markdownManagedPattern =\n /^<!--\\s*@einja:managed:start(?:\\s+id=\"([^\"]+)\")?\\s*-->$/;\n let match = line.match(markdownManagedPattern);\n if (match) {\n return { type: \"managed\", id: match[1] || undefined };\n }\n\n // Markdown seed\n const markdownSeedPattern =\n /^<!--\\s*@einja:seed:start(?:\\s+id=\"([^\"]+)\")?\\s*-->$/;\n match = line.match(markdownSeedPattern);\n if (match) {\n return { type: \"seed\", id: match[1] || undefined };\n }\n\n // YAML/JSON managed\n const yamlManagedPattern = /^\\s*#\\s*@einja:managed:start(?:\\s+id=\"([^\"]+)\")?\\s*$/;\n match = line.match(yamlManagedPattern);\n if (match) {\n return { type: \"managed\", id: match[1] || undefined };\n }\n\n // YAML/JSON seed\n const yamlSeedPattern = /^\\s*#\\s*@einja:seed:start(?:\\s+id=\"([^\"]+)\")?\\s*$/;\n match = line.match(yamlSeedPattern);\n if (match) {\n return { type: \"seed\", id: match[1] || undefined };\n }\n\n return null;\n}\n\n/**\n * 行がマーカー終了かどうかを判定し、種別を返す\n *\n * @param line - 行内容\n * @returns マーカー種別またはnull\n */\nfunction parseEndMarker(line: string): \"managed\" | \"seed\" | null {\n // Markdown managed\n if (/^<!--\\s*@einja:managed:end\\s*-->$/.test(line)) {\n return \"managed\";\n }\n\n // Markdown seed\n if (/^<!--\\s*@einja:seed:end\\s*-->$/.test(line)) {\n return \"seed\";\n }\n\n // YAML/JSON managed\n if (/^\\s*#\\s*@einja:managed:end\\s*$/.test(line)) {\n return \"managed\";\n }\n\n // YAML/JSON seed\n if (/^\\s*#\\s*@einja:seed:end\\s*$/.test(line)) {\n return \"seed\";\n }\n\n return null;\n}\n\n/**\n * パスがmanagedに含まれるかチェック\n *\n * @param filePath - ファイルパス(例: \"package.json\")\n * @param keyPath - チェックするキーパス(例: \"scripts.dev\")\n * @param jsonPaths - JSONパス設定\n * @returns managedに含まれる場合true\n */\nfunction isPathManaged(\n filePath: string,\n keyPath: string,\n jsonPaths: JsonPathsConfig\n): boolean {\n const managedPaths = jsonPaths.managed[filePath] || [];\n // keyPath が managedPaths のいずれかで始まるかチェック\n // 例: keyPath=\"scripts.dev\" が managedPaths=[\"scripts.dev\"] にマッチ\n // または keyPath=\"scripts.dev\" が managedPaths=[\"scripts\"] にマッチ\n return managedPaths.some(\n (p) => keyPath === p || keyPath.startsWith(`${p}.`)\n );\n}\n\n/**\n * パスがseedに含まれるかチェック\n *\n * @param filePath - ファイルパス(例: \"package.json\")\n * @param keyPath - チェックするキーパス(例: \"scripts.custom\")\n * @param jsonPaths - JSONパス設定\n * @returns seedに含まれる場合true\n */\nfunction isPathSeed(\n filePath: string,\n keyPath: string,\n jsonPaths: JsonPathsConfig\n): boolean {\n const seedPaths = jsonPaths.seed[filePath] || [];\n // keyPath が seedPaths のいずれかで始まるかチェック\n return seedPaths.some((p) => keyPath === p || keyPath.startsWith(`${p}.`));\n}\n","import inquirer from \"inquirer\";\nimport * as logger from \"./logger.js\";\n\n/**\n * package.json の依存関係の型\n */\nexport interface PackageJsonDependencies {\n [key: string]: string;\n}\n\n/**\n * バージョン競合の情報\n */\nexport interface VersionConflict {\n packageName: string;\n existingVersion: string;\n templateVersion: string;\n}\n\n/**\n * マージ結果の型\n */\nexport interface PackageJsonMergeResult {\n merged: PackageJsonDependencies;\n conflicts: VersionConflict[];\n}\n\n/**\n * バージョンが異なるかチェック\n *\n * @param existingVersion - 既存のバージョン\n * @param templateVersion - テンプレートのバージョン\n * @returns バージョン競合がある場合 true\n */\nfunction hasVersionConflict(\n existingVersion: string,\n templateVersion: string\n): boolean {\n // Given: 完全一致の場合\n if (existingVersion === templateVersion) {\n // Then: 競合なし\n return false;\n }\n\n // Given: 範囲指定の正規化(^1.0.0 と 1.0.0 は同一とみなす等)\n const normalize = (v: string) => v.replace(/^[\\^~]/, \"\");\n\n // When: 正規化したバージョンを比較\n // Then: 異なる場合は競合あり\n return normalize(existingVersion) !== normalize(templateVersion);\n}\n\n/**\n * 依存関係をマージし、バージョン競合を検出\n *\n * @param existing - 既存の依存関係\n * @param template - テンプレートの依存関係\n * @returns マージ結果と競合リスト\n */\nexport async function mergeDependenciesWithConflictDetection(\n existing: PackageJsonDependencies,\n template: PackageJsonDependencies\n): Promise<PackageJsonMergeResult> {\n // Given: マージ結果と競合リストを初期化\n const merged: PackageJsonDependencies = { ...existing };\n const conflicts: VersionConflict[] = [];\n\n // When: テンプレートの各パッケージを処理\n for (const [packageName, templateVersion] of Object.entries(template)) {\n if (packageName in existing) {\n // Given: 既存パッケージが存在する場合\n const existingVersion = existing[packageName];\n\n if (existingVersion && hasVersionConflict(existingVersion, templateVersion)) {\n // When: バージョン競合が発生\n // Then: 競合リストに追加(この時点ではマージしない)\n conflicts.push({\n packageName,\n existingVersion,\n templateVersion,\n });\n } else {\n // When: バージョンが一致または正規化後一致\n // Then: テンプレートのバージョンを使用\n merged[packageName] = templateVersion;\n }\n } else {\n // Given: 新規パッケージの場合\n // Then: 無条件で追加\n merged[packageName] = templateVersion;\n }\n }\n\n // Then: マージ結果と競合リストを返す\n return { merged, conflicts };\n}\n\n/**\n * ユーザーにバージョン競合の解決方法を尋ねる\n *\n * @param conflicts - 競合リスト\n * @returns パッケージ名とバージョンのマップ\n */\nexport async function resolveVersionConflicts(\n conflicts: VersionConflict[]\n): Promise<Map<string, string>> {\n // Given: 解決結果を格納するマップ\n const resolutions = new Map<string, string>();\n\n // When: 競合が存在する場合\n logger.warn(`\\n⚠️ ${conflicts.length}個のパッケージでバージョン競合が検出されました:\\n`);\n\n // When: 各競合について順次処理\n for (const conflict of conflicts) {\n logger.warn(`📦 ${conflict.packageName}`);\n logger.warn(` 既存: ${conflict.existingVersion}`);\n logger.warn(` テンプレート: ${conflict.templateVersion}\\n`);\n\n // When: ユーザーに選択を求める\n const answer = await inquirer.prompt([\n {\n type: \"list\",\n name: \"version\",\n message: \"どちらのバージョンを使用しますか?\",\n choices: [\n {\n name: `テンプレート (${conflict.templateVersion})`,\n value: \"template\",\n },\n {\n name: `既存 (${conflict.existingVersion})`,\n value: \"existing\",\n },\n {\n name: \"スキップ(既存を維持)\",\n value: \"skip\",\n },\n ],\n },\n ]);\n\n // Then: ユーザーの選択に応じて解決結果を記録\n if (answer.version === \"template\") {\n resolutions.set(conflict.packageName, conflict.templateVersion);\n } else if (answer.version === \"existing\") {\n resolutions.set(conflict.packageName, conflict.existingVersion);\n }\n // skip の場合は何もしない(既存を維持)\n }\n\n // Then: 解決結果を返す\n return resolutions;\n}\n\n/**\n * 依存関係を完全にマージ(競合解決含む)\n *\n * @param existingDeps - 既存の依存関係\n * @param templateDeps - テンプレートの依存関係\n * @param skipPrompts - プロンプトをスキップするかどうか\n * @returns マージされた依存関係\n */\nexport async function mergePackageJsonDependencies(\n existingDeps: PackageJsonDependencies,\n templateDeps: PackageJsonDependencies,\n skipPrompts = false\n): Promise<PackageJsonDependencies> {\n // Given: 依存関係をマージして競合を検出\n const { merged, conflicts } = await mergeDependenciesWithConflictDetection(\n existingDeps,\n templateDeps\n );\n\n // Given: 競合がない場合\n if (conflicts.length === 0) {\n // Then: マージ結果をそのまま返す\n return merged;\n }\n\n // Given: プロンプトをスキップする場合\n if (skipPrompts) {\n // Then: 既存バージョンを優先(競合分は merged に含まれていない)\n logger.info(\n `バージョン競合が${conflicts.length}個ありますが、既存バージョンを維持します`\n );\n return merged;\n }\n\n // When: ユーザーに競合解決を尋ねる\n const resolutions = await resolveVersionConflicts(conflicts);\n\n // When: 解決結果をマージ結果に反映\n for (const [packageName, version] of resolutions.entries()) {\n merged[packageName] = version;\n }\n\n // Then: 最終的なマージ結果を返す\n return merged;\n}\n","import { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n AddOptions,\n AppComponent,\n SyncMetadata,\n} from \"../../types/index.js\";\nimport { mergeAndWriteFile } from \"../../utils/merger.js\";\nimport * as logger from \"../../utils/logger.js\";\n\n/**\n * apps/ ディレクトリにコンポーネントを追加\n */\nexport async function addApps(\n options: AddOptions,\n components: AppComponent[],\n syncMetadata: SyncMetadata\n): Promise<{ added: string[]; skipped: string[]; merged: string[] }> {\n const added: string[] = [];\n const skipped: string[] = [];\n const merged: string[] = [];\n\n const { targetDir, templateDir, config } = options;\n\n for (const component of components) {\n const componentName = component === \"web\" ? \"web\" : component;\n\n const srcDir = join(templateDir, \"apps\", componentName);\n const destDir = join(targetDir, \"apps\", componentName);\n\n logger.info(`Adding app component: ${componentName}`);\n\n await copyDirectory(\n srcDir,\n destDir,\n { added, skipped, merged },\n config.dryRun,\n syncMetadata\n );\n }\n\n return { added, skipped, merged };\n}\n\n/**\n * ディレクトリを再帰的にコピー\n */\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n result: { added: string[]; skipped: string[]; merged: string[] },\n dryRun: boolean,\n syncMetadata: SyncMetadata\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath, result, dryRun, syncMetadata);\n } else {\n if (!dryRun) {\n const mergeResult = await mergeAndWriteFile(\n srcPath,\n destPath,\n syncMetadata\n );\n\n if (mergeResult.action === \"created\") {\n result.added.push(destPath);\n } else if (mergeResult.action === \"skipped\") {\n result.skipped.push(destPath);\n } else if (mergeResult.action === \"merged\") {\n result.merged.push(destPath);\n }\n } else {\n // dry-runモードではスキップ\n result.skipped.push(destPath);\n }\n }\n }\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport type { AddOptions, SyncMetadata } from \"../../types/index.js\";\nimport { mergeAndWriteFile } from \"../../utils/merger.js\";\nimport * as logger from \"../../utils/logger.js\";\n\n/**\n * プロジェクト直下の設定ファイルを追加\n */\nexport async function addConfigFiles(\n options: AddOptions,\n syncMetadata: SyncMetadata\n): Promise<{ added: string[]; skipped: string[]; merged: string[] }> {\n const added: string[] = [];\n const skipped: string[] = [];\n const merged: string[] = [];\n\n const { targetDir, templateDir, config } = options;\n\n logger.info(\"Adding config files from template root\");\n\n // 除外パターン\n const excludedPaths = new Set([\n \".claude\",\n \"docs/einja\",\n \"CLAUDE.md\",\n \".mcp.json\",\n \"node_modules\",\n \".turbo\",\n \"next-env.d.ts\",\n \"styled-system\",\n \"pnpm-lock.yaml\",\n \"package-lock.json\",\n \"packages\",\n \"apps\",\n ]);\n\n // .gitignore のパターンを読み込み\n const gitignorePatterns = await loadGitignorePatterns(templateDir);\n\n await copyConfigDirectory(\n templateDir,\n targetDir,\n templateDir, // rootDir として templateDir を渡す\n { added, skipped, merged },\n config.dryRun,\n excludedPaths,\n gitignorePatterns,\n syncMetadata\n );\n\n return { added, skipped, merged };\n}\n\n/**\n * .gitignore のパターンを読み込み\n */\nasync function loadGitignorePatterns(templateDir: string): Promise<Set<string>> {\n const patterns = new Set<string>();\n const gitignorePath = join(templateDir, \".gitignore\");\n\n try {\n const content = await readFile(gitignorePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n\n for (const line of lines) {\n const trimmed = line.trim();\n // コメントと空行を除外\n if (trimmed && !trimmed.startsWith(\"#\")) {\n // 先頭の / を削除\n const pattern = trimmed.startsWith(\"/\") ? trimmed.slice(1) : trimmed;\n patterns.add(pattern);\n }\n }\n } catch {\n // .gitignore が存在しない場合は無視\n }\n\n return patterns;\n}\n\n/**\n * 設定ファイルのディレクトリを再帰的にコピー\n */\nasync function copyConfigDirectory(\n srcDir: string,\n destDir: string,\n rootDir: string, // テンプレートルートディレクトリ\n result: { added: string[]; skipped: string[]; merged: string[] },\n dryRun: boolean,\n excludedPaths: Set<string>,\n gitignorePatterns: Set<string>,\n syncMetadata: SyncMetadata\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n // rootDir からの相対パスを計算(一貫性を保つ)\n const rawRelativePath = relative(rootDir, srcPath);\n // Windows対応: パス区切り文字をPOSIX形式(/)に正規化\n const relativePath = rawRelativePath.split(sep).join(\"/\");\n\n // 除外パターンに一致するかチェック\n if (shouldExclude(relativePath, excludedPaths, gitignorePatterns)) {\n continue;\n }\n\n if (entry.isDirectory()) {\n await copyConfigDirectory(\n srcPath,\n destPath,\n rootDir, // rootDir を引き継ぐ\n result,\n dryRun,\n excludedPaths,\n gitignorePatterns,\n syncMetadata\n );\n } else {\n if (!dryRun) {\n const mergeResult = await mergeAndWriteFile(\n srcPath,\n destPath,\n syncMetadata\n );\n\n if (mergeResult.action === \"created\") {\n result.added.push(destPath);\n } else if (mergeResult.action === \"skipped\") {\n result.skipped.push(destPath);\n } else if (mergeResult.action === \"merged\") {\n result.merged.push(destPath);\n }\n } else {\n // dry-runモードではスキップ\n result.skipped.push(destPath);\n }\n }\n }\n}\n\n/**\n * パスを除外すべきか判定\n */\nfunction shouldExclude(\n relativePath: string,\n excludedPaths: Set<string>,\n gitignorePatterns: Set<string>\n): boolean {\n // 除外パスに完全一致または部分一致\n for (const excluded of excludedPaths) {\n if (relativePath === excluded || relativePath.startsWith(`${excluded}/`)) {\n return true;\n }\n }\n\n // .gitignore パターンに一致\n for (const pattern of gitignorePatterns) {\n // シンプルなパターンマッチング(ワイルドカード対応)\n if (matchPattern(relativePath, pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * シンプルなパターンマッチング\n */\nfunction matchPattern(path: string, pattern: string): boolean {\n // パターンの最後が / の場合、ディレクトリのみ一致\n if (pattern.endsWith(\"/\")) {\n const dirPattern = pattern.slice(0, -1);\n return path === dirPattern || path.startsWith(`${dirPattern}/`);\n }\n\n // * を含むパターン\n if (pattern.includes(\"*\")) {\n const regexPattern = pattern\n .replace(/\\./g, \"\\\\.\")\n .replace(/\\*/g, \".*\");\n return new RegExp(`^${regexPattern}$`).test(path);\n }\n\n // 完全一致または部分一致\n return path === pattern || path.startsWith(`${pattern}/`);\n}\n","import { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport fsExtra from \"fs-extra\";\nimport inquirer from \"inquirer\";\nimport { collectSyncFiles } from \"../generators/sync.js\";\nimport { promptSyncCategories } from \"../prompts/sync.js\";\nimport type { SyncCategory, SyncMetadata, SyncOptions, SyncResult } from \"../types/index.js\";\nimport { createBackup, getLatestBackup, restoreFromBackup } from \"../utils/backup.js\";\nimport { checkGitStatusForSync } from \"../utils/git.js\";\nimport * as logger from \"../utils/logger.js\";\nimport { mergeAndWriteFile } from \"../utils/merger.js\";\n\n// 同期処理中のバックアップ情報を保持\nlet currentBackupDir: string | undefined;\nlet isSyncing = false;\n\n/**\n * 中断時のクリーンアップ処理\n */\nasync function handleInterrupt(): Promise<void> {\n if (!isSyncing) {\n // 同期処理開始前の中断は単純に終了\n logger.info(\"\\n\\n処理を中断しました\");\n process.exit(0);\n }\n\n logger.info(\"\\n\\n🛑 同期処理を中断しています...\");\n\n if (!currentBackupDir) {\n logger.info(\"バックアップが作成されていないため、クリーンアップは不要です\");\n process.exit(0);\n }\n\n // バックアップからのロールバック確認\n const answer = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"rollback\",\n message: \"変更をロールバックしますか?\",\n default: true,\n },\n ]);\n\n if (answer.rollback) {\n logger.info(\"バックアップから復元中...\");\n const targetDir = process.cwd();\n const success = await restoreFromBackup(currentBackupDir, targetDir);\n\n if (success) {\n logger.success(\"✓ ロールバック完了\");\n } else {\n logger.error(\"❌ ロールバック失敗\");\n logger.info(`手動で復元: cp -r ${currentBackupDir}/* .`);\n }\n }\n\n process.exit(0);\n}\n\n/**\n * テンプレートパスを取得\n */\nfunction getTemplatePath(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const { existsSync } = fsExtra;\n\n // dist/cli.js → ../templates/default (1階層上)\n // src/commands/sync.ts → ../../templates/default (2階層上)\n const distPath = join(__dirname, \"../templates/default\");\n const srcPath = join(__dirname, \"../../templates/default\");\n\n if (existsSync(distPath)) {\n return distPath;\n }\n if (existsSync(srcPath)) {\n return srcPath;\n }\n\n throw new Error(\"テンプレートディレクトリが見つかりません\");\n}\n\n/**\n * sync コマンドのメイン関数\n */\nexport async function syncCommand(options: SyncOptions): Promise<void> {\n const { existsSync } = fsExtra;\n // Ctrl+C (SIGINT) ハンドラーを登録\n const sigintHandler = () => {\n handleInterrupt().catch((error) => {\n logger.error(`クリーンアップ中にエラー: ${error}`);\n process.exit(1);\n });\n };\n\n process.on(\"SIGINT\", sigintHandler);\n\n // 関数終了時にハンドラーを削除(正常終了時)\n const cleanup = () => {\n process.off(\"SIGINT\", sigintHandler);\n };\n\n try {\n // ========================================\n // a) Rollback モード\n // ========================================\n if (options.rollback) {\n logger.info(\"🔄 バックアップからロールバック中...\");\n\n const targetDir = process.cwd();\n const latestBackup = await getLatestBackup(targetDir);\n\n if (!latestBackup) {\n logger.error(\"❌ バックアップが見つかりません\");\n process.exit(1);\n }\n\n logger.info(`バックアップ: ${latestBackup.name}`);\n\n const success = await restoreFromBackup(latestBackup.path, targetDir);\n if (success) {\n logger.success(\"✓ ロールバック完了\");\n } else {\n logger.error(\"❌ ロールバック失敗\");\n process.exit(1);\n }\n\n return;\n }\n\n // ========================================\n // b) Git チェック\n // ========================================\n const targetDir = process.cwd();\n checkGitStatusForSync(options.force || false, targetDir);\n\n // ========================================\n // c) プロンプトまたはデフォルト設定\n // ========================================\n const templatePath = getTemplatePath();\n\n let categories: SyncCategory[];\n let appsDetail: string[] | undefined;\n let packagesDetail: string[] | undefined;\n let conflictStrategy: \"merge\" | \"overwrite\" | \"skip\";\n let packageJsonSections: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"engines\"> | undefined;\n\n if (options.all) {\n // デフォルト: 全カテゴリ選択\n categories = [\n \"env\",\n \"tools\",\n \"git\",\n \"git-hooks\",\n \"github\",\n \"docker\",\n \"monorepo\",\n \"root-config\",\n \"apps\",\n \"packages\",\n \"docs\",\n ];\n appsDetail = undefined; // 全apps\n packagesDetail = undefined; // 全packages\n conflictStrategy = \"merge\";\n\n logger.info(\"全カテゴリを同期対象に設定しました\");\n } else if (options.categories) {\n // コマンドラインで指定されたカテゴリのみ\n categories = options.categories as SyncCategory[];\n appsDetail = undefined;\n packagesDetail = undefined;\n conflictStrategy = \"merge\";\n\n logger.info(`指定されたカテゴリ: ${categories.join(\", \")}`);\n } else {\n // 対話式プロンプト\n const promptResult = await promptSyncCategories(templatePath);\n categories = promptResult.categories;\n appsDetail = promptResult.appsDetail;\n packagesDetail = promptResult.packagesDetail;\n conflictStrategy = promptResult.conflictStrategy;\n packageJsonSections = promptResult.packageJsonSections;\n }\n\n // ========================================\n // d) ファイル収集\n // ========================================\n logger.info(\"📁 同期対象ファイルを収集中...\");\n\n const filesToSync = await collectSyncFiles(templatePath, categories, appsDetail, packagesDetail);\n\n if (filesToSync.length === 0) {\n logger.warn(\"⚠️ 同期対象のファイルが見つかりません\");\n return;\n }\n\n logger.info(`同期対象: ${filesToSync.length}個のファイル`);\n\n // ========================================\n // e) Dry-run モード\n // ========================================\n if (options.dryRun) {\n logger.info(\"\\n📋 同期プレビュー (--dry-run)\\n\");\n\n for (const file of filesToSync) {\n logger.info(` ✓ ${file}`);\n }\n\n logger.info(`\\n合計: ${filesToSync.length}ファイル`);\n logger.info(\"--dry-run モードのため、実際のファイル変更は行われません\");\n return;\n }\n\n // ========================================\n // f) バックアップ作成\n // ========================================\n let backupDir: string | undefined;\n\n if (options.backup !== false) {\n logger.info(\"💾 バックアップ作成中...\");\n\n // 既存ファイルのみバックアップ\n const existingFiles = filesToSync.filter((file) => existsSync(join(targetDir, file)));\n\n if (existingFiles.length > 0) {\n backupDir = await createBackup(targetDir, existingFiles);\n currentBackupDir = backupDir; // グローバル変数に設定\n } else {\n logger.info(\"既存ファイルがないため、バックアップをスキップします\");\n }\n }\n\n // ========================================\n // g) ファイル同期処理\n // ========================================\n logger.info(\"🔄 ファイル同期中...\");\n\n isSyncing = true; // 同期処理開始をマーク\n\n // SyncMetadata の準備(conflictStrategy に基づく)\n const syncMetadata: SyncMetadata = {\n version: \"1.0.0\",\n lastSync: new Date().toISOString(),\n templateVersion: \"0.2.9\",\n files: {},\n jsonPaths: {\n managed: {},\n seed: {},\n },\n };\n\n const result: SyncResult = {\n success: 0,\n skipped: 0,\n errors: 0,\n conflicts: 0,\n files: [],\n };\n\n for (const file of filesToSync) {\n try {\n const sourcePath = join(templatePath, file);\n const targetPath = join(targetDir, file);\n\n if (!existsSync(sourcePath)) {\n logger.warn(`スキップ: ${file} (テンプレートファイルが存在しません)`);\n result.skipped++;\n result.files.push({\n path: file,\n action: \"skipped\",\n reason: \"テンプレートファイルが存在しません\",\n });\n continue;\n }\n\n // マージまたはコピー(packageJsonSections を渡す)\n const mergeResult = await mergeAndWriteFile(\n sourcePath,\n targetPath,\n syncMetadata,\n packageJsonSections\n );\n\n // アクションをマッピング(mergeAndWriteFile の戻り値を SyncResult の型に変換)\n const mappedAction: \"copied\" | \"merged\" | \"skipped\" =\n mergeResult.action === \"created\" || mergeResult.action === \"overwritten\"\n ? \"copied\"\n : mergeResult.action;\n\n result.success++;\n result.files.push({\n path: file,\n action: mappedAction,\n });\n\n logger.info(` ✓ ${file}`);\n } catch (error) {\n result.errors++;\n result.files.push({\n path: file,\n action: \"error\",\n reason: error instanceof Error ? error.message : \"不明なエラー\",\n });\n logger.error(` ✗ ${file}: ${error}`);\n }\n }\n\n // ========================================\n // h) 結果レポート\n // ========================================\n logger.info(\"\\n📊 同期結果:\");\n logger.info(` 成功: ${result.success}ファイル`);\n if (result.skipped > 0) {\n logger.info(` スキップ: ${result.skipped}ファイル`);\n }\n if (result.errors > 0) {\n logger.error(` エラー: ${result.errors}ファイル`);\n }\n\n if (result.errors > 0) {\n isSyncing = false; // エラー時もフラグをクリア\n\n logger.error(\"\\n❌ 同期中にエラーが発生しました\");\n if (backupDir) {\n logger.info(\"バックアップから復元: npx create-einja-app sync --rollback\");\n }\n process.exit(1);\n }\n\n logger.success(\"\\n✓ 同期完了\");\n\n // 正常終了時はグローバル変数をクリア\n isSyncing = false;\n currentBackupDir = undefined;\n\n if (backupDir) {\n logger.info(`\\nバックアップ: ${backupDir}`);\n logger.info(\"復元方法: npx create-einja-app sync --rollback\");\n }\n } finally {\n cleanup();\n }\n}\n","import { glob } from \"glob\";\nimport type { SyncCategory } from \"../types/index.js\";\nimport * as logger from \"../utils/logger.js\";\n\n/**\n * カテゴリとファイルパターンのマッピング\n * prompts/sync.ts の CATEGORY_CONFIGS と同じ定義\n */\nconst CATEGORY_PATTERNS: Record<SyncCategory, string[]> = {\n env: [\".env*\", \".envrc\", \".volta\", \".node-version\"],\n tools: [\"biome.json\", \".prettierrc*\", \".editorconfig\", \".vscode/**\"],\n git: [\".gitignore\", \".gitattributes\"],\n \"git-hooks\": [\".husky/**\"],\n github: [\".github/workflows/**\", \".github/actions/**\", \".github/dependabot.yml\"],\n docker: [\"Dockerfile*\", \"docker-compose*.yml\", \".dockerignore\"],\n monorepo: [\"turbo.json\", \"pnpm-workspace.yaml\"],\n \"root-config\": [\"package.json\", \"tsconfig.json\"],\n apps: [\"apps/**\"],\n packages: [\"packages/**\"],\n docs: [\"README.md\", \"docs/**\"],\n};\n\n/**\n * envファイル保護ルール\n * これらのファイルは同期対象外(暗号化キーと個人設定)\n */\nconst ENV_FILE_PROTECTION = {\n protected: [\".env.keys\", \".env.personal\"],\n};\n\n/**\n * envファイルが保護対象かチェック\n * @param filePath - ファイルパス\n * @returns 保護対象の場合 true\n */\nfunction isProtectedEnvFile(filePath: string): boolean {\n return ENV_FILE_PROTECTION.protected.some((pattern) =>\n filePath.endsWith(pattern)\n );\n}\n\n/**\n * apps/packagesの詳細フィルタリング\n * @param files - 全ファイルリスト\n * @param detail - 選択された詳細項目\n * @param prefix - \"apps\" or \"packages\"\n * @returns フィルタリング後のファイルリスト\n */\nfunction filterDetailFiles(\n files: string[],\n detail: string[] | undefined,\n prefix: string\n): string[] {\n if (!detail || detail.length === 0) {\n // 詳細指定なしの場合は全て含める\n return files;\n }\n\n // 選択されたアイテムのみをフィルタリング\n return files.filter((file) =>\n detail.some((item) => file.startsWith(`${prefix}/${item}/`))\n );\n}\n\n/**\n * カテゴリからglobパターンを抽出\n * @param categories - 選択されたカテゴリ\n * @param appsDetail - apps詳細選択(オプション)\n * @param packagesDetail - packages詳細選択(オプション)\n * @returns globパターン配列\n */\nfunction extractPatternsFromCategories(\n categories: SyncCategory[],\n appsDetail?: string[],\n packagesDetail?: string[]\n): string[] {\n const patterns: string[] = [];\n\n for (const category of categories) {\n const categoryPatterns = CATEGORY_PATTERNS[category];\n\n if (!categoryPatterns) {\n logger.warn(`不明なカテゴリ: ${category}`);\n continue;\n }\n\n // apps/packages は詳細選択に応じてパターンを調整\n if (category === \"apps\" && appsDetail && appsDetail.length > 0) {\n // 例: [\"web\"] → [\"apps/web/**\"]\n patterns.push(...appsDetail.map((app) => `apps/${app}/**`));\n } else if (category === \"packages\" && packagesDetail && packagesDetail.length > 0) {\n // 例: [\"server-core\"] → [\"packages/server-core/**\"]\n patterns.push(...packagesDetail.map((pkg) => `packages/${pkg}/**`));\n } else {\n // 通常のパターンをそのまま追加\n patterns.push(...categoryPatterns);\n }\n }\n\n return patterns;\n}\n\n/**\n * 同期対象ファイルを収集\n * @param templateDir - テンプレートディレクトリパス\n * @param categories - 選択されたカテゴリ\n * @param appsDetail - apps詳細選択(オプション)\n * @param packagesDetail - packages詳細選択(オプション)\n * @returns 収集されたファイルパスの配列\n */\nexport async function collectSyncFiles(\n templateDir: string,\n categories: SyncCategory[],\n appsDetail?: string[],\n packagesDetail?: string[]\n): Promise<string[]> {\n try {\n logger.info(\"同期対象ファイルを収集中...\");\n\n // 1. カテゴリからパターン抽出\n const patterns = extractPatternsFromCategories(\n categories,\n appsDetail,\n packagesDetail\n );\n\n if (patterns.length === 0) {\n logger.warn(\"同期対象のパターンがありません\");\n return [];\n }\n\n // 2. globによるファイル収集(Set で重複除去)\n const fileSet = new Set<string>();\n\n for (const pattern of patterns) {\n try {\n const files = await glob(pattern, {\n cwd: templateDir,\n dot: true, // .で始まるファイルも含める\n nodir: true, // ディレクトリは除外\n });\n\n for (const file of files) {\n fileSet.add(file);\n }\n } catch (error) {\n logger.warn(`パターン ${pattern} の処理中にエラー: ${error}`);\n }\n }\n\n // 3. 保護対象ファイルを除外\n const allFiles = Array.from(fileSet);\n const filteredFiles = allFiles.filter((file) => {\n // 保護対象envファイルを除外\n if (isProtectedEnvFile(file)) {\n logger.info(`保護対象ファイルを除外: ${file}`);\n return false;\n }\n\n return true;\n });\n\n logger.success(`${filteredFiles.length}個のファイルを収集しました`);\n\n return filteredFiles.sort(); // ソートして返却\n } catch (error) {\n logger.error(`ファイル収集中にエラーが発生しました: ${error}`);\n throw error;\n }\n}\n","import inquirer from \"inquirer\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { SyncCategory, SyncCategoryConfig } from \"../types/index.js\";\n\n/**\n * 同期プロンプト結果の型定義\n */\nexport type SyncPromptResult = {\n categories: SyncCategory[];\n appsDetail?: string[];\n packagesDetail?: string[];\n packageJsonSections?: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"engines\">;\n conflictStrategy: \"merge\" | \"overwrite\" | \"skip\";\n};\n\n/**\n * カテゴリとファイルパターンのマッピング\n */\nconst CATEGORY_CONFIGS: Record<SyncCategory, SyncCategoryConfig> = {\n env: {\n name: \"環境設定\",\n description: \".env*, .envrc, .volta, .node-version\",\n patterns: [\".env*\", \".envrc\", \".volta\", \".node-version\"],\n defaultChecked: true,\n },\n tools: {\n name: \"開発ツール\",\n description: \"biome.json, .prettierrc, .editorconfig, .vscode/\",\n patterns: [\"biome.json\", \".prettierrc*\", \".editorconfig\", \".vscode/\"],\n defaultChecked: true,\n },\n git: {\n name: \"Git設定\",\n description: \".gitignore, .gitattributes\",\n patterns: [\".gitignore\", \".gitattributes\"],\n defaultChecked: false,\n },\n \"git-hooks\": {\n name: \"Git Hooks\",\n description: \".husky/\",\n patterns: [\".husky/\"],\n defaultChecked: false,\n },\n github: {\n name: \"CI/CD\",\n description: \".github/workflows/, .github/actions/\",\n patterns: [\".github/workflows/\", \".github/actions/\", \".github/dependabot.yml\"],\n defaultChecked: false,\n },\n docker: {\n name: \"コンテナ\",\n description: \"Dockerfile*, docker-compose.yml, .dockerignore\",\n patterns: [\"Dockerfile*\", \"docker-compose*.yml\", \".dockerignore\"],\n defaultChecked: false,\n },\n monorepo: {\n name: \"モノレポ構成\",\n description: \"turbo.json, pnpm-workspace.yaml\",\n patterns: [\"turbo.json\", \"pnpm-workspace.yaml\"],\n defaultChecked: false,\n },\n \"root-config\": {\n name: \"ルート設定\",\n description: \"package.json, tsconfig.json\",\n patterns: [\"package.json\", \"tsconfig.json\"],\n defaultChecked: false,\n },\n apps: {\n name: \"アプリケーション\",\n description: \"apps/ 配下(次の画面で個別選択)\",\n patterns: [\"apps/**\"],\n defaultChecked: false,\n requiresDetailSelection: true,\n },\n packages: {\n name: \"共通パッケージ\",\n description: \"packages/ 配下(次の画面で個別選択)\",\n patterns: [\"packages/**\"],\n defaultChecked: false,\n requiresDetailSelection: true,\n },\n docs: {\n name: \"ドキュメント\",\n description: \"README.md, docs/\",\n patterns: [\"README.md\", \"docs/**\"],\n defaultChecked: false,\n },\n};\n\n/**\n * デフォルトの同期カテゴリを取得\n * skipPrompts=true 時に使用\n */\nexport function getDefaultSyncCategories(): SyncCategory[] {\n return Object.entries(CATEGORY_CONFIGS)\n .filter(([_key, config]) => config.defaultChecked)\n .map(([key, _config]) => key as SyncCategory);\n}\n\n/**\n * テンプレートディレクトリからアプリ一覧を取得\n * @param templateDir - テンプレートディレクトリのパス\n * @returns アプリ名の配列\n */\nfunction getAvailableApps(templateDir: string): string[] {\n const appsDir = path.join(templateDir, \"apps\");\n try {\n if (!fs.existsSync(appsDir)) {\n return [];\n }\n return fs\n .readdirSync(appsDir, { withFileTypes: true })\n .filter((dirent) => dirent.isDirectory())\n .map((dirent) => dirent.name);\n } catch (error) {\n console.error(`Error reading apps directory: ${error}`);\n return [];\n }\n}\n\n/**\n * テンプレートディレクトリからパッケージ一覧を取得\n * @param templateDir - テンプレートディレクトリのパス\n * @returns パッケージ名の配列\n */\nfunction getAvailablePackages(templateDir: string): string[] {\n const packagesDir = path.join(templateDir, \"packages\");\n try {\n if (!fs.existsSync(packagesDir)) {\n return [];\n }\n return fs\n .readdirSync(packagesDir, { withFileTypes: true })\n .filter((dirent) => dirent.isDirectory())\n .map((dirent) => dirent.name);\n } catch (error) {\n console.error(`Error reading packages directory: ${error}`);\n return [];\n }\n}\n\n/**\n * カテゴリ選択プロンプトを実行(5段階)\n * @param templateDir - テンプレートディレクトリのパス\n * @returns SyncPromptResult - 同期設定\n */\nexport async function promptSyncCategories(\n templateDir: string,\n): Promise<SyncPromptResult> {\n // ステージ1: 大カテゴリ選択\n const categoryAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"categories\",\n message: \"同期する項目を選択してください(Spaceで選択、Enterで確定):\",\n choices: Object.entries(CATEGORY_CONFIGS).map(([key, config]) => ({\n name: `${config.name} - ${config.description}`,\n value: key,\n checked: config.defaultChecked ?? false,\n })),\n },\n ]);\n\n const selectedCategories = categoryAnswers.categories as SyncCategory[];\n const hasApps = selectedCategories.includes(\"apps\");\n const hasPackages = selectedCategories.includes(\"packages\");\n const hasRootConfig = selectedCategories.includes(\"root-config\");\n\n let appsDetail: string[] | undefined;\n let packagesDetail: string[] | undefined;\n let packageJsonSections: Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"engines\"> | undefined;\n let conflictStrategy: \"merge\" | \"overwrite\" | \"skip\" = \"merge\";\n\n // ステージ2: apps詳細選択(appsが選択された場合のみ)\n if (hasApps) {\n const availableApps = getAvailableApps(templateDir);\n if (availableApps.length > 0) {\n const appsAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"apps\",\n message: \"同期するアプリケーションを選択:\",\n choices: availableApps.map((app) => ({\n name: app,\n value: app,\n checked: true,\n })),\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのアプリを選択してください\";\n }\n return true;\n },\n },\n ]);\n appsDetail = appsAnswers.apps as string[];\n } else {\n console.warn(\"警告: apps/ ディレクトリが見つからないか、アプリが存在しません\");\n appsDetail = [];\n }\n }\n\n // ステージ3: packages詳細選択(packagesが選択された場合のみ)\n if (hasPackages) {\n const availablePackages = getAvailablePackages(templateDir);\n if (availablePackages.length > 0) {\n const packagesAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"packages\",\n message: \"同期するパッケージを選択:\",\n choices: availablePackages.map((pkg) => ({\n name: pkg,\n value: pkg,\n checked: true,\n })),\n validate: (input: string[]): boolean | string => {\n if (input.length === 0) {\n return \"少なくとも1つのパッケージを選択してください\";\n }\n return true;\n },\n },\n ]);\n packagesDetail = packagesAnswers.packages as string[];\n } else {\n console.warn(\"警告: packages/ ディレクトリが見つからないか、パッケージが存在しません\");\n packagesDetail = [];\n }\n }\n\n // ステージ4: package.json セクション選択(root-configが選択された場合のみ)\n if (hasRootConfig) {\n const packageJsonAnswers = await inquirer.prompt([\n {\n type: \"checkbox\",\n name: \"sections\",\n message: \"package.jsonの同期セクションを選択:\",\n choices: [\n { name: \"scripts(推奨)\", value: \"scripts\", checked: true },\n { name: \"engines(推奨)\", value: \"engines\", checked: true },\n { name: \"dependencies\", value: \"dependencies\", checked: false },\n { name: \"devDependencies\", value: \"devDependencies\", checked: false },\n ],\n },\n ]);\n packageJsonSections = packageJsonAnswers.sections as Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"engines\">;\n }\n\n // ステージ5: 競合解決戦略選択\n const strategyAnswers = await inquirer.prompt([\n {\n type: \"list\",\n name: \"conflictStrategy\",\n message: \"競合解決戦略を選択してください:\",\n choices: [\n { name: \"マーカーベースマージ(推奨)\", value: \"merge\" },\n { name: \"テンプレートで上書き\", value: \"overwrite\" },\n { name: \"既存ファイル優先\", value: \"skip\" },\n ],\n default: \"merge\",\n },\n ]);\n conflictStrategy = strategyAnswers.conflictStrategy as \"merge\" | \"overwrite\" | \"skip\";\n\n return {\n categories: selectedCategories,\n appsDetail,\n packagesDetail,\n packageJsonSections,\n conflictStrategy,\n };\n}\n","import fsExtra from \"fs-extra\";\nimport { join, dirname, relative } from \"node:path\";\nimport * as logger from \"./logger.js\";\n\n/**\n * バックアップ情報\n */\nexport interface BackupInfo {\n /** バックアップディレクトリパス */\n path: string;\n /** バックアップディレクトリ名 */\n name: string;\n /** 作成日時 */\n timestamp: Date;\n}\n\nconst { copy, ensureDir, readdir, remove, pathExists } = fsExtra;\n\n/**\n * 現在のタイムスタンプを取得(YYYY-MM-DD_HH-mm-ss形式)\n * @returns タイムスタンプ文字列\n */\nfunction getTimestamp(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, \"0\");\n const day = String(now.getDate()).padStart(2, \"0\");\n const hours = String(now.getHours()).padStart(2, \"0\");\n const minutes = String(now.getMinutes()).padStart(2, \"0\");\n const seconds = String(now.getSeconds()).padStart(2, \"0\");\n return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;\n}\n\n/**\n * バックアップディレクトリ名からタイムスタンプを抽出\n * @param dirName - バックアップディレクトリ名\n * @returns タイムスタンプのDate オブジェクト(失敗時は null)\n */\nfunction parseBackupTimestamp(dirName: string): Date | null {\n const match = dirName.match(/^\\.einja-sync-backup-(\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2})$/);\n if (!match || !match[1]) {\n return null;\n }\n\n const timestampStr = match[1];\n const parts = timestampStr.split(\"_\");\n if (parts.length !== 2) {\n return null;\n }\n\n const [datePart, timePart] = parts;\n if (!datePart || !timePart) {\n return null;\n }\n\n const dateParts = datePart.split(\"-\").map(Number);\n const timeParts = timePart.split(\"-\").map(Number);\n\n if (dateParts.length !== 3 || timeParts.length !== 3) {\n return null;\n }\n\n const [year, month, day] = dateParts;\n const [hours, minutes, seconds] = timeParts;\n\n if (\n year === undefined || month === undefined || day === undefined ||\n hours === undefined || minutes === undefined || seconds === undefined\n ) {\n return null;\n }\n\n return new Date(year, month - 1, day, hours, minutes, seconds);\n}\n\n/**\n * 同期前のバックアップを作成\n * @param targetDir - 対象ディレクトリ\n * @param filesToBackup - バックアップするファイルのリスト\n * @returns バックアップディレクトリパス\n */\nexport async function createBackup(\n targetDir: string,\n filesToBackup: string[]\n): Promise<string> {\n const timestamp = getTimestamp();\n const backupDirName = `.einja-sync-backup-${timestamp}`;\n const backupDir = join(targetDir, backupDirName);\n\n try {\n // バックアップディレクトリを作成\n await ensureDir(backupDir);\n\n // ファイルをバックアップ\n for (const file of filesToBackup) {\n const sourcePath = join(targetDir, file);\n const destPath = join(backupDir, file);\n\n // ファイルが存在するか確認\n if (!(await pathExists(sourcePath))) {\n continue;\n }\n\n // 宛先ディレクトリを作成\n await ensureDir(dirname(destPath));\n\n // ファイルをコピー\n await copy(sourcePath, destPath);\n }\n\n return backupDir;\n } catch (error) {\n logger.error(`バックアップの作成に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n}\n\n/**\n * バックアップから復元\n * @param backupDir - バックアップディレクトリパス\n * @param targetDir - 復元先ディレクトリ\n * @returns 成功の場合 true\n */\nexport async function restoreFromBackup(\n backupDir: string,\n targetDir: string\n): Promise<boolean> {\n try {\n // バックアップディレクトリの存在確認\n if (!(await pathExists(backupDir))) {\n logger.error(`バックアップディレクトリが見つかりません: ${backupDir}`);\n return false;\n }\n\n // バックアップ内のファイル一覧を取得\n const files = await getAllFiles(backupDir);\n\n // ファイルを復元\n for (const file of files) {\n const sourcePath = join(backupDir, file);\n const destPath = join(targetDir, file);\n\n // 宛先ディレクトリを作成\n await ensureDir(dirname(destPath));\n\n // ファイルをコピー(上書き)\n await copy(sourcePath, destPath, { overwrite: true });\n }\n\n return true;\n } catch (error) {\n logger.error(`バックアップからの復元に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n return false;\n }\n}\n\n/**\n * ディレクトリ内のすべてのファイルを再帰的に取得\n * @param dirPath - ディレクトリパス\n * @param baseDir - ベースディレクトリ(相対パス計算用)\n * @returns ファイルパスの配列(相対パス)\n */\nasync function getAllFiles(dirPath: string, baseDir?: string): Promise<string[]> {\n const base = baseDir ?? dirPath;\n const entries = await readdir(dirPath, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const fullPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n const subFiles = await getAllFiles(fullPath, base);\n files.push(...subFiles);\n } else {\n files.push(relative(base, fullPath));\n }\n }\n\n return files;\n}\n\n/**\n * 利用可能なバックアップ一覧を取得\n * @param targetDir - 対象ディレクトリ\n * @returns バックアップ情報の配列\n */\nexport async function listBackups(targetDir: string): Promise<BackupInfo[]> {\n try {\n // ディレクトリの存在確認\n if (!(await pathExists(targetDir))) {\n return [];\n }\n\n const entries = await readdir(targetDir, { withFileTypes: true });\n const backups: BackupInfo[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) {\n continue;\n }\n\n const timestamp = parseBackupTimestamp(entry.name);\n if (!timestamp) {\n continue;\n }\n\n backups.push({\n path: join(targetDir, entry.name),\n name: entry.name,\n timestamp,\n });\n }\n\n // タイムスタンプでソート(新しい順)\n backups.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n\n return backups;\n } catch (error) {\n logger.error(`バックアップ一覧の取得に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n return [];\n }\n}\n\n/**\n * 古いバックアップを削除\n * @param targetDir - 対象ディレクトリ\n * @param retentionDays - 保持日数(デフォルト: 7)\n * @returns 削除したバックアップ数\n */\nexport async function cleanOldBackups(\n targetDir: string,\n retentionDays = 7\n): Promise<number> {\n try {\n const backups = await listBackups(targetDir);\n const now = Date.now();\n const retentionMs = retentionDays * 24 * 60 * 60 * 1000;\n let deletedCount = 0;\n\n for (const backup of backups) {\n const age = now - backup.timestamp.getTime();\n if (age > retentionMs) {\n await remove(backup.path);\n deletedCount++;\n logger.info(`古いバックアップを削除しました: ${backup.name}`);\n }\n }\n\n return deletedCount;\n } catch (error) {\n logger.error(`バックアップの削除に失敗しました: ${error instanceof Error ? error.message : String(error)}`);\n return 0;\n }\n}\n\n/**\n * 最新のバックアップを取得\n * @param targetDir - 対象ディレクトリ\n * @returns 最新のバックアップ情報(存在しない場合は null)\n */\nexport async function getLatestBackup(targetDir: string): Promise<BackupInfo | null> {\n const backups = await listBackups(targetDir);\n return backups.length > 0 ? backups[0] ?? null : null;\n}\n","import { execSync } from \"node:child_process\";\nimport * as logger from \"./logger.js\";\n\n/**\n * カレントディレクトリがGitリポジトリかチェック\n * @param targetDir - 対象ディレクトリ(省略時はカレント)\n * @returns Gitリポジトリの場合 true\n */\nexport function isGitRepository(targetDir?: string): boolean {\n try {\n const cwd = targetDir || process.cwd();\n execSync(\"git rev-parse --is-inside-work-tree\", {\n cwd,\n stdio: \"ignore\",\n });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 未コミットの変更があるかチェック\n * @param targetDir - 対象ディレクトリ(省略時はカレント)\n * @returns 未コミットの変更がある場合 true\n */\nexport function hasUncommittedChanges(targetDir?: string): boolean {\n if (!isGitRepository(targetDir)) {\n logger.warn(\"⚠️ このディレクトリはGitリポジトリではありません\");\n return false;\n }\n\n try {\n const cwd = targetDir || process.cwd();\n const output = execSync(\"git status --porcelain\", {\n cwd,\n encoding: \"utf-8\",\n });\n return output.trim().length > 0;\n } catch (error) {\n logger.warn(`⚠️ Gitステータス確認中にエラーが発生しました: ${error}`);\n return false;\n }\n}\n\n/**\n * sync コマンド実行前のGitステータスチェック\n * @param force - --forceフラグ\n * @param targetDir - 対象ディレクトリ(省略時はカレント)\n * @returns チェック通過の場合 true、ブロックの場合 process.exit(1)\n */\nexport function checkGitStatusForSync(\n force: boolean,\n targetDir?: string,\n): boolean {\n // 1. Gitリポジトリかチェック\n if (!isGitRepository(targetDir)) {\n logger.warn(\"⚠️ このディレクトリはGitリポジトリではありません\");\n logger.warn(\n \" sync実行後の差分確認は `git diff` で行うことを推奨します\",\n );\n // 処理は続行(警告のみ)\n return true;\n }\n\n // 2. 未コミット変更チェック\n if (hasUncommittedChanges(targetDir)) {\n if (!force) {\n // デフォルトでブロック\n logger.error(\"❌ 未コミットの変更があります\");\n logger.error(\n \" 変更をコミットしてから実行するか、--force フラグを使用してください\",\n );\n process.exit(1);\n }\n\n // --force 指定時は警告のみ\n logger.warn(\"⚠️ 未コミットの変更がありますが、--force により続行します\");\n logger.warn(\n \" 問題が発生した場合は `git checkout .` で復元できます\",\n );\n }\n\n return true;\n}\n"],"mappings":"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","names":["readFileSync","fileURLToPath","dirname","join","existsSync","ora","dirname","join","readFileSync","writeFileSync","existsSync","__filename","__dirname","dirname","join","error","chalk","inquirer","inquirer","error","chalk","existsSync","error","ora","existsSync","join","ora","inquirer","join","inquirer","join","inquirer","error","join","readFileSync","writeFileSync","join","packageJsonPath","join","readFileSync","writeFileSync","join","join","join","join","join","join","writeFileSync","join","writeFileSync","packageJsonPath","join","existsSync","ora","error","existsSync","readFile","dirname","join","fileURLToPath","ora","inquirer","join","readFileSync","writeFileSync","existsSync","dirname","inquirer","inquirer","existsSync","readFileSync","dirname","writeFileSync","join","readdir","join","join","copyDirectory","readdir","readdir","join","relative","join","readdir","relative","path","getTemplatePath","__filename","fileURLToPath","__dirname","dirname","join","existsSync","readFile","ora","error","packageJsonPath","packageJson","dirname","join","fileURLToPath","fsExtra","inquirer","glob","glob","error","inquirer","error","inquirer","fsExtra","join","dirname","relative","ensureDir","readdir","fsExtra","join","dirname","error","relative","execSync","execSync","error","inquirer","success","getTemplatePath","__filename","fileURLToPath","__dirname","dirname","existsSync","fsExtra","join","error","targetDir","__filename","fileURLToPath","__dirname","dirname","join","readFileSync"]}
|