create-einja-app 0.2.19 → 0.3.1
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 +263 -22
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { readFileSync as
|
|
5
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
6
6
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7
|
-
import { dirname as dirname6, join as
|
|
7
|
+
import { dirname as dirname6, join as join8 } from "path";
|
|
8
8
|
|
|
9
9
|
// src/commands/create.ts
|
|
10
10
|
import { existsSync as existsSync3, readdirSync } from "fs";
|
|
@@ -537,7 +537,7 @@ async function createCommand(projectName, options) {
|
|
|
537
537
|
}
|
|
538
538
|
|
|
539
539
|
// src/commands/sync.ts
|
|
540
|
-
import { dirname as dirname5, join as
|
|
540
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
541
541
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
542
542
|
import fsExtra3 from "fs-extra";
|
|
543
543
|
import inquirer5 from "inquirer";
|
|
@@ -559,12 +559,57 @@ var CATEGORY_PATTERNS = {
|
|
|
559
559
|
docs: ["README.md", "docs/**"]
|
|
560
560
|
};
|
|
561
561
|
var ENV_FILE_PROTECTION = {
|
|
562
|
-
|
|
562
|
+
// 同期から保護するファイル(秘密鍵・暗号化済み値を含む)
|
|
563
|
+
protected: [
|
|
564
|
+
".env.keys",
|
|
565
|
+
".env.personal",
|
|
566
|
+
".env.develop",
|
|
567
|
+
".env.local",
|
|
568
|
+
".env.production",
|
|
569
|
+
".env.staging",
|
|
570
|
+
".env.preview"
|
|
571
|
+
],
|
|
572
|
+
// 同期を許可するファイル(テンプレート・例示ファイル)
|
|
573
|
+
allowed: [
|
|
574
|
+
".env.example",
|
|
575
|
+
".env.personal.example",
|
|
576
|
+
".envrc"
|
|
577
|
+
]
|
|
563
578
|
};
|
|
579
|
+
var SYNC_EXCLUDE_PATTERNS = [
|
|
580
|
+
"**/prisma/schema.prisma",
|
|
581
|
+
// DBモデルはユーザー固有
|
|
582
|
+
"**/prisma/migrations/**",
|
|
583
|
+
// マイグレーション履歴
|
|
584
|
+
"pnpm-lock.yaml",
|
|
585
|
+
// lockfile は sync すべきでない
|
|
586
|
+
"**/node_modules/**",
|
|
587
|
+
// 依存関係
|
|
588
|
+
"**/.git/**"
|
|
589
|
+
// Git内部
|
|
590
|
+
];
|
|
564
591
|
function isProtectedEnvFile(filePath) {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
592
|
+
const fileName = filePath.split("/").pop() ?? "";
|
|
593
|
+
if (ENV_FILE_PROTECTION.allowed.some((pattern) => fileName === pattern)) {
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
if (ENV_FILE_PROTECTION.protected.some((pattern) => fileName === pattern)) {
|
|
597
|
+
return true;
|
|
598
|
+
}
|
|
599
|
+
if (fileName.startsWith(".env")) {
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
function isExcludedFile(filePath) {
|
|
605
|
+
for (const pattern of SYNC_EXCLUDE_PATTERNS) {
|
|
606
|
+
const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\./g, "\\.");
|
|
607
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
608
|
+
if (regex.test(filePath)) {
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return false;
|
|
568
613
|
}
|
|
569
614
|
function extractPatternsFromCategories(categories, appsDetail, packagesDetail) {
|
|
570
615
|
const patterns = [];
|
|
@@ -619,6 +664,10 @@ async function collectSyncFiles(templateDir, categories, appsDetail, packagesDet
|
|
|
619
664
|
info(`\u4FDD\u8B77\u5BFE\u8C61\u30D5\u30A1\u30A4\u30EB\u3092\u9664\u5916: ${file}`);
|
|
620
665
|
return false;
|
|
621
666
|
}
|
|
667
|
+
if (isExcludedFile(file)) {
|
|
668
|
+
info(`\u9664\u5916\u30D1\u30BF\u30FC\u30F3\u306B\u30DE\u30C3\u30C1: ${file}`);
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
622
671
|
return true;
|
|
623
672
|
});
|
|
624
673
|
success(`${filteredFiles.length}\u500B\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u53CE\u96C6\u3057\u307E\u3057\u305F`);
|
|
@@ -1290,8 +1339,11 @@ async function mergePackageJson(existingContent, templateContent, packageJsonSec
|
|
|
1290
1339
|
return `${JSON.stringify(result, null, 2)}
|
|
1291
1340
|
`;
|
|
1292
1341
|
}
|
|
1293
|
-
async function mergeAndWriteFile(templatePath, targetPath, syncMetadata, packageJsonSections, conflictStrategy = "merge") {
|
|
1294
|
-
|
|
1342
|
+
async function mergeAndWriteFile(templatePath, targetPath, syncMetadata, packageJsonSections, conflictStrategy = "merge", templateVariables) {
|
|
1343
|
+
let templateContent = readFileSync3(templatePath, "utf-8");
|
|
1344
|
+
if (templateVariables) {
|
|
1345
|
+
templateContent = replacePlaceholders(templateContent, templateVariables);
|
|
1346
|
+
}
|
|
1295
1347
|
const targetExists = existsSync5(targetPath);
|
|
1296
1348
|
const existingContent = targetExists ? readFileSync3(targetPath, "utf-8") : null;
|
|
1297
1349
|
if (targetExists && conflictStrategy === "skip") {
|
|
@@ -1453,6 +1505,138 @@ function isPathSeed(filePath, keyPath, jsonPaths) {
|
|
|
1453
1505
|
return seedPaths.some((p) => keyPath === p || keyPath.startsWith(`${p}.`));
|
|
1454
1506
|
}
|
|
1455
1507
|
|
|
1508
|
+
// src/utils/placeholder-validator.ts
|
|
1509
|
+
import { readFile } from "fs/promises";
|
|
1510
|
+
import { join as join5 } from "path";
|
|
1511
|
+
var PLACEHOLDER_PATTERNS = [
|
|
1512
|
+
"@repo/",
|
|
1513
|
+
"{{packageName}}",
|
|
1514
|
+
"{{projectName}}",
|
|
1515
|
+
"{{description}}"
|
|
1516
|
+
];
|
|
1517
|
+
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1518
|
+
".png",
|
|
1519
|
+
".jpg",
|
|
1520
|
+
".jpeg",
|
|
1521
|
+
".gif",
|
|
1522
|
+
".ico",
|
|
1523
|
+
".svg",
|
|
1524
|
+
".woff",
|
|
1525
|
+
".woff2",
|
|
1526
|
+
".ttf",
|
|
1527
|
+
".eot",
|
|
1528
|
+
".zip",
|
|
1529
|
+
".tar",
|
|
1530
|
+
".gz",
|
|
1531
|
+
".pdf",
|
|
1532
|
+
".mp4",
|
|
1533
|
+
".mp3"
|
|
1534
|
+
]);
|
|
1535
|
+
var EXCLUDED_DIRS = ["node_modules/", ".git/", "dist/", ".next/"];
|
|
1536
|
+
function isBinaryFile(filePath) {
|
|
1537
|
+
const lastDot = filePath.lastIndexOf(".");
|
|
1538
|
+
if (lastDot === -1) return false;
|
|
1539
|
+
const ext = filePath.substring(lastDot).toLowerCase();
|
|
1540
|
+
return BINARY_EXTENSIONS.has(ext);
|
|
1541
|
+
}
|
|
1542
|
+
function isExcludedDir(filePath) {
|
|
1543
|
+
return EXCLUDED_DIRS.some((dir) => filePath.includes(dir));
|
|
1544
|
+
}
|
|
1545
|
+
async function validatePlaceholders(targetDir, filePaths) {
|
|
1546
|
+
const violations = [];
|
|
1547
|
+
for (const filePath of filePaths) {
|
|
1548
|
+
if (isBinaryFile(filePath) || isExcludedDir(filePath)) {
|
|
1549
|
+
continue;
|
|
1550
|
+
}
|
|
1551
|
+
try {
|
|
1552
|
+
const fullPath = join5(targetDir, filePath);
|
|
1553
|
+
const content = await readFile(fullPath, "utf-8");
|
|
1554
|
+
const lines = content.split("\n");
|
|
1555
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1556
|
+
const line = lines[i] ?? "";
|
|
1557
|
+
for (const pattern of PLACEHOLDER_PATTERNS) {
|
|
1558
|
+
if (line.includes(pattern)) {
|
|
1559
|
+
violations.push({
|
|
1560
|
+
filePath,
|
|
1561
|
+
line: i + 1,
|
|
1562
|
+
placeholder: pattern,
|
|
1563
|
+
context: line.trim()
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
} catch {
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
return {
|
|
1572
|
+
isValid: violations.length === 0,
|
|
1573
|
+
violations
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
// src/utils/project-detector.ts
|
|
1578
|
+
import { readFileSync as readFileSync4, existsSync as existsSync6, readdirSync as readdirSync3, statSync } from "fs";
|
|
1579
|
+
import { join as join6 } from "path";
|
|
1580
|
+
async function detectProjectConfig(targetDir) {
|
|
1581
|
+
let projectName = null;
|
|
1582
|
+
let packageScope = null;
|
|
1583
|
+
const rootPackageJsonPath = join6(targetDir, "package.json");
|
|
1584
|
+
if (existsSync6(rootPackageJsonPath)) {
|
|
1585
|
+
try {
|
|
1586
|
+
const rootPkg = JSON.parse(
|
|
1587
|
+
readFileSync4(rootPackageJsonPath, "utf-8")
|
|
1588
|
+
);
|
|
1589
|
+
if (rootPkg.name) {
|
|
1590
|
+
projectName = rootPkg.name;
|
|
1591
|
+
}
|
|
1592
|
+
} catch {
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
const candidateDirs = [join6(targetDir, "apps"), join6(targetDir, "packages")];
|
|
1596
|
+
for (const dir of candidateDirs) {
|
|
1597
|
+
if (!existsSync6(dir)) {
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
try {
|
|
1601
|
+
const entries = readdirSync3(dir);
|
|
1602
|
+
for (const entry of entries) {
|
|
1603
|
+
const entryPath = join6(dir, entry);
|
|
1604
|
+
if (!statSync(entryPath).isDirectory()) {
|
|
1605
|
+
continue;
|
|
1606
|
+
}
|
|
1607
|
+
const pkgJsonPath = join6(entryPath, "package.json");
|
|
1608
|
+
if (!existsSync6(pkgJsonPath)) {
|
|
1609
|
+
continue;
|
|
1610
|
+
}
|
|
1611
|
+
try {
|
|
1612
|
+
const pkg = JSON.parse(
|
|
1613
|
+
readFileSync4(pkgJsonPath, "utf-8")
|
|
1614
|
+
);
|
|
1615
|
+
if (pkg.name) {
|
|
1616
|
+
const match = pkg.name.match(/^(@[^/]+)\//);
|
|
1617
|
+
if (match?.[1]) {
|
|
1618
|
+
const detectedScope = match[1];
|
|
1619
|
+
if (packageScope && packageScope !== detectedScope) {
|
|
1620
|
+
console.warn(
|
|
1621
|
+
`\u8B66\u544A: \u7570\u306A\u308B\u30B9\u30B3\u30FC\u30D7\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\uFF08${packageScope} vs ${detectedScope}\uFF09\u3002\u6700\u521D\u306B\u898B\u3064\u304B\u3063\u305F ${packageScope} \u3092\u4F7F\u7528\u3057\u307E\u3059\u3002`
|
|
1622
|
+
);
|
|
1623
|
+
} else if (!packageScope) {
|
|
1624
|
+
packageScope = detectedScope;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
} catch {
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
} catch {
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
if (projectName && packageScope) {
|
|
1635
|
+
return { projectName, packageScope };
|
|
1636
|
+
}
|
|
1637
|
+
return null;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1456
1640
|
// src/commands/sync.ts
|
|
1457
1641
|
var currentBackupDir;
|
|
1458
1642
|
var isSyncing = false;
|
|
@@ -1490,19 +1674,19 @@ async function handleInterrupt() {
|
|
|
1490
1674
|
function getTemplatePath2() {
|
|
1491
1675
|
const __filename3 = fileURLToPath2(import.meta.url);
|
|
1492
1676
|
const __dirname3 = dirname5(__filename3);
|
|
1493
|
-
const { existsSync:
|
|
1494
|
-
const distPath =
|
|
1495
|
-
const srcPath =
|
|
1496
|
-
if (
|
|
1677
|
+
const { existsSync: existsSync7 } = fsExtra3;
|
|
1678
|
+
const distPath = join7(__dirname3, "../templates/default");
|
|
1679
|
+
const srcPath = join7(__dirname3, "../../templates/default");
|
|
1680
|
+
if (existsSync7(distPath)) {
|
|
1497
1681
|
return distPath;
|
|
1498
1682
|
}
|
|
1499
|
-
if (
|
|
1683
|
+
if (existsSync7(srcPath)) {
|
|
1500
1684
|
return srcPath;
|
|
1501
1685
|
}
|
|
1502
1686
|
throw new Error("\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
|
|
1503
1687
|
}
|
|
1504
1688
|
async function syncCommand(options) {
|
|
1505
|
-
const { existsSync:
|
|
1689
|
+
const { existsSync: existsSync7 } = fsExtra3;
|
|
1506
1690
|
const sigintHandler = () => {
|
|
1507
1691
|
handleInterrupt().catch((error2) => {
|
|
1508
1692
|
error(`\u30AF\u30EA\u30FC\u30F3\u30A2\u30C3\u30D7\u4E2D\u306B\u30A8\u30E9\u30FC: ${error2}`);
|
|
@@ -1579,6 +1763,52 @@ async function syncCommand(options) {
|
|
|
1579
1763
|
return;
|
|
1580
1764
|
}
|
|
1581
1765
|
info(`\u540C\u671F\u5BFE\u8C61: ${filesToSync.length}\u500B\u306E\u30D5\u30A1\u30A4\u30EB`);
|
|
1766
|
+
let templateVariables;
|
|
1767
|
+
info("\u{1F50D} \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u8A2D\u5B9A\u3092\u691C\u51FA\u4E2D...");
|
|
1768
|
+
const detectedConfig = await detectProjectConfig(targetDir);
|
|
1769
|
+
if (detectedConfig) {
|
|
1770
|
+
templateVariables = {
|
|
1771
|
+
projectName: detectedConfig.projectName,
|
|
1772
|
+
packageName: detectedConfig.packageScope,
|
|
1773
|
+
description: `${detectedConfig.projectName} - Einja Management Template`
|
|
1774
|
+
};
|
|
1775
|
+
info(` \u2713 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D: ${detectedConfig.projectName}`);
|
|
1776
|
+
info(` \u2713 \u30D1\u30C3\u30B1\u30FC\u30B8\u30B9\u30B3\u30FC\u30D7: ${detectedConfig.packageScope}`);
|
|
1777
|
+
} else {
|
|
1778
|
+
warn("\u26A0\uFE0F \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u8A2D\u5B9A\u3092\u81EA\u52D5\u691C\u51FA\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
1779
|
+
const inputAnswers = await inquirer5.prompt([
|
|
1780
|
+
{
|
|
1781
|
+
type: "input",
|
|
1782
|
+
name: "projectName",
|
|
1783
|
+
message: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044:",
|
|
1784
|
+
validate: (input) => {
|
|
1785
|
+
if (!input.trim()) {
|
|
1786
|
+
return "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D\u306F\u5FC5\u9808\u3067\u3059";
|
|
1787
|
+
}
|
|
1788
|
+
return true;
|
|
1789
|
+
}
|
|
1790
|
+
},
|
|
1791
|
+
{
|
|
1792
|
+
type: "input",
|
|
1793
|
+
name: "packageScope",
|
|
1794
|
+
message: "\u30D1\u30C3\u30B1\u30FC\u30B8\u30B9\u30B3\u30FC\u30D7\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: @mycompany\uFF09:",
|
|
1795
|
+
validate: (input) => {
|
|
1796
|
+
if (!input.trim()) {
|
|
1797
|
+
return "\u30D1\u30C3\u30B1\u30FC\u30B8\u30B9\u30B3\u30FC\u30D7\u306F\u5FC5\u9808\u3067\u3059";
|
|
1798
|
+
}
|
|
1799
|
+
if (!input.startsWith("@")) {
|
|
1800
|
+
return "\u30D1\u30C3\u30B1\u30FC\u30B8\u30B9\u30B3\u30FC\u30D7\u306F @ \u3067\u59CB\u307E\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u4F8B: @mycompany\uFF09";
|
|
1801
|
+
}
|
|
1802
|
+
return true;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
]);
|
|
1806
|
+
templateVariables = {
|
|
1807
|
+
projectName: inputAnswers.projectName,
|
|
1808
|
+
packageName: inputAnswers.packageScope,
|
|
1809
|
+
description: `${inputAnswers.projectName} - Einja Management Template`
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1582
1812
|
if (options.dryRun) {
|
|
1583
1813
|
info("\n\u{1F4CB} \u540C\u671F\u30D7\u30EC\u30D3\u30E5\u30FC (--dry-run)\n");
|
|
1584
1814
|
for (const file of filesToSync) {
|
|
@@ -1592,7 +1822,7 @@ async function syncCommand(options) {
|
|
|
1592
1822
|
let backupDir;
|
|
1593
1823
|
if (options.backup !== false) {
|
|
1594
1824
|
info("\u{1F4BE} \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u4F5C\u6210\u4E2D...");
|
|
1595
|
-
const existingFiles = filesToSync.filter((file) =>
|
|
1825
|
+
const existingFiles = filesToSync.filter((file) => existsSync7(join7(targetDir, file)));
|
|
1596
1826
|
if (existingFiles.length > 0) {
|
|
1597
1827
|
backupDir = await createBackup(targetDir, existingFiles);
|
|
1598
1828
|
currentBackupDir = backupDir;
|
|
@@ -1621,9 +1851,9 @@ async function syncCommand(options) {
|
|
|
1621
1851
|
};
|
|
1622
1852
|
for (const file of filesToSync) {
|
|
1623
1853
|
try {
|
|
1624
|
-
const sourcePath =
|
|
1625
|
-
const targetPath =
|
|
1626
|
-
if (!
|
|
1854
|
+
const sourcePath = join7(templatePath, file);
|
|
1855
|
+
const targetPath = join7(targetDir, file);
|
|
1856
|
+
if (!existsSync7(sourcePath)) {
|
|
1627
1857
|
warn(`\u30B9\u30AD\u30C3\u30D7: ${file} (\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u305B\u3093)`);
|
|
1628
1858
|
result.skipped++;
|
|
1629
1859
|
result.files.push({
|
|
@@ -1638,7 +1868,8 @@ async function syncCommand(options) {
|
|
|
1638
1868
|
targetPath,
|
|
1639
1869
|
syncMetadata,
|
|
1640
1870
|
packageJsonSections,
|
|
1641
|
-
conflictStrategy
|
|
1871
|
+
conflictStrategy,
|
|
1872
|
+
templateVariables
|
|
1642
1873
|
);
|
|
1643
1874
|
const mappedAction = mergeResult.action === "created" || mergeResult.action === "overwritten" ? "copied" : mergeResult.action;
|
|
1644
1875
|
result.success++;
|
|
@@ -1657,6 +1888,16 @@ async function syncCommand(options) {
|
|
|
1657
1888
|
error(` \u2717 ${file}: ${error2}`);
|
|
1658
1889
|
}
|
|
1659
1890
|
}
|
|
1891
|
+
const syncedFiles = result.files.filter((f) => f.action === "copied" || f.action === "merged").map((f) => f.path);
|
|
1892
|
+
if (syncedFiles.length > 0) {
|
|
1893
|
+
const validation = await validatePlaceholders(targetDir, syncedFiles);
|
|
1894
|
+
if (!validation.isValid) {
|
|
1895
|
+
warn("\n\u26A0 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u5909\u6570\u306E\u7F6E\u63DB\u6F0F\u308C\u3092\u691C\u51FA:");
|
|
1896
|
+
for (const v of validation.violations) {
|
|
1897
|
+
warn(` ${v.filePath}:${v.line} \u2014 ${v.placeholder}`);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1660
1901
|
info("\n\u{1F4CA} \u540C\u671F\u7D50\u679C:");
|
|
1661
1902
|
info(` \u6210\u529F: ${result.success}\u30D5\u30A1\u30A4\u30EB`);
|
|
1662
1903
|
if (result.skipped > 0) {
|
|
@@ -1689,8 +1930,8 @@ async function syncCommand(options) {
|
|
|
1689
1930
|
// src/cli.ts
|
|
1690
1931
|
var __filename2 = fileURLToPath3(import.meta.url);
|
|
1691
1932
|
var __dirname2 = dirname6(__filename2);
|
|
1692
|
-
var packageJsonPath =
|
|
1693
|
-
var packageJson = JSON.parse(
|
|
1933
|
+
var packageJsonPath = join8(__dirname2, "../package.json");
|
|
1934
|
+
var packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
|
|
1694
1935
|
var program = new Command();
|
|
1695
1936
|
program.name("create-einja-app").description("CLI tool to create new projects with Einja Management Template").version(packageJson.version);
|
|
1696
1937
|
program.argument("[project-name]", "Project name").option("--skip-git", "Skip git initialization").option("--skip-install", "Skip package installation").action(
|
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/sync.ts","../src/generators/sync.ts","../src/prompts/sync.ts","../src/utils/backup.ts","../src/utils/git.ts","../src/utils/merger.ts","../src/utils/package-json-merger.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 { 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// 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(\" pnpm dev # PostgreSQL起動 + 開発サーバー起動\"));\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 { 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 conflictStrategy\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 scripts: [\"scripts/**\"],\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\" | \"peerDependencies\" | \"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 firstRunDefault: true,\n },\n tools: {\n name: \"開発ツール\",\n description: \"biome.json, .prettierrc, .editorconfig, .vscode/\",\n patterns: [\"biome.json\", \".prettierrc*\", \".editorconfig\", \".vscode/\"],\n defaultChecked: true,\n firstRunDefault: true,\n },\n git: {\n name: \"Git設定\",\n description: \".gitignore, .gitattributes\",\n patterns: [\".gitignore\", \".gitattributes\"],\n defaultChecked: false,\n firstRunDefault: true,\n },\n \"git-hooks\": {\n name: \"Git Hooks\",\n description: \".husky/\",\n patterns: [\".husky/\"],\n defaultChecked: false,\n firstRunDefault: true,\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 firstRunDefault: true,\n },\n \"root-config\": {\n name: \"ルート設定\",\n description: \"package.json, tsconfig.json\",\n patterns: [\"package.json\", \"tsconfig.json\"],\n defaultChecked: false,\n firstRunDefault: true,\n },\n scripts: {\n name: \"スクリプト\",\n description: \"scripts/ 配下\",\n patterns: [\"scripts/**\"],\n defaultChecked: false,\n },\n apps: {\n name: \"アプリケーション\",\n description: \"apps/ 配下(次の画面で個別選択)\",\n patterns: [\"apps/**\"],\n defaultChecked: false,\n firstRunDefault: true,\n requiresDetailSelection: true,\n },\n packages: {\n name: \"共通パッケージ\",\n description: \"packages/ 配下(次の画面で個別選択)\",\n patterns: [\"packages/**\"],\n defaultChecked: false,\n firstRunDefault: true,\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 * @param isFirstRun - 初回実行かどうか\n * @returns SyncPromptResult - 同期設定\n */\nexport async function promptSyncCategories(\n templateDir: string,\n isFirstRun = false,\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: isFirstRun\n ? (config.firstRunDefault ?? config.defaultChecked ?? false)\n : (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\" | \"peerDependencies\" | \"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 { name: \"peerDependencies\", value: \"peerDependencies\", checked: false },\n ],\n },\n ]);\n packageJsonSections = packageJsonAnswers.sections as Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"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","import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport type { SyncMetadata, JsonPathsConfig, ConflictStrategy } 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 conflictStrategy: ConflictStrategy = \"merge\"\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 // conflictStrategy による早期リターン(ファイルが既に存在する場合のみ)\n if (targetExists && conflictStrategy === \"skip\") {\n return { action: \"skipped\", path: targetPath };\n }\n if (targetExists && conflictStrategy === \"overwrite\") {\n ensureDir(dirname(targetPath));\n writeFileSync(targetPath, templateContent, \"utf-8\");\n return { action: \"overwritten\", path: targetPath };\n }\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"],"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","dirname","join","fileURLToPath","fsExtra","inquirer","glob","glob","error","inquirer","error","inquirer","fsExtra","join","dirname","relative","ensureDir","fsExtra","join","dirname","error","relative","error","readFileSync","writeFileSync","existsSync","dirname","inquirer","inquirer","readFileSync","existsSync","dirname","writeFileSync","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/sync.ts","../src/generators/sync.ts","../src/prompts/sync.ts","../src/utils/backup.ts","../src/utils/git.ts","../src/utils/merger.ts","../src/utils/package-json-merger.ts","../src/utils/placeholder-validator.ts","../src/utils/project-detector.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 { 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// 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 */\nexport function 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(\" pnpm dev # PostgreSQL起動 + 開発サーバー起動\"));\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 { 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\";\nimport { validatePlaceholders } from \"../utils/placeholder-validator.js\";\nimport { detectProjectConfig } from \"../utils/project-detector.js\";\nimport type { TemplateVariables } from \"../generators/template.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 // d-2) プロジェクト設定の検出(テンプレート変数置換用)\n // ========================================\n let templateVariables: TemplateVariables | undefined;\n\n logger.info(\"🔍 プロジェクト設定を検出中...\");\n const detectedConfig = await detectProjectConfig(targetDir);\n\n if (detectedConfig) {\n // 検出成功\n templateVariables = {\n projectName: detectedConfig.projectName,\n packageName: detectedConfig.packageScope,\n description: `${detectedConfig.projectName} - Einja Management Template`,\n };\n logger.info(` ✓ プロジェクト名: ${detectedConfig.projectName}`);\n logger.info(` ✓ パッケージスコープ: ${detectedConfig.packageScope}`);\n } else {\n // 検出失敗 → 対話的に入力を求める\n logger.warn(\"⚠️ プロジェクト設定を自動検出できませんでした\");\n\n const inputAnswers = await inquirer.prompt([\n {\n type: \"input\",\n name: \"projectName\",\n message: \"プロジェクト名を入力してください:\",\n validate: (input: string) => {\n if (!input.trim()) {\n return \"プロジェクト名は必須です\";\n }\n return true;\n },\n },\n {\n type: \"input\",\n name: \"packageScope\",\n message: \"パッケージスコープを入力してください(例: @mycompany):\",\n validate: (input: string) => {\n if (!input.trim()) {\n return \"パッケージスコープは必須です\";\n }\n if (!input.startsWith(\"@\")) {\n return \"パッケージスコープは @ で始まる必要があります(例: @mycompany)\";\n }\n return true;\n },\n },\n ]);\n\n templateVariables = {\n projectName: inputAnswers.projectName as string,\n packageName: inputAnswers.packageScope as string,\n description: `${inputAnswers.projectName} - Einja Management Template`,\n };\n }\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 と templateVariables を渡す)\n const mergeResult = await mergeAndWriteFile(\n sourcePath,\n targetPath,\n syncMetadata,\n packageJsonSections,\n conflictStrategy,\n templateVariables\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 const syncedFiles = result.files\n .filter((f) => f.action === \"copied\" || f.action === \"merged\")\n .map((f) => f.path);\n\n if (syncedFiles.length > 0) {\n const validation = await validatePlaceholders(targetDir, syncedFiles);\n if (!validation.isValid) {\n logger.warn(\"\\n⚠ テンプレート変数の置換漏れを検出:\");\n for (const v of validation.violations) {\n logger.warn(` ${v.filePath}:${v.line} — ${v.placeholder}`);\n }\n }\n }\n\n // ========================================\n // i) 結果レポート\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 scripts: [\"scripts/**\"],\n apps: [\"apps/**\"],\n packages: [\"packages/**\"],\n docs: [\"README.md\", \"docs/**\"],\n};\n\n/**\n * envファイル保護ルール\n * これらのファイルは同期対象外(暗号化キーと個人設定)\n */\nconst ENV_FILE_PROTECTION = {\n // 同期から保護するファイル(秘密鍵・暗号化済み値を含む)\n protected: [\n \".env.keys\",\n \".env.personal\",\n \".env.develop\",\n \".env.local\",\n \".env.production\",\n \".env.staging\",\n \".env.preview\",\n ],\n // 同期を許可するファイル(テンプレート・例示ファイル)\n allowed: [\n \".env.example\",\n \".env.personal.example\",\n \".envrc\",\n ],\n};\n\n/**\n * 同期から除外するファイルパターン\n * ユーザー固有のデータやビルド生成物を除外\n */\nconst SYNC_EXCLUDE_PATTERNS = [\n \"**/prisma/schema.prisma\", // DBモデルはユーザー固有\n \"**/prisma/migrations/**\", // マイグレーション履歴\n \"pnpm-lock.yaml\", // lockfile は sync すべきでない\n \"**/node_modules/**\", // 依存関係\n \"**/.git/**\", // Git内部\n];\n\n/**\n * envファイルが保護対象かチェック(ホワイトリスト方式)\n * @param filePath - ファイルパス\n * @returns 保護対象の場合 true\n */\nfunction isProtectedEnvFile(filePath: string): boolean {\n const fileName = filePath.split(\"/\").pop() ?? \"\";\n\n // allowedリストに含まれる場合は保護しない(同期を許可)\n if (ENV_FILE_PROTECTION.allowed.some((pattern) => fileName === pattern)) {\n return false;\n }\n\n // protectedリストに含まれる場合は保護(同期を拒否)\n if (ENV_FILE_PROTECTION.protected.some((pattern) => fileName === pattern)) {\n return true;\n }\n\n // .env で始まるファイルはデフォルトで保護(allowedにない限り)\n if (fileName.startsWith(\".env\")) {\n return true;\n }\n\n return false;\n}\n\n/**\n * ファイルが除外パターンにマッチするかチェック\n * @param filePath - ファイルパス\n * @returns 除外対象の場合 true\n */\nfunction isExcludedFile(filePath: string): boolean {\n for (const pattern of SYNC_EXCLUDE_PATTERNS) {\n // 簡易的なパターンマッチング(glob 互換)\n const regexPattern = pattern\n .replace(/\\*\\*/g, \".*\") // ** → 任意のディレクトリ\n .replace(/\\*/g, \"[^/]*\") // * → 任意の文字(ただし / 以外)\n .replace(/\\./g, \"\\\\.\"); // . → エスケープ\n\n const regex = new RegExp(`^${regexPattern}$`);\n if (regex.test(filePath)) {\n return true;\n }\n }\n return false;\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 // 除外パターンにマッチするファイルを除外\n if (isExcludedFile(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\" | \"peerDependencies\" | \"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 firstRunDefault: true,\n },\n tools: {\n name: \"開発ツール\",\n description: \"biome.json, .prettierrc, .editorconfig, .vscode/\",\n patterns: [\"biome.json\", \".prettierrc*\", \".editorconfig\", \".vscode/\"],\n defaultChecked: true,\n firstRunDefault: true,\n },\n git: {\n name: \"Git設定\",\n description: \".gitignore, .gitattributes\",\n patterns: [\".gitignore\", \".gitattributes\"],\n defaultChecked: false,\n firstRunDefault: true,\n },\n \"git-hooks\": {\n name: \"Git Hooks\",\n description: \".husky/\",\n patterns: [\".husky/\"],\n defaultChecked: false,\n firstRunDefault: true,\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 firstRunDefault: true,\n },\n \"root-config\": {\n name: \"ルート設定\",\n description: \"package.json, tsconfig.json\",\n patterns: [\"package.json\", \"tsconfig.json\"],\n defaultChecked: false,\n firstRunDefault: true,\n },\n scripts: {\n name: \"スクリプト\",\n description: \"scripts/ 配下\",\n patterns: [\"scripts/**\"],\n defaultChecked: false,\n },\n apps: {\n name: \"アプリケーション\",\n description: \"apps/ 配下(次の画面で個別選択)\",\n patterns: [\"apps/**\"],\n defaultChecked: false,\n firstRunDefault: true,\n requiresDetailSelection: true,\n },\n packages: {\n name: \"共通パッケージ\",\n description: \"packages/ 配下(次の画面で個別選択)\",\n patterns: [\"packages/**\"],\n defaultChecked: false,\n firstRunDefault: true,\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 * @param isFirstRun - 初回実行かどうか\n * @returns SyncPromptResult - 同期設定\n */\nexport async function promptSyncCategories(\n templateDir: string,\n isFirstRun = false,\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: isFirstRun\n ? (config.firstRunDefault ?? config.defaultChecked ?? false)\n : (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\" | \"peerDependencies\" | \"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 { name: \"peerDependencies\", value: \"peerDependencies\", checked: false },\n ],\n },\n ]);\n packageJsonSections = packageJsonAnswers.sections as Array<\"scripts\" | \"dependencies\" | \"devDependencies\" | \"peerDependencies\" | \"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","import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport type { SyncMetadata, JsonPathsConfig, ConflictStrategy } from \"../types/index.js\";\nimport { ensureDir } from \"./fs.js\";\nimport { mergePackageJsonDependencies } from \"./package-json-merger.js\";\nimport * as logger from \"./logger.js\";\nimport { replacePlaceholders, type TemplateVariables } from \"../generators/template.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 * @param conflictStrategy - 競合戦略(デフォルト: \"merge\")\n * @param templateVariables - テンプレート変数(オプショナル)\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 conflictStrategy: ConflictStrategy = \"merge\",\n templateVariables?: TemplateVariables\n): Promise<{\n action: \"created\" | \"merged\" | \"skipped\" | \"overwritten\";\n path: string;\n}> {\n let templateContent = readFileSync(templatePath, \"utf-8\");\n\n // テンプレート変数が指定されている場合は置換を実行\n if (templateVariables) {\n templateContent = replacePlaceholders(templateContent, templateVariables);\n }\n\n const targetExists = existsSync(targetPath);\n const existingContent = targetExists ? readFileSync(targetPath, \"utf-8\") : null;\n\n // conflictStrategy による早期リターン(ファイルが既に存在する場合のみ)\n if (targetExists && conflictStrategy === \"skip\") {\n return { action: \"skipped\", path: targetPath };\n }\n if (targetExists && conflictStrategy === \"overwrite\") {\n ensureDir(dirname(targetPath));\n writeFileSync(targetPath, templateContent, \"utf-8\");\n return { action: \"overwritten\", path: targetPath };\n }\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 { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ValidationResult {\n isValid: boolean;\n violations: PlaceholderViolation[];\n}\n\nexport interface PlaceholderViolation {\n filePath: string;\n line: number;\n placeholder: string;\n context: string;\n}\n\nconst PLACEHOLDER_PATTERNS = [\n \"@repo/\",\n \"{{packageName}}\",\n \"{{projectName}}\",\n \"{{description}}\",\n];\n\nconst BINARY_EXTENSIONS = new Set([\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".ico\",\n \".svg\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n \".zip\",\n \".tar\",\n \".gz\",\n \".pdf\",\n \".mp4\",\n \".mp3\",\n]);\n\nconst EXCLUDED_DIRS = [\"node_modules/\", \".git/\", \"dist/\", \".next/\"];\n\nfunction isBinaryFile(filePath: string): boolean {\n const lastDot = filePath.lastIndexOf(\".\");\n if (lastDot === -1) return false;\n const ext = filePath.substring(lastDot).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\n}\n\nfunction isExcludedDir(filePath: string): boolean {\n return EXCLUDED_DIRS.some((dir) => filePath.includes(dir));\n}\n\n/**\n * 指定されたファイル群にテンプレートプレースホルダーが残っていないか検証する\n */\nexport async function validatePlaceholders(\n targetDir: string,\n filePaths: string[],\n): Promise<ValidationResult> {\n const violations: PlaceholderViolation[] = [];\n\n for (const filePath of filePaths) {\n if (isBinaryFile(filePath) || isExcludedDir(filePath)) {\n continue;\n }\n\n try {\n const fullPath = join(targetDir, filePath);\n const content = await readFile(fullPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n for (const pattern of PLACEHOLDER_PATTERNS) {\n if (line.includes(pattern)) {\n violations.push({\n filePath,\n line: i + 1,\n placeholder: pattern,\n context: line.trim(),\n });\n }\n }\n }\n } catch {\n // ファイル読み込み失敗時はスキップして続行\n }\n }\n\n return {\n isValid: violations.length === 0,\n violations,\n };\n}\n","import { readFileSync, existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * プロジェクト設定の型定義\n */\nexport interface ProjectConfig {\n projectName: string;\n packageScope: string; // e.g. \"@mycompany\"\n}\n\n/**\n * package.json からプロジェクト設定を検出する\n *\n * 検出の優先順位:\n * 1. ルート package.json の name フィールドから projectName を取得\n * 2. apps/ or packages/ 配下の package.json から name のスコープ部分を抽出\n * 例: \"@mycompany/web\" → \"@mycompany\"\n * 3. 検出できない場合は null を返す(呼び出し側で対話プロンプトにフォールバック)\n *\n * @param targetDir - ターゲットディレクトリパス\n * @returns プロジェクト設定、または検出失敗時は null\n */\nexport async function detectProjectConfig(\n targetDir: string\n): Promise<ProjectConfig | null> {\n let projectName: string | null = null;\n let packageScope: string | null = null;\n\n // 1. ルート package.json から projectName を取得\n const rootPackageJsonPath = join(targetDir, \"package.json\");\n if (existsSync(rootPackageJsonPath)) {\n try {\n const rootPkg = JSON.parse(\n readFileSync(rootPackageJsonPath, \"utf-8\")\n ) as { name?: string };\n if (rootPkg.name) {\n projectName = rootPkg.name;\n }\n } catch {\n // JSONパースエラーは無視して次の検出方法にフォールバック\n }\n }\n\n // 2. apps/ or packages/ 配下の package.json からスコープを抽出\n const candidateDirs = [join(targetDir, \"apps\"), join(targetDir, \"packages\")];\n\n for (const dir of candidateDirs) {\n if (!existsSync(dir)) {\n continue;\n }\n\n try {\n const entries = readdirSync(dir);\n\n for (const entry of entries) {\n const entryPath = join(dir, entry);\n\n // ディレクトリのみを対象\n if (!statSync(entryPath).isDirectory()) {\n continue;\n }\n\n const pkgJsonPath = join(entryPath, \"package.json\");\n if (!existsSync(pkgJsonPath)) {\n continue;\n }\n\n try {\n const pkg = JSON.parse(\n readFileSync(pkgJsonPath, \"utf-8\")\n ) as { name?: string };\n\n if (pkg.name) {\n // スコープの抽出(例: \"@mycompany/web\" → \"@mycompany\")\n const match = pkg.name.match(/^(@[^/]+)\\//);\n if (match?.[1]) {\n const detectedScope = match[1];\n\n // 既にスコープが検出されている場合は一致を検証\n if (packageScope && packageScope !== detectedScope) {\n // 異なるスコープが見つかった場合は警告(最初に見つかったものを使用)\n console.warn(\n `警告: 異なるスコープが検出されました(${packageScope} vs ${detectedScope})。最初に見つかった ${packageScope} を使用します。`\n );\n } else if (!packageScope) {\n packageScope = detectedScope;\n }\n }\n }\n } catch {\n // パースエラーは無視して次のファイルへ\n }\n }\n } catch {\n // ディレクトリ読み込みエラーは無視\n }\n }\n\n // 3. 検出結果を返す\n if (projectName && packageScope) {\n return { projectName, packageScope };\n }\n\n // どちらかが欠けている場合は null を返す\n return null;\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","dirname","join","fileURLToPath","fsExtra","inquirer","glob","glob","error","inquirer","error","inquirer","fsExtra","join","dirname","relative","ensureDir","fsExtra","join","dirname","error","relative","error","readFileSync","writeFileSync","existsSync","dirname","inquirer","inquirer","readFileSync","existsSync","dirname","writeFileSync","join","readFileSync","existsSync","readdirSync","join","inquirer","success","getTemplatePath","__filename","fileURLToPath","__dirname","dirname","existsSync","fsExtra","join","error","targetDir","__filename","fileURLToPath","__dirname","dirname","join","readFileSync"]}
|