create-einja-app 0.2.9 → 0.2.11

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/dist/cli.js CHANGED
@@ -3,8 +3,8 @@
3
3
  // src/cli.ts
4
4
  import { Command } from "commander";
5
5
  import { readFileSync as readFileSync5 } from "fs";
6
- import { fileURLToPath as fileURLToPath3 } from "url";
7
- import { dirname as dirname5, join as join14 } from "path";
6
+ import { fileURLToPath as fileURLToPath4 } from "url";
7
+ import { dirname as dirname7, join as join17 } from "path";
8
8
 
9
9
  // src/commands/create.ts
10
10
  import { existsSync as existsSync3, readdirSync } from "fs";
@@ -1165,7 +1165,99 @@ import { join as join10 } from "path";
1165
1165
 
1166
1166
  // src/utils/merger.ts
1167
1167
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync5 } from "fs";
1168
- import { dirname as dirname3 } from "path";
1168
+ import { dirname as dirname3, basename } from "path";
1169
+
1170
+ // src/utils/package-json-merger.ts
1171
+ import inquirer6 from "inquirer";
1172
+ function hasVersionConflict(existingVersion, templateVersion) {
1173
+ if (existingVersion === templateVersion) {
1174
+ return false;
1175
+ }
1176
+ const normalize = (v) => v.replace(/^[\^~]/, "");
1177
+ return normalize(existingVersion) !== normalize(templateVersion);
1178
+ }
1179
+ async function mergeDependenciesWithConflictDetection(existing, template) {
1180
+ const merged = { ...existing };
1181
+ const conflicts = [];
1182
+ for (const [packageName, templateVersion] of Object.entries(template)) {
1183
+ if (packageName in existing) {
1184
+ const existingVersion = existing[packageName];
1185
+ if (existingVersion && hasVersionConflict(existingVersion, templateVersion)) {
1186
+ conflicts.push({
1187
+ packageName,
1188
+ existingVersion,
1189
+ templateVersion
1190
+ });
1191
+ } else {
1192
+ merged[packageName] = templateVersion;
1193
+ }
1194
+ } else {
1195
+ merged[packageName] = templateVersion;
1196
+ }
1197
+ }
1198
+ return { merged, conflicts };
1199
+ }
1200
+ async function resolveVersionConflicts(conflicts) {
1201
+ const resolutions = /* @__PURE__ */ new Map();
1202
+ warn(`
1203
+ \u26A0\uFE0F ${conflicts.length}\u500B\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u3067\u30D0\u30FC\u30B8\u30E7\u30F3\u7AF6\u5408\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F:
1204
+ `);
1205
+ for (const conflict of conflicts) {
1206
+ warn(`\u{1F4E6} ${conflict.packageName}`);
1207
+ warn(` \u65E2\u5B58: ${conflict.existingVersion}`);
1208
+ warn(` \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8: ${conflict.templateVersion}
1209
+ `);
1210
+ const answer = await inquirer6.prompt([
1211
+ {
1212
+ type: "list",
1213
+ name: "version",
1214
+ message: "\u3069\u3061\u3089\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u307E\u3059\u304B\uFF1F",
1215
+ choices: [
1216
+ {
1217
+ name: `\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 (${conflict.templateVersion})`,
1218
+ value: "template"
1219
+ },
1220
+ {
1221
+ name: `\u65E2\u5B58 (${conflict.existingVersion})`,
1222
+ value: "existing"
1223
+ },
1224
+ {
1225
+ name: "\u30B9\u30AD\u30C3\u30D7\uFF08\u65E2\u5B58\u3092\u7DAD\u6301\uFF09",
1226
+ value: "skip"
1227
+ }
1228
+ ]
1229
+ }
1230
+ ]);
1231
+ if (answer.version === "template") {
1232
+ resolutions.set(conflict.packageName, conflict.templateVersion);
1233
+ } else if (answer.version === "existing") {
1234
+ resolutions.set(conflict.packageName, conflict.existingVersion);
1235
+ }
1236
+ }
1237
+ return resolutions;
1238
+ }
1239
+ async function mergePackageJsonDependencies(existingDeps, templateDeps, skipPrompts = false) {
1240
+ const { merged, conflicts } = await mergeDependenciesWithConflictDetection(
1241
+ existingDeps,
1242
+ templateDeps
1243
+ );
1244
+ if (conflicts.length === 0) {
1245
+ return merged;
1246
+ }
1247
+ if (skipPrompts) {
1248
+ info(
1249
+ `\u30D0\u30FC\u30B8\u30E7\u30F3\u7AF6\u5408\u304C${conflicts.length}\u500B\u3042\u308A\u307E\u3059\u304C\u3001\u65E2\u5B58\u30D0\u30FC\u30B8\u30E7\u30F3\u3092\u7DAD\u6301\u3057\u307E\u3059`
1250
+ );
1251
+ return merged;
1252
+ }
1253
+ const resolutions = await resolveVersionConflicts(conflicts);
1254
+ for (const [packageName, version] of resolutions.entries()) {
1255
+ merged[packageName] = version;
1256
+ }
1257
+ return merged;
1258
+ }
1259
+
1260
+ // src/utils/merger.ts
1169
1261
  function mergeTextWithMarkers(templateContent, existingContent) {
1170
1262
  if (existingContent === null) {
1171
1263
  return templateContent;
@@ -1291,16 +1383,60 @@ async function saveSyncMetadata(targetDir, metadata) {
1291
1383
  ensureDir(dirname3(metadataPath));
1292
1384
  writeFileSync5(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
1293
1385
  }
1294
- async function mergeAndWriteFile(templatePath, targetPath, syncMetadata) {
1386
+ async function mergePackageJson(existingContent, templateContent, packageJsonSections) {
1387
+ const existingPkg = JSON.parse(existingContent);
1388
+ const templatePkg = JSON.parse(templateContent);
1389
+ const result = { ...existingPkg };
1390
+ if ((!packageJsonSections || packageJsonSections.includes("scripts")) && templatePkg.scripts && typeof templatePkg.scripts === "object") {
1391
+ result.scripts = {
1392
+ ...existingPkg.scripts && typeof existingPkg.scripts === "object" ? existingPkg.scripts : {},
1393
+ ...templatePkg.scripts
1394
+ };
1395
+ }
1396
+ if ((!packageJsonSections || packageJsonSections.includes("dependencies")) && templatePkg.dependencies && typeof templatePkg.dependencies === "object") {
1397
+ result.dependencies = await mergePackageJsonDependencies(
1398
+ existingPkg.dependencies && typeof existingPkg.dependencies === "object" ? existingPkg.dependencies : {},
1399
+ templatePkg.dependencies,
1400
+ false
1401
+ );
1402
+ }
1403
+ if ((!packageJsonSections || packageJsonSections.includes("devDependencies")) && templatePkg.devDependencies && typeof templatePkg.devDependencies === "object") {
1404
+ result.devDependencies = await mergePackageJsonDependencies(
1405
+ existingPkg.devDependencies && typeof existingPkg.devDependencies === "object" ? existingPkg.devDependencies : {},
1406
+ templatePkg.devDependencies,
1407
+ false
1408
+ );
1409
+ }
1410
+ if ((!packageJsonSections || packageJsonSections.includes("engines")) && templatePkg.engines && typeof templatePkg.engines === "object") {
1411
+ if (existingPkg.engines && JSON.stringify(existingPkg.engines) !== JSON.stringify(templatePkg.engines)) {
1412
+ warn("\u26A0\uFE0F engines \u3092\u7F6E\u63DB\u3057\u307E\u3059:");
1413
+ warn(` \u65E2\u5B58: ${JSON.stringify(existingPkg.engines)}`);
1414
+ warn(` \u65B0\u898F: ${JSON.stringify(templatePkg.engines)}`);
1415
+ }
1416
+ result.engines = templatePkg.engines;
1417
+ }
1418
+ return `${JSON.stringify(result, null, 2)}
1419
+ `;
1420
+ }
1421
+ async function mergeAndWriteFile(templatePath, targetPath, syncMetadata, packageJsonSections) {
1295
1422
  const templateContent = readFileSync4(templatePath, "utf-8");
1296
1423
  const targetExists = existsSync5(targetPath);
1297
1424
  const existingContent = targetExists ? readFileSync4(targetPath, "utf-8") : null;
1298
1425
  const isJsonFile = targetPath.endsWith(".json");
1426
+ const isPackageJson = basename(targetPath) === "package.json";
1299
1427
  let mergedContent;
1300
1428
  let action;
1301
1429
  if (!targetExists) {
1302
1430
  mergedContent = templateContent;
1303
1431
  action = "created";
1432
+ } else if (isPackageJson && existingContent) {
1433
+ try {
1434
+ mergedContent = await mergePackageJson(existingContent, templateContent, packageJsonSections);
1435
+ action = "merged";
1436
+ } catch {
1437
+ mergedContent = templateContent;
1438
+ action = "overwritten";
1439
+ }
1304
1440
  } else if (isJsonFile) {
1305
1441
  try {
1306
1442
  const templateJson = JSON.parse(templateContent);
@@ -1646,16 +1782,16 @@ function shouldExclude(relativePath, excludedPaths, gitignorePatterns) {
1646
1782
  }
1647
1783
  return false;
1648
1784
  }
1649
- function matchPattern(path, pattern) {
1785
+ function matchPattern(path2, pattern) {
1650
1786
  if (pattern.endsWith("/")) {
1651
1787
  const dirPattern = pattern.slice(0, -1);
1652
- return path === dirPattern || path.startsWith(`${dirPattern}/`);
1788
+ return path2 === dirPattern || path2.startsWith(`${dirPattern}/`);
1653
1789
  }
1654
1790
  if (pattern.includes("*")) {
1655
1791
  const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
1656
- return new RegExp(`^${regexPattern}$`).test(path);
1792
+ return new RegExp(`^${regexPattern}$`).test(path2);
1657
1793
  }
1658
- return path === pattern || path.startsWith(`${pattern}/`);
1794
+ return path2 === pattern || path2.startsWith(`${pattern}/`);
1659
1795
  }
1660
1796
 
1661
1797
  // src/commands/add.ts
@@ -1831,14 +1967,733 @@ async function addCommand(options) {
1831
1967
  }
1832
1968
  }
1833
1969
 
1970
+ // src/commands/sync.ts
1971
+ import { dirname as dirname6, join as join16 } from "path";
1972
+ import { fileURLToPath as fileURLToPath3 } from "url";
1973
+ import fsExtra3 from "fs-extra";
1974
+ import inquirer8 from "inquirer";
1975
+
1976
+ // src/generators/sync.ts
1977
+ import { glob as glob2 } from "glob";
1978
+ var CATEGORY_PATTERNS = {
1979
+ env: [".env*", ".envrc", ".volta", ".node-version"],
1980
+ tools: ["biome.json", ".prettierrc*", ".editorconfig", ".vscode/**"],
1981
+ git: [".gitignore", ".gitattributes"],
1982
+ "git-hooks": [".husky/**"],
1983
+ github: [".github/workflows/**", ".github/actions/**", ".github/dependabot.yml"],
1984
+ docker: ["Dockerfile*", "docker-compose*.yml", ".dockerignore"],
1985
+ monorepo: ["turbo.json", "pnpm-workspace.yaml"],
1986
+ "root-config": ["package.json", "tsconfig.json"],
1987
+ apps: ["apps/**"],
1988
+ packages: ["packages/**"],
1989
+ docs: ["README.md", "docs/**"]
1990
+ };
1991
+ var ENV_FILE_PROTECTION = {
1992
+ protected: [".env.keys", ".env.personal"]
1993
+ };
1994
+ function isProtectedEnvFile(filePath) {
1995
+ return ENV_FILE_PROTECTION.protected.some(
1996
+ (pattern) => filePath.endsWith(pattern)
1997
+ );
1998
+ }
1999
+ function extractPatternsFromCategories(categories, appsDetail, packagesDetail) {
2000
+ const patterns = [];
2001
+ for (const category of categories) {
2002
+ const categoryPatterns = CATEGORY_PATTERNS[category];
2003
+ if (!categoryPatterns) {
2004
+ warn(`\u4E0D\u660E\u306A\u30AB\u30C6\u30B4\u30EA: ${category}`);
2005
+ continue;
2006
+ }
2007
+ if (category === "apps" && appsDetail && appsDetail.length > 0) {
2008
+ patterns.push(...appsDetail.map((app) => `apps/${app}/**`));
2009
+ } else if (category === "packages" && packagesDetail && packagesDetail.length > 0) {
2010
+ patterns.push(...packagesDetail.map((pkg) => `packages/${pkg}/**`));
2011
+ } else {
2012
+ patterns.push(...categoryPatterns);
2013
+ }
2014
+ }
2015
+ return patterns;
2016
+ }
2017
+ async function collectSyncFiles(templateDir, categories, appsDetail, packagesDetail) {
2018
+ try {
2019
+ info("\u540C\u671F\u5BFE\u8C61\u30D5\u30A1\u30A4\u30EB\u3092\u53CE\u96C6\u4E2D...");
2020
+ const patterns = extractPatternsFromCategories(
2021
+ categories,
2022
+ appsDetail,
2023
+ packagesDetail
2024
+ );
2025
+ if (patterns.length === 0) {
2026
+ warn("\u540C\u671F\u5BFE\u8C61\u306E\u30D1\u30BF\u30FC\u30F3\u304C\u3042\u308A\u307E\u305B\u3093");
2027
+ return [];
2028
+ }
2029
+ const fileSet = /* @__PURE__ */ new Set();
2030
+ for (const pattern of patterns) {
2031
+ try {
2032
+ const files = await glob2(pattern, {
2033
+ cwd: templateDir,
2034
+ dot: true,
2035
+ // .で始まるファイルも含める
2036
+ nodir: true
2037
+ // ディレクトリは除外
2038
+ });
2039
+ for (const file of files) {
2040
+ fileSet.add(file);
2041
+ }
2042
+ } catch (error2) {
2043
+ warn(`\u30D1\u30BF\u30FC\u30F3 ${pattern} \u306E\u51E6\u7406\u4E2D\u306B\u30A8\u30E9\u30FC: ${error2}`);
2044
+ }
2045
+ }
2046
+ const allFiles = Array.from(fileSet);
2047
+ const filteredFiles = allFiles.filter((file) => {
2048
+ if (isProtectedEnvFile(file)) {
2049
+ info(`\u4FDD\u8B77\u5BFE\u8C61\u30D5\u30A1\u30A4\u30EB\u3092\u9664\u5916: ${file}`);
2050
+ return false;
2051
+ }
2052
+ return true;
2053
+ });
2054
+ success(`${filteredFiles.length}\u500B\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u53CE\u96C6\u3057\u307E\u3057\u305F`);
2055
+ return filteredFiles.sort();
2056
+ } catch (error2) {
2057
+ error(`\u30D5\u30A1\u30A4\u30EB\u53CE\u96C6\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F: ${error2}`);
2058
+ throw error2;
2059
+ }
2060
+ }
2061
+
2062
+ // src/prompts/sync.ts
2063
+ import inquirer7 from "inquirer";
2064
+ import * as fs from "fs";
2065
+ import * as path from "path";
2066
+ var CATEGORY_CONFIGS = {
2067
+ env: {
2068
+ name: "\u74B0\u5883\u8A2D\u5B9A",
2069
+ description: ".env*, .envrc, .volta, .node-version",
2070
+ patterns: [".env*", ".envrc", ".volta", ".node-version"],
2071
+ defaultChecked: true
2072
+ },
2073
+ tools: {
2074
+ name: "\u958B\u767A\u30C4\u30FC\u30EB",
2075
+ description: "biome.json, .prettierrc, .editorconfig, .vscode/",
2076
+ patterns: ["biome.json", ".prettierrc*", ".editorconfig", ".vscode/"],
2077
+ defaultChecked: true
2078
+ },
2079
+ git: {
2080
+ name: "Git\u8A2D\u5B9A",
2081
+ description: ".gitignore, .gitattributes",
2082
+ patterns: [".gitignore", ".gitattributes"],
2083
+ defaultChecked: false
2084
+ },
2085
+ "git-hooks": {
2086
+ name: "Git Hooks",
2087
+ description: ".husky/",
2088
+ patterns: [".husky/"],
2089
+ defaultChecked: false
2090
+ },
2091
+ github: {
2092
+ name: "CI/CD",
2093
+ description: ".github/workflows/, .github/actions/",
2094
+ patterns: [".github/workflows/", ".github/actions/", ".github/dependabot.yml"],
2095
+ defaultChecked: false
2096
+ },
2097
+ docker: {
2098
+ name: "\u30B3\u30F3\u30C6\u30CA",
2099
+ description: "Dockerfile*, docker-compose.yml, .dockerignore",
2100
+ patterns: ["Dockerfile*", "docker-compose*.yml", ".dockerignore"],
2101
+ defaultChecked: false
2102
+ },
2103
+ monorepo: {
2104
+ name: "\u30E2\u30CE\u30EC\u30DD\u69CB\u6210",
2105
+ description: "turbo.json, pnpm-workspace.yaml",
2106
+ patterns: ["turbo.json", "pnpm-workspace.yaml"],
2107
+ defaultChecked: false
2108
+ },
2109
+ "root-config": {
2110
+ name: "\u30EB\u30FC\u30C8\u8A2D\u5B9A",
2111
+ description: "package.json, tsconfig.json",
2112
+ patterns: ["package.json", "tsconfig.json"],
2113
+ defaultChecked: false
2114
+ },
2115
+ apps: {
2116
+ name: "\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3",
2117
+ description: "apps/ \u914D\u4E0B\uFF08\u6B21\u306E\u753B\u9762\u3067\u500B\u5225\u9078\u629E\uFF09",
2118
+ patterns: ["apps/**"],
2119
+ defaultChecked: false,
2120
+ requiresDetailSelection: true
2121
+ },
2122
+ packages: {
2123
+ name: "\u5171\u901A\u30D1\u30C3\u30B1\u30FC\u30B8",
2124
+ description: "packages/ \u914D\u4E0B\uFF08\u6B21\u306E\u753B\u9762\u3067\u500B\u5225\u9078\u629E\uFF09",
2125
+ patterns: ["packages/**"],
2126
+ defaultChecked: false,
2127
+ requiresDetailSelection: true
2128
+ },
2129
+ docs: {
2130
+ name: "\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8",
2131
+ description: "README.md, docs/",
2132
+ patterns: ["README.md", "docs/**"],
2133
+ defaultChecked: false
2134
+ }
2135
+ };
2136
+ function getAvailableApps(templateDir) {
2137
+ const appsDir = path.join(templateDir, "apps");
2138
+ try {
2139
+ if (!fs.existsSync(appsDir)) {
2140
+ return [];
2141
+ }
2142
+ return fs.readdirSync(appsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
2143
+ } catch (error2) {
2144
+ console.error(`Error reading apps directory: ${error2}`);
2145
+ return [];
2146
+ }
2147
+ }
2148
+ function getAvailablePackages(templateDir) {
2149
+ const packagesDir = path.join(templateDir, "packages");
2150
+ try {
2151
+ if (!fs.existsSync(packagesDir)) {
2152
+ return [];
2153
+ }
2154
+ return fs.readdirSync(packagesDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
2155
+ } catch (error2) {
2156
+ console.error(`Error reading packages directory: ${error2}`);
2157
+ return [];
2158
+ }
2159
+ }
2160
+ async function promptSyncCategories(templateDir) {
2161
+ const categoryAnswers = await inquirer7.prompt([
2162
+ {
2163
+ type: "checkbox",
2164
+ name: "categories",
2165
+ message: "\u540C\u671F\u3059\u308B\u9805\u76EE\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08Space\u3067\u9078\u629E\u3001Enter\u3067\u78BA\u5B9A\uFF09:",
2166
+ choices: Object.entries(CATEGORY_CONFIGS).map(([key, config]) => ({
2167
+ name: `${config.name} - ${config.description}`,
2168
+ value: key,
2169
+ checked: config.defaultChecked ?? false
2170
+ }))
2171
+ }
2172
+ ]);
2173
+ const selectedCategories = categoryAnswers.categories;
2174
+ const hasApps = selectedCategories.includes("apps");
2175
+ const hasPackages = selectedCategories.includes("packages");
2176
+ const hasRootConfig = selectedCategories.includes("root-config");
2177
+ let appsDetail;
2178
+ let packagesDetail;
2179
+ let packageJsonSections;
2180
+ let conflictStrategy = "merge";
2181
+ if (hasApps) {
2182
+ const availableApps = getAvailableApps(templateDir);
2183
+ if (availableApps.length > 0) {
2184
+ const appsAnswers = await inquirer7.prompt([
2185
+ {
2186
+ type: "checkbox",
2187
+ name: "apps",
2188
+ message: "\u540C\u671F\u3059\u308B\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3092\u9078\u629E:",
2189
+ choices: availableApps.map((app) => ({
2190
+ name: app,
2191
+ value: app,
2192
+ checked: true
2193
+ })),
2194
+ validate: (input) => {
2195
+ if (input.length === 0) {
2196
+ return "\u5C11\u306A\u304F\u3068\u30821\u3064\u306E\u30A2\u30D7\u30EA\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044";
2197
+ }
2198
+ return true;
2199
+ }
2200
+ }
2201
+ ]);
2202
+ appsDetail = appsAnswers.apps;
2203
+ } else {
2204
+ console.warn("\u8B66\u544A: apps/ \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u3089\u306A\u3044\u304B\u3001\u30A2\u30D7\u30EA\u304C\u5B58\u5728\u3057\u307E\u305B\u3093");
2205
+ appsDetail = [];
2206
+ }
2207
+ }
2208
+ if (hasPackages) {
2209
+ const availablePackages = getAvailablePackages(templateDir);
2210
+ if (availablePackages.length > 0) {
2211
+ const packagesAnswers = await inquirer7.prompt([
2212
+ {
2213
+ type: "checkbox",
2214
+ name: "packages",
2215
+ message: "\u540C\u671F\u3059\u308B\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u9078\u629E:",
2216
+ choices: availablePackages.map((pkg) => ({
2217
+ name: pkg,
2218
+ value: pkg,
2219
+ checked: true
2220
+ })),
2221
+ validate: (input) => {
2222
+ if (input.length === 0) {
2223
+ return "\u5C11\u306A\u304F\u3068\u30821\u3064\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044";
2224
+ }
2225
+ return true;
2226
+ }
2227
+ }
2228
+ ]);
2229
+ packagesDetail = packagesAnswers.packages;
2230
+ } else {
2231
+ console.warn("\u8B66\u544A: packages/ \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u3089\u306A\u3044\u304B\u3001\u30D1\u30C3\u30B1\u30FC\u30B8\u304C\u5B58\u5728\u3057\u307E\u305B\u3093");
2232
+ packagesDetail = [];
2233
+ }
2234
+ }
2235
+ if (hasRootConfig) {
2236
+ const packageJsonAnswers = await inquirer7.prompt([
2237
+ {
2238
+ type: "checkbox",
2239
+ name: "sections",
2240
+ message: "package.json\u306E\u540C\u671F\u30BB\u30AF\u30B7\u30E7\u30F3\u3092\u9078\u629E:",
2241
+ choices: [
2242
+ { name: "scripts\uFF08\u63A8\u5968\uFF09", value: "scripts", checked: true },
2243
+ { name: "engines\uFF08\u63A8\u5968\uFF09", value: "engines", checked: true },
2244
+ { name: "dependencies", value: "dependencies", checked: false },
2245
+ { name: "devDependencies", value: "devDependencies", checked: false }
2246
+ ]
2247
+ }
2248
+ ]);
2249
+ packageJsonSections = packageJsonAnswers.sections;
2250
+ }
2251
+ const strategyAnswers = await inquirer7.prompt([
2252
+ {
2253
+ type: "list",
2254
+ name: "conflictStrategy",
2255
+ message: "\u7AF6\u5408\u89E3\u6C7A\u6226\u7565\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044:",
2256
+ choices: [
2257
+ { name: "\u30DE\u30FC\u30AB\u30FC\u30D9\u30FC\u30B9\u30DE\u30FC\u30B8\uFF08\u63A8\u5968\uFF09", value: "merge" },
2258
+ { name: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3067\u4E0A\u66F8\u304D", value: "overwrite" },
2259
+ { name: "\u65E2\u5B58\u30D5\u30A1\u30A4\u30EB\u512A\u5148", value: "skip" }
2260
+ ],
2261
+ default: "merge"
2262
+ }
2263
+ ]);
2264
+ conflictStrategy = strategyAnswers.conflictStrategy;
2265
+ return {
2266
+ categories: selectedCategories,
2267
+ appsDetail,
2268
+ packagesDetail,
2269
+ packageJsonSections,
2270
+ conflictStrategy
2271
+ };
2272
+ }
2273
+
2274
+ // src/utils/backup.ts
2275
+ import fsExtra2 from "fs-extra";
2276
+ import { join as join15, dirname as dirname5, relative as relative3 } from "path";
2277
+ var { copy, ensureDir: ensureDir2, readdir: readdir4, remove, pathExists } = fsExtra2;
2278
+ function getTimestamp() {
2279
+ const now = /* @__PURE__ */ new Date();
2280
+ const year = now.getFullYear();
2281
+ const month = String(now.getMonth() + 1).padStart(2, "0");
2282
+ const day = String(now.getDate()).padStart(2, "0");
2283
+ const hours = String(now.getHours()).padStart(2, "0");
2284
+ const minutes = String(now.getMinutes()).padStart(2, "0");
2285
+ const seconds = String(now.getSeconds()).padStart(2, "0");
2286
+ return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
2287
+ }
2288
+ function parseBackupTimestamp(dirName) {
2289
+ const match = dirName.match(/^\.einja-sync-backup-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})$/);
2290
+ if (!match || !match[1]) {
2291
+ return null;
2292
+ }
2293
+ const timestampStr = match[1];
2294
+ const parts = timestampStr.split("_");
2295
+ if (parts.length !== 2) {
2296
+ return null;
2297
+ }
2298
+ const [datePart, timePart] = parts;
2299
+ if (!datePart || !timePart) {
2300
+ return null;
2301
+ }
2302
+ const dateParts = datePart.split("-").map(Number);
2303
+ const timeParts = timePart.split("-").map(Number);
2304
+ if (dateParts.length !== 3 || timeParts.length !== 3) {
2305
+ return null;
2306
+ }
2307
+ const [year, month, day] = dateParts;
2308
+ const [hours, minutes, seconds] = timeParts;
2309
+ if (year === void 0 || month === void 0 || day === void 0 || hours === void 0 || minutes === void 0 || seconds === void 0) {
2310
+ return null;
2311
+ }
2312
+ return new Date(year, month - 1, day, hours, minutes, seconds);
2313
+ }
2314
+ async function createBackup(targetDir, filesToBackup) {
2315
+ const timestamp = getTimestamp();
2316
+ const backupDirName = `.einja-sync-backup-${timestamp}`;
2317
+ const backupDir = join15(targetDir, backupDirName);
2318
+ try {
2319
+ await ensureDir2(backupDir);
2320
+ for (const file of filesToBackup) {
2321
+ const sourcePath = join15(targetDir, file);
2322
+ const destPath = join15(backupDir, file);
2323
+ if (!await pathExists(sourcePath)) {
2324
+ continue;
2325
+ }
2326
+ await ensureDir2(dirname5(destPath));
2327
+ await copy(sourcePath, destPath);
2328
+ }
2329
+ return backupDir;
2330
+ } catch (error2) {
2331
+ error(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${error2 instanceof Error ? error2.message : String(error2)}`);
2332
+ throw error2;
2333
+ }
2334
+ }
2335
+ async function restoreFromBackup(backupDir, targetDir) {
2336
+ try {
2337
+ if (!await pathExists(backupDir)) {
2338
+ error(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${backupDir}`);
2339
+ return false;
2340
+ }
2341
+ const files = await getAllFiles(backupDir);
2342
+ for (const file of files) {
2343
+ const sourcePath = join15(backupDir, file);
2344
+ const destPath = join15(targetDir, file);
2345
+ await ensureDir2(dirname5(destPath));
2346
+ await copy(sourcePath, destPath, { overwrite: true });
2347
+ }
2348
+ return true;
2349
+ } catch (error2) {
2350
+ error(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u306E\u5FA9\u5143\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${error2 instanceof Error ? error2.message : String(error2)}`);
2351
+ return false;
2352
+ }
2353
+ }
2354
+ async function getAllFiles(dirPath, baseDir) {
2355
+ const base = baseDir ?? dirPath;
2356
+ const entries = await readdir4(dirPath, { withFileTypes: true });
2357
+ const files = [];
2358
+ for (const entry of entries) {
2359
+ const fullPath = join15(dirPath, entry.name);
2360
+ if (entry.isDirectory()) {
2361
+ const subFiles = await getAllFiles(fullPath, base);
2362
+ files.push(...subFiles);
2363
+ } else {
2364
+ files.push(relative3(base, fullPath));
2365
+ }
2366
+ }
2367
+ return files;
2368
+ }
2369
+ async function listBackups(targetDir) {
2370
+ try {
2371
+ if (!await pathExists(targetDir)) {
2372
+ return [];
2373
+ }
2374
+ const entries = await readdir4(targetDir, { withFileTypes: true });
2375
+ const backups = [];
2376
+ for (const entry of entries) {
2377
+ if (!entry.isDirectory()) {
2378
+ continue;
2379
+ }
2380
+ const timestamp = parseBackupTimestamp(entry.name);
2381
+ if (!timestamp) {
2382
+ continue;
2383
+ }
2384
+ backups.push({
2385
+ path: join15(targetDir, entry.name),
2386
+ name: entry.name,
2387
+ timestamp
2388
+ });
2389
+ }
2390
+ backups.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
2391
+ return backups;
2392
+ } catch (error2) {
2393
+ error(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${error2 instanceof Error ? error2.message : String(error2)}`);
2394
+ return [];
2395
+ }
2396
+ }
2397
+ async function getLatestBackup(targetDir) {
2398
+ const backups = await listBackups(targetDir);
2399
+ return backups.length > 0 ? backups[0] ?? null : null;
2400
+ }
2401
+
2402
+ // src/utils/git.ts
2403
+ import { execSync as execSync2 } from "child_process";
2404
+ function isGitRepository(targetDir) {
2405
+ try {
2406
+ const cwd = targetDir || process.cwd();
2407
+ execSync2("git rev-parse --is-inside-work-tree", {
2408
+ cwd,
2409
+ stdio: "ignore"
2410
+ });
2411
+ return true;
2412
+ } catch {
2413
+ return false;
2414
+ }
2415
+ }
2416
+ function hasUncommittedChanges(targetDir) {
2417
+ if (!isGitRepository(targetDir)) {
2418
+ warn("\u26A0\uFE0F \u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306FGit\u30EA\u30DD\u30B8\u30C8\u30EA\u3067\u306F\u3042\u308A\u307E\u305B\u3093");
2419
+ return false;
2420
+ }
2421
+ try {
2422
+ const cwd = targetDir || process.cwd();
2423
+ const output = execSync2("git status --porcelain", {
2424
+ cwd,
2425
+ encoding: "utf-8"
2426
+ });
2427
+ return output.trim().length > 0;
2428
+ } catch (error2) {
2429
+ warn(`\u26A0\uFE0F Git\u30B9\u30C6\u30FC\u30BF\u30B9\u78BA\u8A8D\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F: ${error2}`);
2430
+ return false;
2431
+ }
2432
+ }
2433
+ function checkGitStatusForSync(force, targetDir) {
2434
+ if (!isGitRepository(targetDir)) {
2435
+ warn("\u26A0\uFE0F \u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306FGit\u30EA\u30DD\u30B8\u30C8\u30EA\u3067\u306F\u3042\u308A\u307E\u305B\u3093");
2436
+ warn(
2437
+ " sync\u5B9F\u884C\u5F8C\u306E\u5DEE\u5206\u78BA\u8A8D\u306F `git diff` \u3067\u884C\u3046\u3053\u3068\u3092\u63A8\u5968\u3057\u307E\u3059"
2438
+ );
2439
+ return true;
2440
+ }
2441
+ if (hasUncommittedChanges(targetDir)) {
2442
+ if (!force) {
2443
+ error("\u274C \u672A\u30B3\u30DF\u30C3\u30C8\u306E\u5909\u66F4\u304C\u3042\u308A\u307E\u3059");
2444
+ error(
2445
+ " \u5909\u66F4\u3092\u30B3\u30DF\u30C3\u30C8\u3057\u3066\u304B\u3089\u5B9F\u884C\u3059\u308B\u304B\u3001--force \u30D5\u30E9\u30B0\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044"
2446
+ );
2447
+ process.exit(1);
2448
+ }
2449
+ warn("\u26A0\uFE0F \u672A\u30B3\u30DF\u30C3\u30C8\u306E\u5909\u66F4\u304C\u3042\u308A\u307E\u3059\u304C\u3001--force \u306B\u3088\u308A\u7D9A\u884C\u3057\u307E\u3059");
2450
+ warn(
2451
+ " \u554F\u984C\u304C\u767A\u751F\u3057\u305F\u5834\u5408\u306F `git checkout .` \u3067\u5FA9\u5143\u3067\u304D\u307E\u3059"
2452
+ );
2453
+ }
2454
+ return true;
2455
+ }
2456
+
2457
+ // src/commands/sync.ts
2458
+ var currentBackupDir;
2459
+ var isSyncing = false;
2460
+ async function handleInterrupt() {
2461
+ if (!isSyncing) {
2462
+ info("\n\n\u51E6\u7406\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F");
2463
+ process.exit(0);
2464
+ }
2465
+ info("\n\n\u{1F6D1} \u540C\u671F\u51E6\u7406\u3092\u4E2D\u65AD\u3057\u3066\u3044\u307E\u3059...");
2466
+ if (!currentBackupDir) {
2467
+ info("\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304C\u4F5C\u6210\u3055\u308C\u3066\u3044\u306A\u3044\u305F\u3081\u3001\u30AF\u30EA\u30FC\u30F3\u30A2\u30C3\u30D7\u306F\u4E0D\u8981\u3067\u3059");
2468
+ process.exit(0);
2469
+ }
2470
+ const answer = await inquirer8.prompt([
2471
+ {
2472
+ type: "confirm",
2473
+ name: "rollback",
2474
+ message: "\u5909\u66F4\u3092\u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u3057\u307E\u3059\u304B\uFF1F",
2475
+ default: true
2476
+ }
2477
+ ]);
2478
+ if (answer.rollback) {
2479
+ info("\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u5FA9\u5143\u4E2D...");
2480
+ const targetDir = process.cwd();
2481
+ const success2 = await restoreFromBackup(currentBackupDir, targetDir);
2482
+ if (success2) {
2483
+ success("\u2713 \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5B8C\u4E86");
2484
+ } else {
2485
+ error("\u274C \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5931\u6557");
2486
+ info(`\u624B\u52D5\u3067\u5FA9\u5143: cp -r ${currentBackupDir}/* .`);
2487
+ }
2488
+ }
2489
+ process.exit(0);
2490
+ }
2491
+ function getTemplatePath3() {
2492
+ const __filename3 = fileURLToPath3(import.meta.url);
2493
+ const __dirname3 = dirname6(__filename3);
2494
+ const { existsSync: existsSync8 } = fsExtra3;
2495
+ const distPath = join16(__dirname3, "../templates/default");
2496
+ const srcPath = join16(__dirname3, "../../templates/default");
2497
+ if (existsSync8(distPath)) {
2498
+ return distPath;
2499
+ }
2500
+ if (existsSync8(srcPath)) {
2501
+ return srcPath;
2502
+ }
2503
+ throw new Error("\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
2504
+ }
2505
+ async function syncCommand(options) {
2506
+ const { existsSync: existsSync8 } = fsExtra3;
2507
+ const sigintHandler = () => {
2508
+ handleInterrupt().catch((error2) => {
2509
+ error(`\u30AF\u30EA\u30FC\u30F3\u30A2\u30C3\u30D7\u4E2D\u306B\u30A8\u30E9\u30FC: ${error2}`);
2510
+ process.exit(1);
2511
+ });
2512
+ };
2513
+ process.on("SIGINT", sigintHandler);
2514
+ const cleanup = () => {
2515
+ process.off("SIGINT", sigintHandler);
2516
+ };
2517
+ try {
2518
+ if (options.rollback) {
2519
+ info("\u{1F504} \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u4E2D...");
2520
+ const targetDir2 = process.cwd();
2521
+ const latestBackup = await getLatestBackup(targetDir2);
2522
+ if (!latestBackup) {
2523
+ error("\u274C \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
2524
+ process.exit(1);
2525
+ }
2526
+ info(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7: ${latestBackup.name}`);
2527
+ const success2 = await restoreFromBackup(latestBackup.path, targetDir2);
2528
+ if (success2) {
2529
+ success("\u2713 \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5B8C\u4E86");
2530
+ } else {
2531
+ error("\u274C \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5931\u6557");
2532
+ process.exit(1);
2533
+ }
2534
+ return;
2535
+ }
2536
+ const targetDir = process.cwd();
2537
+ checkGitStatusForSync(options.force || false, targetDir);
2538
+ const templatePath = getTemplatePath3();
2539
+ let categories;
2540
+ let appsDetail;
2541
+ let packagesDetail;
2542
+ let conflictStrategy;
2543
+ let packageJsonSections;
2544
+ if (options.all) {
2545
+ categories = [
2546
+ "env",
2547
+ "tools",
2548
+ "git",
2549
+ "git-hooks",
2550
+ "github",
2551
+ "docker",
2552
+ "monorepo",
2553
+ "root-config",
2554
+ "apps",
2555
+ "packages",
2556
+ "docs"
2557
+ ];
2558
+ appsDetail = void 0;
2559
+ packagesDetail = void 0;
2560
+ conflictStrategy = "merge";
2561
+ info("\u5168\u30AB\u30C6\u30B4\u30EA\u3092\u540C\u671F\u5BFE\u8C61\u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F");
2562
+ } else if (options.categories) {
2563
+ categories = options.categories;
2564
+ appsDetail = void 0;
2565
+ packagesDetail = void 0;
2566
+ conflictStrategy = "merge";
2567
+ info(`\u6307\u5B9A\u3055\u308C\u305F\u30AB\u30C6\u30B4\u30EA: ${categories.join(", ")}`);
2568
+ } else {
2569
+ const promptResult = await promptSyncCategories(templatePath);
2570
+ categories = promptResult.categories;
2571
+ appsDetail = promptResult.appsDetail;
2572
+ packagesDetail = promptResult.packagesDetail;
2573
+ conflictStrategy = promptResult.conflictStrategy;
2574
+ packageJsonSections = promptResult.packageJsonSections;
2575
+ }
2576
+ info("\u{1F4C1} \u540C\u671F\u5BFE\u8C61\u30D5\u30A1\u30A4\u30EB\u3092\u53CE\u96C6\u4E2D...");
2577
+ const filesToSync = await collectSyncFiles(templatePath, categories, appsDetail, packagesDetail);
2578
+ if (filesToSync.length === 0) {
2579
+ warn("\u26A0\uFE0F \u540C\u671F\u5BFE\u8C61\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
2580
+ return;
2581
+ }
2582
+ info(`\u540C\u671F\u5BFE\u8C61: ${filesToSync.length}\u500B\u306E\u30D5\u30A1\u30A4\u30EB`);
2583
+ if (options.dryRun) {
2584
+ info("\n\u{1F4CB} \u540C\u671F\u30D7\u30EC\u30D3\u30E5\u30FC (--dry-run)\n");
2585
+ for (const file of filesToSync) {
2586
+ info(` \u2713 ${file}`);
2587
+ }
2588
+ info(`
2589
+ \u5408\u8A08: ${filesToSync.length}\u30D5\u30A1\u30A4\u30EB`);
2590
+ info("--dry-run \u30E2\u30FC\u30C9\u306E\u305F\u3081\u3001\u5B9F\u969B\u306E\u30D5\u30A1\u30A4\u30EB\u5909\u66F4\u306F\u884C\u308F\u308C\u307E\u305B\u3093");
2591
+ return;
2592
+ }
2593
+ let backupDir;
2594
+ if (options.backup !== false) {
2595
+ info("\u{1F4BE} \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u4F5C\u6210\u4E2D...");
2596
+ const existingFiles = filesToSync.filter((file) => existsSync8(join16(targetDir, file)));
2597
+ if (existingFiles.length > 0) {
2598
+ backupDir = await createBackup(targetDir, existingFiles);
2599
+ currentBackupDir = backupDir;
2600
+ } else {
2601
+ info("\u65E2\u5B58\u30D5\u30A1\u30A4\u30EB\u304C\u306A\u3044\u305F\u3081\u3001\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3059");
2602
+ }
2603
+ }
2604
+ info("\u{1F504} \u30D5\u30A1\u30A4\u30EB\u540C\u671F\u4E2D...");
2605
+ isSyncing = true;
2606
+ const syncMetadata = {
2607
+ version: "1.0.0",
2608
+ lastSync: (/* @__PURE__ */ new Date()).toISOString(),
2609
+ templateVersion: "0.2.9",
2610
+ files: {},
2611
+ jsonPaths: {
2612
+ managed: {},
2613
+ seed: {}
2614
+ }
2615
+ };
2616
+ const result = {
2617
+ success: 0,
2618
+ skipped: 0,
2619
+ errors: 0,
2620
+ conflicts: 0,
2621
+ files: []
2622
+ };
2623
+ for (const file of filesToSync) {
2624
+ try {
2625
+ const sourcePath = join16(templatePath, file);
2626
+ const targetPath = join16(targetDir, file);
2627
+ if (!existsSync8(sourcePath)) {
2628
+ warn(`\u30B9\u30AD\u30C3\u30D7: ${file} (\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u305B\u3093)`);
2629
+ result.skipped++;
2630
+ result.files.push({
2631
+ path: file,
2632
+ action: "skipped",
2633
+ reason: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u305B\u3093"
2634
+ });
2635
+ continue;
2636
+ }
2637
+ const mergeResult = await mergeAndWriteFile(
2638
+ sourcePath,
2639
+ targetPath,
2640
+ syncMetadata,
2641
+ packageJsonSections
2642
+ );
2643
+ const mappedAction = mergeResult.action === "created" || mergeResult.action === "overwritten" ? "copied" : mergeResult.action;
2644
+ result.success++;
2645
+ result.files.push({
2646
+ path: file,
2647
+ action: mappedAction
2648
+ });
2649
+ info(` \u2713 ${file}`);
2650
+ } catch (error2) {
2651
+ result.errors++;
2652
+ result.files.push({
2653
+ path: file,
2654
+ action: "error",
2655
+ reason: error2 instanceof Error ? error2.message : "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC"
2656
+ });
2657
+ error(` \u2717 ${file}: ${error2}`);
2658
+ }
2659
+ }
2660
+ info("\n\u{1F4CA} \u540C\u671F\u7D50\u679C:");
2661
+ info(` \u6210\u529F: ${result.success}\u30D5\u30A1\u30A4\u30EB`);
2662
+ if (result.skipped > 0) {
2663
+ info(` \u30B9\u30AD\u30C3\u30D7: ${result.skipped}\u30D5\u30A1\u30A4\u30EB`);
2664
+ }
2665
+ if (result.errors > 0) {
2666
+ error(` \u30A8\u30E9\u30FC: ${result.errors}\u30D5\u30A1\u30A4\u30EB`);
2667
+ }
2668
+ if (result.errors > 0) {
2669
+ isSyncing = false;
2670
+ error("\n\u274C \u540C\u671F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F");
2671
+ if (backupDir) {
2672
+ info("\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u5FA9\u5143: npx create-einja-app sync --rollback");
2673
+ }
2674
+ process.exit(1);
2675
+ }
2676
+ success("\n\u2713 \u540C\u671F\u5B8C\u4E86");
2677
+ isSyncing = false;
2678
+ currentBackupDir = void 0;
2679
+ if (backupDir) {
2680
+ info(`
2681
+ \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7: ${backupDir}`);
2682
+ info("\u5FA9\u5143\u65B9\u6CD5: npx create-einja-app sync --rollback");
2683
+ }
2684
+ } finally {
2685
+ cleanup();
2686
+ }
2687
+ }
2688
+
1834
2689
  // src/cli.ts
1835
- var __filename2 = fileURLToPath3(import.meta.url);
1836
- var __dirname2 = dirname5(__filename2);
1837
- var packageJsonPath = join14(__dirname2, "../package.json");
2690
+ var __filename2 = fileURLToPath4(import.meta.url);
2691
+ var __dirname2 = dirname7(__filename2);
2692
+ var packageJsonPath = join17(__dirname2, "../package.json");
1838
2693
  var packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
1839
2694
  var program = new Command();
1840
2695
  program.name("create-einja-app").description("CLI tool to create new projects with Einja Management Template").version(packageJson.version);
1841
- program.argument("[project-name]", "Project name").option("--skip-git", "Skip git initialization").option("--skip-install", "Skip package installation").option("-y, --yes", "Skip interactive prompts").action(
2696
+ program.argument("[project-name]", "Project name").option("--skip-git", "Skip git initialization").option("--skip-install", "Skip package installation").action(
1842
2697
  async (projectName, options) => {
1843
2698
  await createCommand(projectName, options);
1844
2699
  }
@@ -1846,13 +2701,26 @@ program.argument("[project-name]", "Project name").option("--skip-git", "Skip gi
1846
2701
  program.command("setup").description("Setup tools for existing project").action(async () => {
1847
2702
  await setupCommand();
1848
2703
  });
1849
- program.command("add").description("Add einja components to existing monorepo").option("-y, --yes", "Skip prompts and use defaults (select all)").option("--all", "Select all components (same as -y)").option("--dry-run", "Preview changes without making them").action(
2704
+ program.command("add").description("Add einja components to existing monorepo").option("--all", "Select all components").option("--dry-run", "Preview changes without making them").action(
1850
2705
  async (options) => {
1851
2706
  await addCommand({
1852
- skipPrompts: options.yes || options.all || false,
2707
+ skipPrompts: options.all || false,
1853
2708
  dryRun: options.dryRun || false
1854
2709
  });
1855
2710
  }
1856
2711
  );
2712
+ program.command("sync").description("Sync template files to existing project").option("--categories <categories>", "Comma-separated list of categories to sync").option("--all", "Sync all categories").option("--dry-run", "Preview changes without making them").option("--backup", "Create backup before syncing (default: true)", true).option("--rollback", "Rollback to previous backup").option("--force", "Force sync even with uncommitted changes").action(
2713
+ async (options) => {
2714
+ await syncCommand({
2715
+ categories: options.categories?.split(","),
2716
+ all: options.all || false,
2717
+ dryRun: options.dryRun || false,
2718
+ backup: options.backup !== false,
2719
+ // デフォルトtrue
2720
+ rollback: options.rollback || false,
2721
+ force: options.force || false
2722
+ });
2723
+ }
2724
+ );
1857
2725
  program.parse();
1858
2726
  //# sourceMappingURL=cli.js.map