create-einja-app 0.2.8 → 0.2.10
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 +12 -7
- package/dist/cli.js +879 -14
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/.envrc +29 -3
- package/templates/default/AGENTS.md +52 -0
- package/templates/default/CLAUDE.md +2 -2
- package/templates/default/scripts/template-update.ts +3 -3
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
|
|
7
|
-
import { dirname as
|
|
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
|
|
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(
|
|
1785
|
+
function matchPattern(path2, pattern) {
|
|
1650
1786
|
if (pattern.endsWith("/")) {
|
|
1651
1787
|
const dirPattern = pattern.slice(0, -1);
|
|
1652
|
-
return
|
|
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(
|
|
1792
|
+
return new RegExp(`^${regexPattern}$`).test(path2);
|
|
1657
1793
|
}
|
|
1658
|
-
return
|
|
1794
|
+
return path2 === pattern || path2.startsWith(`${pattern}/`);
|
|
1659
1795
|
}
|
|
1660
1796
|
|
|
1661
1797
|
// src/commands/add.ts
|
|
@@ -1831,14 +1967,730 @@ 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 { existsSync as existsSync8 } 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 { copy, ensureDir as ensureDir2, readdir as readdir4, remove, pathExists } from "fs-extra";
|
|
2276
|
+
import { join as join15, dirname as dirname5, relative as relative3 } from "path";
|
|
2277
|
+
function getTimestamp() {
|
|
2278
|
+
const now = /* @__PURE__ */ new Date();
|
|
2279
|
+
const year = now.getFullYear();
|
|
2280
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
2281
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
2282
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
2283
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
2284
|
+
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
2285
|
+
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
|
|
2286
|
+
}
|
|
2287
|
+
function parseBackupTimestamp(dirName) {
|
|
2288
|
+
const match = dirName.match(/^\.einja-sync-backup-(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})$/);
|
|
2289
|
+
if (!match || !match[1]) {
|
|
2290
|
+
return null;
|
|
2291
|
+
}
|
|
2292
|
+
const timestampStr = match[1];
|
|
2293
|
+
const parts = timestampStr.split("_");
|
|
2294
|
+
if (parts.length !== 2) {
|
|
2295
|
+
return null;
|
|
2296
|
+
}
|
|
2297
|
+
const [datePart, timePart] = parts;
|
|
2298
|
+
if (!datePart || !timePart) {
|
|
2299
|
+
return null;
|
|
2300
|
+
}
|
|
2301
|
+
const dateParts = datePart.split("-").map(Number);
|
|
2302
|
+
const timeParts = timePart.split("-").map(Number);
|
|
2303
|
+
if (dateParts.length !== 3 || timeParts.length !== 3) {
|
|
2304
|
+
return null;
|
|
2305
|
+
}
|
|
2306
|
+
const [year, month, day] = dateParts;
|
|
2307
|
+
const [hours, minutes, seconds] = timeParts;
|
|
2308
|
+
if (year === void 0 || month === void 0 || day === void 0 || hours === void 0 || minutes === void 0 || seconds === void 0) {
|
|
2309
|
+
return null;
|
|
2310
|
+
}
|
|
2311
|
+
return new Date(year, month - 1, day, hours, minutes, seconds);
|
|
2312
|
+
}
|
|
2313
|
+
async function createBackup(targetDir, filesToBackup) {
|
|
2314
|
+
const timestamp = getTimestamp();
|
|
2315
|
+
const backupDirName = `.einja-sync-backup-${timestamp}`;
|
|
2316
|
+
const backupDir = join15(targetDir, backupDirName);
|
|
2317
|
+
try {
|
|
2318
|
+
await ensureDir2(backupDir);
|
|
2319
|
+
for (const file of filesToBackup) {
|
|
2320
|
+
const sourcePath = join15(targetDir, file);
|
|
2321
|
+
const destPath = join15(backupDir, file);
|
|
2322
|
+
if (!await pathExists(sourcePath)) {
|
|
2323
|
+
continue;
|
|
2324
|
+
}
|
|
2325
|
+
await ensureDir2(dirname5(destPath));
|
|
2326
|
+
await copy(sourcePath, destPath);
|
|
2327
|
+
}
|
|
2328
|
+
return backupDir;
|
|
2329
|
+
} catch (error2) {
|
|
2330
|
+
error(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
2331
|
+
throw error2;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
async function restoreFromBackup(backupDir, targetDir) {
|
|
2335
|
+
try {
|
|
2336
|
+
if (!await pathExists(backupDir)) {
|
|
2337
|
+
error(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${backupDir}`);
|
|
2338
|
+
return false;
|
|
2339
|
+
}
|
|
2340
|
+
const files = await getAllFiles(backupDir);
|
|
2341
|
+
for (const file of files) {
|
|
2342
|
+
const sourcePath = join15(backupDir, file);
|
|
2343
|
+
const destPath = join15(targetDir, file);
|
|
2344
|
+
await ensureDir2(dirname5(destPath));
|
|
2345
|
+
await copy(sourcePath, destPath, { overwrite: true });
|
|
2346
|
+
}
|
|
2347
|
+
return true;
|
|
2348
|
+
} catch (error2) {
|
|
2349
|
+
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)}`);
|
|
2350
|
+
return false;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
async function getAllFiles(dirPath, baseDir) {
|
|
2354
|
+
const base = baseDir ?? dirPath;
|
|
2355
|
+
const entries = await readdir4(dirPath, { withFileTypes: true });
|
|
2356
|
+
const files = [];
|
|
2357
|
+
for (const entry of entries) {
|
|
2358
|
+
const fullPath = join15(dirPath, entry.name);
|
|
2359
|
+
if (entry.isDirectory()) {
|
|
2360
|
+
const subFiles = await getAllFiles(fullPath, base);
|
|
2361
|
+
files.push(...subFiles);
|
|
2362
|
+
} else {
|
|
2363
|
+
files.push(relative3(base, fullPath));
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
return files;
|
|
2367
|
+
}
|
|
2368
|
+
async function listBackups(targetDir) {
|
|
2369
|
+
try {
|
|
2370
|
+
if (!await pathExists(targetDir)) {
|
|
2371
|
+
return [];
|
|
2372
|
+
}
|
|
2373
|
+
const entries = await readdir4(targetDir, { withFileTypes: true });
|
|
2374
|
+
const backups = [];
|
|
2375
|
+
for (const entry of entries) {
|
|
2376
|
+
if (!entry.isDirectory()) {
|
|
2377
|
+
continue;
|
|
2378
|
+
}
|
|
2379
|
+
const timestamp = parseBackupTimestamp(entry.name);
|
|
2380
|
+
if (!timestamp) {
|
|
2381
|
+
continue;
|
|
2382
|
+
}
|
|
2383
|
+
backups.push({
|
|
2384
|
+
path: join15(targetDir, entry.name),
|
|
2385
|
+
name: entry.name,
|
|
2386
|
+
timestamp
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
backups.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
2390
|
+
return backups;
|
|
2391
|
+
} catch (error2) {
|
|
2392
|
+
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)}`);
|
|
2393
|
+
return [];
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
async function getLatestBackup(targetDir) {
|
|
2397
|
+
const backups = await listBackups(targetDir);
|
|
2398
|
+
return backups.length > 0 ? backups[0] ?? null : null;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
// src/utils/git.ts
|
|
2402
|
+
import { execSync as execSync2 } from "child_process";
|
|
2403
|
+
function isGitRepository(targetDir) {
|
|
2404
|
+
try {
|
|
2405
|
+
const cwd = targetDir || process.cwd();
|
|
2406
|
+
execSync2("git rev-parse --is-inside-work-tree", {
|
|
2407
|
+
cwd,
|
|
2408
|
+
stdio: "ignore"
|
|
2409
|
+
});
|
|
2410
|
+
return true;
|
|
2411
|
+
} catch {
|
|
2412
|
+
return false;
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
function hasUncommittedChanges(targetDir) {
|
|
2416
|
+
if (!isGitRepository(targetDir)) {
|
|
2417
|
+
warn("\u26A0\uFE0F \u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306FGit\u30EA\u30DD\u30B8\u30C8\u30EA\u3067\u306F\u3042\u308A\u307E\u305B\u3093");
|
|
2418
|
+
return false;
|
|
2419
|
+
}
|
|
2420
|
+
try {
|
|
2421
|
+
const cwd = targetDir || process.cwd();
|
|
2422
|
+
const output = execSync2("git status --porcelain", {
|
|
2423
|
+
cwd,
|
|
2424
|
+
encoding: "utf-8"
|
|
2425
|
+
});
|
|
2426
|
+
return output.trim().length > 0;
|
|
2427
|
+
} catch (error2) {
|
|
2428
|
+
warn(`\u26A0\uFE0F Git\u30B9\u30C6\u30FC\u30BF\u30B9\u78BA\u8A8D\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F: ${error2}`);
|
|
2429
|
+
return false;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
function checkGitStatusForSync(force, targetDir) {
|
|
2433
|
+
if (!isGitRepository(targetDir)) {
|
|
2434
|
+
warn("\u26A0\uFE0F \u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306FGit\u30EA\u30DD\u30B8\u30C8\u30EA\u3067\u306F\u3042\u308A\u307E\u305B\u3093");
|
|
2435
|
+
warn(
|
|
2436
|
+
" sync\u5B9F\u884C\u5F8C\u306E\u5DEE\u5206\u78BA\u8A8D\u306F `git diff` \u3067\u884C\u3046\u3053\u3068\u3092\u63A8\u5968\u3057\u307E\u3059"
|
|
2437
|
+
);
|
|
2438
|
+
return true;
|
|
2439
|
+
}
|
|
2440
|
+
if (hasUncommittedChanges(targetDir)) {
|
|
2441
|
+
if (!force) {
|
|
2442
|
+
error("\u274C \u672A\u30B3\u30DF\u30C3\u30C8\u306E\u5909\u66F4\u304C\u3042\u308A\u307E\u3059");
|
|
2443
|
+
error(
|
|
2444
|
+
" \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"
|
|
2445
|
+
);
|
|
2446
|
+
process.exit(1);
|
|
2447
|
+
}
|
|
2448
|
+
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");
|
|
2449
|
+
warn(
|
|
2450
|
+
" \u554F\u984C\u304C\u767A\u751F\u3057\u305F\u5834\u5408\u306F `git checkout .` \u3067\u5FA9\u5143\u3067\u304D\u307E\u3059"
|
|
2451
|
+
);
|
|
2452
|
+
}
|
|
2453
|
+
return true;
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
// src/commands/sync.ts
|
|
2457
|
+
var currentBackupDir;
|
|
2458
|
+
var isSyncing = false;
|
|
2459
|
+
async function handleInterrupt() {
|
|
2460
|
+
if (!isSyncing) {
|
|
2461
|
+
info("\n\n\u51E6\u7406\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F");
|
|
2462
|
+
process.exit(0);
|
|
2463
|
+
}
|
|
2464
|
+
info("\n\n\u{1F6D1} \u540C\u671F\u51E6\u7406\u3092\u4E2D\u65AD\u3057\u3066\u3044\u307E\u3059...");
|
|
2465
|
+
if (!currentBackupDir) {
|
|
2466
|
+
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");
|
|
2467
|
+
process.exit(0);
|
|
2468
|
+
}
|
|
2469
|
+
const answer = await inquirer8.prompt([
|
|
2470
|
+
{
|
|
2471
|
+
type: "confirm",
|
|
2472
|
+
name: "rollback",
|
|
2473
|
+
message: "\u5909\u66F4\u3092\u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u3057\u307E\u3059\u304B\uFF1F",
|
|
2474
|
+
default: true
|
|
2475
|
+
}
|
|
2476
|
+
]);
|
|
2477
|
+
if (answer.rollback) {
|
|
2478
|
+
info("\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u5FA9\u5143\u4E2D...");
|
|
2479
|
+
const targetDir = process.cwd();
|
|
2480
|
+
const success2 = await restoreFromBackup(currentBackupDir, targetDir);
|
|
2481
|
+
if (success2) {
|
|
2482
|
+
success("\u2713 \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5B8C\u4E86");
|
|
2483
|
+
} else {
|
|
2484
|
+
error("\u274C \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5931\u6557");
|
|
2485
|
+
info(`\u624B\u52D5\u3067\u5FA9\u5143: cp -r ${currentBackupDir}/* .`);
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
process.exit(0);
|
|
2489
|
+
}
|
|
2490
|
+
function getTemplatePath3() {
|
|
2491
|
+
const __filename3 = fileURLToPath3(import.meta.url);
|
|
2492
|
+
const __dirname3 = dirname6(__filename3);
|
|
2493
|
+
const distPath = join16(__dirname3, "../templates/default");
|
|
2494
|
+
const srcPath = join16(__dirname3, "../../templates/default");
|
|
2495
|
+
if (existsSync8(distPath)) {
|
|
2496
|
+
return distPath;
|
|
2497
|
+
}
|
|
2498
|
+
if (existsSync8(srcPath)) {
|
|
2499
|
+
return srcPath;
|
|
2500
|
+
}
|
|
2501
|
+
throw new Error("\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
|
|
2502
|
+
}
|
|
2503
|
+
async function syncCommand(options) {
|
|
2504
|
+
const sigintHandler = () => {
|
|
2505
|
+
handleInterrupt().catch((error2) => {
|
|
2506
|
+
error(`\u30AF\u30EA\u30FC\u30F3\u30A2\u30C3\u30D7\u4E2D\u306B\u30A8\u30E9\u30FC: ${error2}`);
|
|
2507
|
+
process.exit(1);
|
|
2508
|
+
});
|
|
2509
|
+
};
|
|
2510
|
+
process.on("SIGINT", sigintHandler);
|
|
2511
|
+
const cleanup = () => {
|
|
2512
|
+
process.off("SIGINT", sigintHandler);
|
|
2513
|
+
};
|
|
2514
|
+
try {
|
|
2515
|
+
if (options.rollback) {
|
|
2516
|
+
info("\u{1F504} \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u4E2D...");
|
|
2517
|
+
const targetDir2 = process.cwd();
|
|
2518
|
+
const latestBackup = await getLatestBackup(targetDir2);
|
|
2519
|
+
if (!latestBackup) {
|
|
2520
|
+
error("\u274C \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
|
|
2521
|
+
process.exit(1);
|
|
2522
|
+
}
|
|
2523
|
+
info(`\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7: ${latestBackup.name}`);
|
|
2524
|
+
const success2 = await restoreFromBackup(latestBackup.path, targetDir2);
|
|
2525
|
+
if (success2) {
|
|
2526
|
+
success("\u2713 \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5B8C\u4E86");
|
|
2527
|
+
} else {
|
|
2528
|
+
error("\u274C \u30ED\u30FC\u30EB\u30D0\u30C3\u30AF\u5931\u6557");
|
|
2529
|
+
process.exit(1);
|
|
2530
|
+
}
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2533
|
+
const targetDir = process.cwd();
|
|
2534
|
+
checkGitStatusForSync(options.force || false, targetDir);
|
|
2535
|
+
const templatePath = getTemplatePath3();
|
|
2536
|
+
let categories;
|
|
2537
|
+
let appsDetail;
|
|
2538
|
+
let packagesDetail;
|
|
2539
|
+
let conflictStrategy;
|
|
2540
|
+
let packageJsonSections;
|
|
2541
|
+
if (options.all) {
|
|
2542
|
+
categories = [
|
|
2543
|
+
"env",
|
|
2544
|
+
"tools",
|
|
2545
|
+
"git",
|
|
2546
|
+
"git-hooks",
|
|
2547
|
+
"github",
|
|
2548
|
+
"docker",
|
|
2549
|
+
"monorepo",
|
|
2550
|
+
"root-config",
|
|
2551
|
+
"apps",
|
|
2552
|
+
"packages",
|
|
2553
|
+
"docs"
|
|
2554
|
+
];
|
|
2555
|
+
appsDetail = void 0;
|
|
2556
|
+
packagesDetail = void 0;
|
|
2557
|
+
conflictStrategy = "merge";
|
|
2558
|
+
info("\u5168\u30AB\u30C6\u30B4\u30EA\u3092\u540C\u671F\u5BFE\u8C61\u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F");
|
|
2559
|
+
} else if (options.categories) {
|
|
2560
|
+
categories = options.categories;
|
|
2561
|
+
appsDetail = void 0;
|
|
2562
|
+
packagesDetail = void 0;
|
|
2563
|
+
conflictStrategy = "merge";
|
|
2564
|
+
info(`\u6307\u5B9A\u3055\u308C\u305F\u30AB\u30C6\u30B4\u30EA: ${categories.join(", ")}`);
|
|
2565
|
+
} else {
|
|
2566
|
+
const promptResult = await promptSyncCategories(templatePath);
|
|
2567
|
+
categories = promptResult.categories;
|
|
2568
|
+
appsDetail = promptResult.appsDetail;
|
|
2569
|
+
packagesDetail = promptResult.packagesDetail;
|
|
2570
|
+
conflictStrategy = promptResult.conflictStrategy;
|
|
2571
|
+
packageJsonSections = promptResult.packageJsonSections;
|
|
2572
|
+
}
|
|
2573
|
+
info("\u{1F4C1} \u540C\u671F\u5BFE\u8C61\u30D5\u30A1\u30A4\u30EB\u3092\u53CE\u96C6\u4E2D...");
|
|
2574
|
+
const filesToSync = await collectSyncFiles(templatePath, categories, appsDetail, packagesDetail);
|
|
2575
|
+
if (filesToSync.length === 0) {
|
|
2576
|
+
warn("\u26A0\uFE0F \u540C\u671F\u5BFE\u8C61\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
|
|
2577
|
+
return;
|
|
2578
|
+
}
|
|
2579
|
+
info(`\u540C\u671F\u5BFE\u8C61: ${filesToSync.length}\u500B\u306E\u30D5\u30A1\u30A4\u30EB`);
|
|
2580
|
+
if (options.dryRun) {
|
|
2581
|
+
info("\n\u{1F4CB} \u540C\u671F\u30D7\u30EC\u30D3\u30E5\u30FC (--dry-run)\n");
|
|
2582
|
+
for (const file of filesToSync) {
|
|
2583
|
+
info(` \u2713 ${file}`);
|
|
2584
|
+
}
|
|
2585
|
+
info(`
|
|
2586
|
+
\u5408\u8A08: ${filesToSync.length}\u30D5\u30A1\u30A4\u30EB`);
|
|
2587
|
+
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");
|
|
2588
|
+
return;
|
|
2589
|
+
}
|
|
2590
|
+
let backupDir;
|
|
2591
|
+
if (options.backup !== false) {
|
|
2592
|
+
info("\u{1F4BE} \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u4F5C\u6210\u4E2D...");
|
|
2593
|
+
const existingFiles = filesToSync.filter((file) => existsSync8(join16(targetDir, file)));
|
|
2594
|
+
if (existingFiles.length > 0) {
|
|
2595
|
+
backupDir = await createBackup(targetDir, existingFiles);
|
|
2596
|
+
currentBackupDir = backupDir;
|
|
2597
|
+
} else {
|
|
2598
|
+
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");
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
info("\u{1F504} \u30D5\u30A1\u30A4\u30EB\u540C\u671F\u4E2D...");
|
|
2602
|
+
isSyncing = true;
|
|
2603
|
+
const syncMetadata = {
|
|
2604
|
+
version: "1.0.0",
|
|
2605
|
+
lastSync: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2606
|
+
templateVersion: "0.2.9",
|
|
2607
|
+
files: {},
|
|
2608
|
+
jsonPaths: {
|
|
2609
|
+
managed: {},
|
|
2610
|
+
seed: {}
|
|
2611
|
+
}
|
|
2612
|
+
};
|
|
2613
|
+
const result = {
|
|
2614
|
+
success: 0,
|
|
2615
|
+
skipped: 0,
|
|
2616
|
+
errors: 0,
|
|
2617
|
+
conflicts: 0,
|
|
2618
|
+
files: []
|
|
2619
|
+
};
|
|
2620
|
+
for (const file of filesToSync) {
|
|
2621
|
+
try {
|
|
2622
|
+
const sourcePath = join16(templatePath, file);
|
|
2623
|
+
const targetPath = join16(targetDir, file);
|
|
2624
|
+
if (!existsSync8(sourcePath)) {
|
|
2625
|
+
warn(`\u30B9\u30AD\u30C3\u30D7: ${file} (\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u305B\u3093)`);
|
|
2626
|
+
result.skipped++;
|
|
2627
|
+
result.files.push({
|
|
2628
|
+
path: file,
|
|
2629
|
+
action: "skipped",
|
|
2630
|
+
reason: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u305B\u3093"
|
|
2631
|
+
});
|
|
2632
|
+
continue;
|
|
2633
|
+
}
|
|
2634
|
+
const mergeResult = await mergeAndWriteFile(
|
|
2635
|
+
sourcePath,
|
|
2636
|
+
targetPath,
|
|
2637
|
+
syncMetadata,
|
|
2638
|
+
packageJsonSections
|
|
2639
|
+
);
|
|
2640
|
+
const mappedAction = mergeResult.action === "created" || mergeResult.action === "overwritten" ? "copied" : mergeResult.action;
|
|
2641
|
+
result.success++;
|
|
2642
|
+
result.files.push({
|
|
2643
|
+
path: file,
|
|
2644
|
+
action: mappedAction
|
|
2645
|
+
});
|
|
2646
|
+
info(` \u2713 ${file}`);
|
|
2647
|
+
} catch (error2) {
|
|
2648
|
+
result.errors++;
|
|
2649
|
+
result.files.push({
|
|
2650
|
+
path: file,
|
|
2651
|
+
action: "error",
|
|
2652
|
+
reason: error2 instanceof Error ? error2.message : "\u4E0D\u660E\u306A\u30A8\u30E9\u30FC"
|
|
2653
|
+
});
|
|
2654
|
+
error(` \u2717 ${file}: ${error2}`);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
info("\n\u{1F4CA} \u540C\u671F\u7D50\u679C:");
|
|
2658
|
+
info(` \u6210\u529F: ${result.success}\u30D5\u30A1\u30A4\u30EB`);
|
|
2659
|
+
if (result.skipped > 0) {
|
|
2660
|
+
info(` \u30B9\u30AD\u30C3\u30D7: ${result.skipped}\u30D5\u30A1\u30A4\u30EB`);
|
|
2661
|
+
}
|
|
2662
|
+
if (result.errors > 0) {
|
|
2663
|
+
error(` \u30A8\u30E9\u30FC: ${result.errors}\u30D5\u30A1\u30A4\u30EB`);
|
|
2664
|
+
}
|
|
2665
|
+
if (result.errors > 0) {
|
|
2666
|
+
isSyncing = false;
|
|
2667
|
+
error("\n\u274C \u540C\u671F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F");
|
|
2668
|
+
if (backupDir) {
|
|
2669
|
+
info("\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u5FA9\u5143: npx create-einja-app sync --rollback");
|
|
2670
|
+
}
|
|
2671
|
+
process.exit(1);
|
|
2672
|
+
}
|
|
2673
|
+
success("\n\u2713 \u540C\u671F\u5B8C\u4E86");
|
|
2674
|
+
isSyncing = false;
|
|
2675
|
+
currentBackupDir = void 0;
|
|
2676
|
+
if (backupDir) {
|
|
2677
|
+
info(`
|
|
2678
|
+
\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7: ${backupDir}`);
|
|
2679
|
+
info("\u5FA9\u5143\u65B9\u6CD5: npx create-einja-app sync --rollback");
|
|
2680
|
+
}
|
|
2681
|
+
} finally {
|
|
2682
|
+
cleanup();
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
|
|
1834
2686
|
// src/cli.ts
|
|
1835
|
-
var __filename2 =
|
|
1836
|
-
var __dirname2 =
|
|
1837
|
-
var packageJsonPath =
|
|
2687
|
+
var __filename2 = fileURLToPath4(import.meta.url);
|
|
2688
|
+
var __dirname2 = dirname7(__filename2);
|
|
2689
|
+
var packageJsonPath = join17(__dirname2, "../package.json");
|
|
1838
2690
|
var packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
|
|
1839
2691
|
var program = new Command();
|
|
1840
2692
|
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").
|
|
2693
|
+
program.argument("[project-name]", "Project name").option("--skip-git", "Skip git initialization").option("--skip-install", "Skip package installation").action(
|
|
1842
2694
|
async (projectName, options) => {
|
|
1843
2695
|
await createCommand(projectName, options);
|
|
1844
2696
|
}
|
|
@@ -1846,13 +2698,26 @@ program.argument("[project-name]", "Project name").option("--skip-git", "Skip gi
|
|
|
1846
2698
|
program.command("setup").description("Setup tools for existing project").action(async () => {
|
|
1847
2699
|
await setupCommand();
|
|
1848
2700
|
});
|
|
1849
|
-
program.command("add").description("Add einja components to existing monorepo").option("
|
|
2701
|
+
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
2702
|
async (options) => {
|
|
1851
2703
|
await addCommand({
|
|
1852
|
-
skipPrompts: options.
|
|
2704
|
+
skipPrompts: options.all || false,
|
|
1853
2705
|
dryRun: options.dryRun || false
|
|
1854
2706
|
});
|
|
1855
2707
|
}
|
|
1856
2708
|
);
|
|
2709
|
+
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(
|
|
2710
|
+
async (options) => {
|
|
2711
|
+
await syncCommand({
|
|
2712
|
+
categories: options.categories?.split(","),
|
|
2713
|
+
all: options.all || false,
|
|
2714
|
+
dryRun: options.dryRun || false,
|
|
2715
|
+
backup: options.backup !== false,
|
|
2716
|
+
// デフォルトtrue
|
|
2717
|
+
rollback: options.rollback || false,
|
|
2718
|
+
force: options.force || false
|
|
2719
|
+
});
|
|
2720
|
+
}
|
|
2721
|
+
);
|
|
1857
2722
|
program.parse();
|
|
1858
2723
|
//# sourceMappingURL=cli.js.map
|