@percepta/create 3.0.0 → 3.0.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/index.js +213 -199
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,10 +17,9 @@ import {
|
|
|
17
17
|
import { program } from "commander";
|
|
18
18
|
|
|
19
19
|
// src/commands/create.ts
|
|
20
|
-
import
|
|
20
|
+
import path6 from "path";
|
|
21
21
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
22
|
-
import
|
|
23
|
-
import fs4 from "fs-extra";
|
|
22
|
+
import fs6 from "fs-extra";
|
|
24
23
|
import chalk from "chalk";
|
|
25
24
|
import ora from "ora";
|
|
26
25
|
import { execSync, spawn } from "child_process";
|
|
@@ -255,10 +254,50 @@ async function detectMonorepo(startDir) {
|
|
|
255
254
|
return NOT_FOUND;
|
|
256
255
|
}
|
|
257
256
|
|
|
257
|
+
// src/utils/env-local.ts
|
|
258
|
+
import path4 from "path";
|
|
259
|
+
import { randomBytes } from "crypto";
|
|
260
|
+
import fs4 from "fs-extra";
|
|
261
|
+
async function generateEnvLocal(packageDir) {
|
|
262
|
+
const examplePath = path4.join(packageDir, ".env.example");
|
|
263
|
+
const localPath = path4.join(packageDir, ".env.local");
|
|
264
|
+
if (!await fs4.pathExists(examplePath)) return;
|
|
265
|
+
if (await fs4.pathExists(localPath)) return;
|
|
266
|
+
const authSecret = randomBytes(32).toString("base64");
|
|
267
|
+
const encKey = randomBytes(16).toString("hex");
|
|
268
|
+
const content = (await fs4.readFile(examplePath, "utf-8")).replace(/^BETTER_AUTH_SECRET=.*$/m, `BETTER_AUTH_SECRET=${authSecret}`).replace(/^ENCRYPTION_SECRET_KEY=.*$/m, `ENCRYPTION_SECRET_KEY=${encKey}`);
|
|
269
|
+
await fs4.writeFile(localPath, content);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/utils/relocate-workflows.ts
|
|
273
|
+
import path5 from "path";
|
|
274
|
+
import fs5 from "fs-extra";
|
|
275
|
+
async function relocateWorkflowsToRoot(packageDir, monorepoRoot, appName) {
|
|
276
|
+
const sourceDir = path5.join(packageDir, ".github", "workflows");
|
|
277
|
+
if (!await fs5.pathExists(sourceDir)) return;
|
|
278
|
+
const targetDir = path5.join(monorepoRoot, ".github", "workflows");
|
|
279
|
+
await fs5.ensureDir(targetDir);
|
|
280
|
+
const entries = await fs5.readdir(sourceDir);
|
|
281
|
+
for (const name of entries) {
|
|
282
|
+
if (!name.startsWith(`${appName}-`)) continue;
|
|
283
|
+
if (!/\.(ya?ml)$/.test(name)) continue;
|
|
284
|
+
await fs5.move(path5.join(sourceDir, name), path5.join(targetDir, name), {
|
|
285
|
+
overwrite: true
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
if ((await fs5.readdir(sourceDir)).length === 0) {
|
|
289
|
+
await fs5.rmdir(sourceDir);
|
|
290
|
+
const packageGithub = path5.join(packageDir, ".github");
|
|
291
|
+
if ((await fs5.readdir(packageGithub)).length === 0) {
|
|
292
|
+
await fs5.rmdir(packageGithub);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
258
297
|
// src/commands/create.ts
|
|
259
298
|
var PACKAGE_MANAGER = "pnpm";
|
|
260
299
|
function shPath(p) {
|
|
261
|
-
return p.split(
|
|
300
|
+
return p.split(path6.sep).join("/");
|
|
262
301
|
}
|
|
263
302
|
function runPackageManagerInstall(packageManager, cwd) {
|
|
264
303
|
return new Promise((resolve, reject) => {
|
|
@@ -376,48 +415,17 @@ async function autoRunWebapp(packageDir) {
|
|
|
376
415
|
return true;
|
|
377
416
|
}
|
|
378
417
|
function readTemplateVersions() {
|
|
379
|
-
const versionsPath =
|
|
380
|
-
|
|
418
|
+
const versionsPath = path6.resolve(
|
|
419
|
+
path6.dirname(fileURLToPath2(import.meta.url)),
|
|
381
420
|
"../template-versions.json"
|
|
382
421
|
);
|
|
383
422
|
try {
|
|
384
|
-
const content =
|
|
423
|
+
const content = fs6.readFileSync(versionsPath, "utf-8");
|
|
385
424
|
return JSON.parse(content);
|
|
386
425
|
} catch {
|
|
387
426
|
return {};
|
|
388
427
|
}
|
|
389
428
|
}
|
|
390
|
-
async function generateEnvLocal(packageDir) {
|
|
391
|
-
const examplePath = path4.join(packageDir, ".env.example");
|
|
392
|
-
const localPath = path4.join(packageDir, ".env.local");
|
|
393
|
-
if (!await fs4.pathExists(examplePath)) return;
|
|
394
|
-
if (await fs4.pathExists(localPath)) return;
|
|
395
|
-
const authSecret = randomBytes(32).toString("base64");
|
|
396
|
-
const encKey = randomBytes(16).toString("hex");
|
|
397
|
-
const content = (await fs4.readFile(examplePath, "utf-8")).replace(/^BETTER_AUTH_SECRET=.*$/m, `BETTER_AUTH_SECRET=${authSecret}`).replace(/^ENCRYPTION_SECRET_KEY=.*$/m, `ENCRYPTION_SECRET_KEY=${encKey}`);
|
|
398
|
-
await fs4.writeFile(localPath, content);
|
|
399
|
-
}
|
|
400
|
-
async function relocateWorkflowsToRoot(packageDir, monorepoRoot, appName) {
|
|
401
|
-
const sourceDir = path4.join(packageDir, ".github", "workflows");
|
|
402
|
-
if (!await fs4.pathExists(sourceDir)) return;
|
|
403
|
-
const targetDir = path4.join(monorepoRoot, ".github", "workflows");
|
|
404
|
-
await fs4.ensureDir(targetDir);
|
|
405
|
-
const entries = await fs4.readdir(sourceDir);
|
|
406
|
-
for (const name of entries) {
|
|
407
|
-
if (!name.startsWith(`${appName}-`)) continue;
|
|
408
|
-
if (!/\.(ya?ml)$/.test(name)) continue;
|
|
409
|
-
await fs4.move(path4.join(sourceDir, name), path4.join(targetDir, name), {
|
|
410
|
-
overwrite: true
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
if ((await fs4.readdir(sourceDir)).length === 0) {
|
|
414
|
-
await fs4.rmdir(sourceDir);
|
|
415
|
-
const packageGithub = path4.join(packageDir, ".github");
|
|
416
|
-
if ((await fs4.readdir(packageGithub)).length === 0) {
|
|
417
|
-
await fs4.rmdir(packageGithub);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
429
|
async function writeMosaicFiles(packageDir, config, projectType) {
|
|
422
430
|
const templateVersions = readTemplateVersions();
|
|
423
431
|
const manifest = {
|
|
@@ -431,8 +439,8 @@ async function writeMosaicFiles(packageDir, config, projectType) {
|
|
|
431
439
|
}
|
|
432
440
|
};
|
|
433
441
|
await writeManifest(packageDir, manifest);
|
|
434
|
-
const notesPath =
|
|
435
|
-
await
|
|
442
|
+
const notesPath = path6.join(packageDir, "mosaic-template-notes.md");
|
|
443
|
+
await fs6.writeFile(
|
|
436
444
|
notesPath,
|
|
437
445
|
`# Mosaic Divergence Notes
|
|
438
446
|
|
|
@@ -445,6 +453,90 @@ _None yet \u2014 freshly created from template._
|
|
|
445
453
|
`
|
|
446
454
|
);
|
|
447
455
|
}
|
|
456
|
+
async function scaffoldMonorepo(targetDir, config) {
|
|
457
|
+
const monoSpinner = ora("Copying monorepo template...").start();
|
|
458
|
+
try {
|
|
459
|
+
await copyTemplate(targetDir, "monorepo");
|
|
460
|
+
monoSpinner.succeed("Copied monorepo template");
|
|
461
|
+
} catch (error) {
|
|
462
|
+
monoSpinner.fail("Failed to copy monorepo template");
|
|
463
|
+
console.error(error);
|
|
464
|
+
process.exit(1);
|
|
465
|
+
}
|
|
466
|
+
const replaceSpinner = ora("Replacing monorepo placeholders...").start();
|
|
467
|
+
try {
|
|
468
|
+
const stats = await replacePlaceholders(targetDir, config);
|
|
469
|
+
replaceSpinner.succeed(
|
|
470
|
+
`Replaced placeholders in ${stats.modified} monorepo files`
|
|
471
|
+
);
|
|
472
|
+
} catch (error) {
|
|
473
|
+
replaceSpinner.fail("Failed to replace monorepo placeholders");
|
|
474
|
+
console.error(error);
|
|
475
|
+
process.exit(1);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
async function addPackageToMonorepo(args) {
|
|
479
|
+
const { packageDir, monorepoRoot, projectType, config } = args;
|
|
480
|
+
const copySpinner = ora("Copying package template...").start();
|
|
481
|
+
try {
|
|
482
|
+
await copyTemplate(packageDir, projectType);
|
|
483
|
+
copySpinner.succeed("Copied package template");
|
|
484
|
+
} catch (error) {
|
|
485
|
+
copySpinner.fail("Failed to copy package template");
|
|
486
|
+
console.error(error);
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
const replaceSpinner = ora("Replacing package placeholders...").start();
|
|
490
|
+
try {
|
|
491
|
+
const stats = await replacePlaceholders(packageDir, config);
|
|
492
|
+
replaceSpinner.succeed(
|
|
493
|
+
`Replaced placeholders in ${stats.modified} package files`
|
|
494
|
+
);
|
|
495
|
+
} catch (error) {
|
|
496
|
+
replaceSpinner.fail("Failed to replace package placeholders");
|
|
497
|
+
console.error(error);
|
|
498
|
+
process.exit(1);
|
|
499
|
+
}
|
|
500
|
+
await writeMosaicFiles(packageDir, config, projectType);
|
|
501
|
+
if (projectType === "webapp") {
|
|
502
|
+
await generateEnvLocal(packageDir);
|
|
503
|
+
await relocateWorkflowsToRoot(packageDir, monorepoRoot, config.name);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function initGitRepo(targetDir) {
|
|
507
|
+
const gitSpinner = ora("Initializing git repository...").start();
|
|
508
|
+
try {
|
|
509
|
+
execSync("git init", { cwd: targetDir, stdio: "ignore" });
|
|
510
|
+
execSync("git add -A", { cwd: targetDir, stdio: "ignore" });
|
|
511
|
+
execSync('git commit -m "Initial commit from @percepta/create"', {
|
|
512
|
+
cwd: targetDir,
|
|
513
|
+
stdio: "ignore"
|
|
514
|
+
});
|
|
515
|
+
gitSpinner.succeed("Initialized git repository");
|
|
516
|
+
} catch {
|
|
517
|
+
gitSpinner.warn("Failed to initialize git repository");
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
async function installAtMonorepoRoot(monorepoRoot, installDeps) {
|
|
521
|
+
if (!installDeps) return false;
|
|
522
|
+
const spinner = ora(
|
|
523
|
+
`Installing dependencies with ${PACKAGE_MANAGER}...`
|
|
524
|
+
).start();
|
|
525
|
+
try {
|
|
526
|
+
await runPackageManagerInstall(PACKAGE_MANAGER, monorepoRoot);
|
|
527
|
+
spinner.succeed("Installed dependencies");
|
|
528
|
+
return true;
|
|
529
|
+
} catch {
|
|
530
|
+
spinner.warn(
|
|
531
|
+
`Failed to install dependencies. Run '${PACKAGE_MANAGER} install' from monorepo root.`
|
|
532
|
+
);
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
async function maybeAutoRunWebapp(packageDir, projectType, installSucceeded) {
|
|
537
|
+
if (!packageDir || projectType !== "webapp" || !installSucceeded) return false;
|
|
538
|
+
return autoRunWebapp(packageDir);
|
|
539
|
+
}
|
|
448
540
|
function getProjectTypeLabel(projectType) {
|
|
449
541
|
switch (projectType) {
|
|
450
542
|
case "monorepo":
|
|
@@ -512,7 +604,7 @@ async function createProject(options) {
|
|
|
512
604
|
if (options.yes) {
|
|
513
605
|
const projectType = options.type || "webapp";
|
|
514
606
|
const kebabName = toKebabCase(projectName);
|
|
515
|
-
const directory = monorepoContext.found && monorepoContext.packageDir ?
|
|
607
|
+
const directory = monorepoContext.found && monorepoContext.packageDir ? path6.join(monorepoContext.packageDir, kebabName) : path6.resolve(cwd, kebabName);
|
|
516
608
|
answers = {
|
|
517
609
|
projectType,
|
|
518
610
|
directory,
|
|
@@ -528,9 +620,31 @@ async function createProject(options) {
|
|
|
528
620
|
monorepoContext
|
|
529
621
|
});
|
|
530
622
|
if (monorepoContext.found && monorepoContext.packageDir && !answers.directory) {
|
|
531
|
-
answers.directory =
|
|
623
|
+
answers.directory = path6.join(monorepoContext.packageDir, answers.name);
|
|
532
624
|
}
|
|
533
625
|
}
|
|
626
|
+
if (answers.projectType === "webapp" && answers.installDeps && !process.env.NPM_TOKEN) {
|
|
627
|
+
console.log();
|
|
628
|
+
console.error(chalk.red("Error: NPM_TOKEN environment variable is not set."));
|
|
629
|
+
console.error(chalk.dim(" Required to install private @percepta/* packages."));
|
|
630
|
+
console.error();
|
|
631
|
+
console.error(" 1. Grab the npm token from 1Password:");
|
|
632
|
+
console.error(
|
|
633
|
+
chalk.cyan(
|
|
634
|
+
" https://start.1password.com/open/i?a=5TX2B4O3QNE4FNQ2A7ZJZDRRBI&v=j7trpyuqh7gt635dtuj6y4pwjm&i=cmmdi5trji7ctkn3fseakf4mgi&h=aitco.1password.com"
|
|
635
|
+
)
|
|
636
|
+
);
|
|
637
|
+
console.error(" 2. Add to ~/.zshrc:");
|
|
638
|
+
console.error(chalk.cyan(' export NPM_TOKEN="<paste-token>"'));
|
|
639
|
+
console.error(" 3. Open a new terminal (or " + chalk.cyan("source ~/.zshrc") + ") and re-run.");
|
|
640
|
+
console.error();
|
|
641
|
+
console.error(
|
|
642
|
+
chalk.dim(
|
|
643
|
+
" Or pass --skip-install to scaffold without running install."
|
|
644
|
+
)
|
|
645
|
+
);
|
|
646
|
+
process.exit(1);
|
|
647
|
+
}
|
|
534
648
|
const config = {
|
|
535
649
|
name: answers.name,
|
|
536
650
|
title: answers.title,
|
|
@@ -540,7 +654,8 @@ async function createProject(options) {
|
|
|
540
654
|
};
|
|
541
655
|
const typeLabel = getProjectTypeLabel(answers.projectType);
|
|
542
656
|
if (monorepoContext.found) {
|
|
543
|
-
const
|
|
657
|
+
const monorepoRoot = monorepoContext.rootDir;
|
|
658
|
+
const packageDir = monorepoContext.packageDir ? path6.join(monorepoContext.packageDir, answers.name) : answers.directory;
|
|
544
659
|
console.log(chalk.dim(" Package type:"), typeLabel);
|
|
545
660
|
console.log(chalk.dim(" Target:"), packageDir);
|
|
546
661
|
console.log(chalk.dim(" Name:"), config.name);
|
|
@@ -549,8 +664,8 @@ async function createProject(options) {
|
|
|
549
664
|
console.log(chalk.dim(" Database:"), config.dbName);
|
|
550
665
|
}
|
|
551
666
|
console.log();
|
|
552
|
-
if (await
|
|
553
|
-
const files = await
|
|
667
|
+
if (await fs6.pathExists(packageDir)) {
|
|
668
|
+
const files = await fs6.readdir(packageDir);
|
|
554
669
|
if (files.length > 0) {
|
|
555
670
|
console.error(
|
|
556
671
|
chalk.red(`Error: Directory ${packageDir} is not empty.`)
|
|
@@ -558,81 +673,45 @@ async function createProject(options) {
|
|
|
558
673
|
process.exit(1);
|
|
559
674
|
}
|
|
560
675
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
await copyTemplate(packageDir, answers.projectType);
|
|
564
|
-
copySpinner.succeed("Copied template files");
|
|
565
|
-
} catch (error) {
|
|
566
|
-
copySpinner.fail("Failed to copy template files");
|
|
567
|
-
console.error(error);
|
|
568
|
-
process.exit(1);
|
|
569
|
-
}
|
|
570
|
-
const replaceSpinner = ora("Replacing placeholders...").start();
|
|
571
|
-
try {
|
|
572
|
-
const stats = await replacePlaceholders(packageDir, config);
|
|
573
|
-
replaceSpinner.succeed(
|
|
574
|
-
`Replaced placeholders in ${stats.modified} files`
|
|
575
|
-
);
|
|
576
|
-
} catch (error) {
|
|
577
|
-
replaceSpinner.fail("Failed to replace placeholders");
|
|
578
|
-
console.error(error);
|
|
579
|
-
process.exit(1);
|
|
580
|
-
}
|
|
581
|
-
await writeMosaicFiles(packageDir, config, answers.projectType);
|
|
582
|
-
if (answers.projectType === "webapp") {
|
|
583
|
-
await generateEnvLocal(packageDir);
|
|
584
|
-
}
|
|
585
|
-
if (answers.projectType === "webapp") {
|
|
586
|
-
await relocateWorkflowsToRoot(
|
|
676
|
+
if (answers.projectType !== "monorepo") {
|
|
677
|
+
await addPackageToMonorepo({
|
|
587
678
|
packageDir,
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
await warnIfMissingRootNpmrc(monorepoContext.rootDir);
|
|
593
|
-
let installSucceeded = false;
|
|
594
|
-
if (answers.installDeps) {
|
|
595
|
-
const packageManager = PACKAGE_MANAGER;
|
|
596
|
-
const installSpinner = ora(
|
|
597
|
-
`Installing dependencies with ${packageManager}...`
|
|
598
|
-
).start();
|
|
599
|
-
try {
|
|
600
|
-
await runPackageManagerInstall(
|
|
601
|
-
packageManager,
|
|
602
|
-
monorepoContext.rootDir
|
|
603
|
-
);
|
|
604
|
-
installSpinner.succeed("Installed dependencies");
|
|
605
|
-
installSucceeded = true;
|
|
606
|
-
} catch {
|
|
607
|
-
installSpinner.warn(
|
|
608
|
-
`Failed to install dependencies. Run '${packageManager} install' from monorepo root.`
|
|
609
|
-
);
|
|
610
|
-
}
|
|
679
|
+
monorepoRoot,
|
|
680
|
+
projectType: answers.projectType,
|
|
681
|
+
config
|
|
682
|
+
});
|
|
611
683
|
}
|
|
684
|
+
await warnIfMissingRootNpmrc(monorepoRoot);
|
|
685
|
+
const installSucceeded = await installAtMonorepoRoot(
|
|
686
|
+
monorepoRoot,
|
|
687
|
+
answers.installDeps
|
|
688
|
+
);
|
|
612
689
|
console.log();
|
|
613
690
|
console.log(
|
|
614
691
|
chalk.green("\u2714"),
|
|
615
692
|
chalk.bold(`Created ${typeLabel} at`),
|
|
616
|
-
chalk.cyan(
|
|
693
|
+
chalk.cyan(path6.relative(monorepoRoot, packageDir))
|
|
617
694
|
);
|
|
618
695
|
console.log();
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
696
|
+
const devStarted = await maybeAutoRunWebapp(
|
|
697
|
+
packageDir,
|
|
698
|
+
answers.projectType,
|
|
699
|
+
installSucceeded
|
|
700
|
+
);
|
|
701
|
+
if (devStarted) return;
|
|
623
702
|
printNextStepsExisting(answers, options, packageDir);
|
|
624
703
|
} else {
|
|
625
704
|
const isBareMonorepo = answers.projectType === "monorepo";
|
|
626
|
-
const
|
|
627
|
-
const packageDir = isBareMonorepo ? null :
|
|
705
|
+
const monorepoRoot = answers.directory;
|
|
706
|
+
const packageDir = isBareMonorepo ? null : path6.join(monorepoRoot, "packages", answers.name);
|
|
628
707
|
if (isBareMonorepo) {
|
|
629
708
|
console.log(chalk.dim(" Type:"), typeLabel);
|
|
630
|
-
console.log(chalk.dim(" Directory:"),
|
|
709
|
+
console.log(chalk.dim(" Directory:"), monorepoRoot);
|
|
631
710
|
console.log(chalk.dim(" Name:"), config.name);
|
|
632
711
|
console.log(chalk.dim(" Title:"), config.title);
|
|
633
712
|
} else {
|
|
634
713
|
console.log(chalk.dim(" Package type:"), typeLabel);
|
|
635
|
-
console.log(chalk.dim(" Monorepo directory:"),
|
|
714
|
+
console.log(chalk.dim(" Monorepo directory:"), monorepoRoot);
|
|
636
715
|
console.log(chalk.dim(" Package:"), `packages/${answers.name}/`);
|
|
637
716
|
console.log(chalk.dim(" Name:"), config.name);
|
|
638
717
|
console.log(chalk.dim(" Title:"), config.title);
|
|
@@ -641,101 +720,34 @@ async function createProject(options) {
|
|
|
641
720
|
}
|
|
642
721
|
}
|
|
643
722
|
console.log();
|
|
644
|
-
if (await
|
|
645
|
-
const files = await
|
|
723
|
+
if (await fs6.pathExists(monorepoRoot)) {
|
|
724
|
+
const files = await fs6.readdir(monorepoRoot);
|
|
646
725
|
if (files.length > 0) {
|
|
647
726
|
console.error(
|
|
648
|
-
chalk.red(`Error: Directory ${
|
|
649
|
-
);
|
|
650
|
-
process.exit(1);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
const monoSpinner = ora("Copying monorepo template...").start();
|
|
654
|
-
try {
|
|
655
|
-
await copyTemplate(targetDir, "monorepo");
|
|
656
|
-
monoSpinner.succeed("Copied monorepo template");
|
|
657
|
-
} catch (error) {
|
|
658
|
-
monoSpinner.fail("Failed to copy monorepo template");
|
|
659
|
-
console.error(error);
|
|
660
|
-
process.exit(1);
|
|
661
|
-
}
|
|
662
|
-
const monoReplaceSpinner = ora(
|
|
663
|
-
"Replacing monorepo placeholders..."
|
|
664
|
-
).start();
|
|
665
|
-
try {
|
|
666
|
-
const stats = await replacePlaceholders(targetDir, config);
|
|
667
|
-
monoReplaceSpinner.succeed(
|
|
668
|
-
`Replaced placeholders in ${stats.modified} monorepo files`
|
|
669
|
-
);
|
|
670
|
-
} catch (error) {
|
|
671
|
-
monoReplaceSpinner.fail("Failed to replace monorepo placeholders");
|
|
672
|
-
console.error(error);
|
|
673
|
-
process.exit(1);
|
|
674
|
-
}
|
|
675
|
-
if (packageDir) {
|
|
676
|
-
const pkgSpinner = ora("Copying package template...").start();
|
|
677
|
-
try {
|
|
678
|
-
await copyTemplate(packageDir, answers.projectType);
|
|
679
|
-
pkgSpinner.succeed("Copied package template");
|
|
680
|
-
} catch (error) {
|
|
681
|
-
pkgSpinner.fail("Failed to copy package template");
|
|
682
|
-
console.error(error);
|
|
683
|
-
process.exit(1);
|
|
684
|
-
}
|
|
685
|
-
const pkgReplaceSpinner = ora(
|
|
686
|
-
"Replacing package placeholders..."
|
|
687
|
-
).start();
|
|
688
|
-
try {
|
|
689
|
-
const stats = await replacePlaceholders(packageDir, config);
|
|
690
|
-
pkgReplaceSpinner.succeed(
|
|
691
|
-
`Replaced placeholders in ${stats.modified} package files`
|
|
727
|
+
chalk.red(`Error: Directory ${monorepoRoot} is not empty.`)
|
|
692
728
|
);
|
|
693
|
-
} catch (error) {
|
|
694
|
-
pkgReplaceSpinner.fail("Failed to replace package placeholders");
|
|
695
|
-
console.error(error);
|
|
696
729
|
process.exit(1);
|
|
697
730
|
}
|
|
698
|
-
await writeMosaicFiles(packageDir, config, answers.projectType);
|
|
699
|
-
if (answers.projectType === "webapp") {
|
|
700
|
-
await generateEnvLocal(packageDir);
|
|
701
|
-
}
|
|
702
|
-
if (answers.projectType === "webapp") {
|
|
703
|
-
await relocateWorkflowsToRoot(packageDir, targetDir, config.name);
|
|
704
|
-
}
|
|
705
731
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
732
|
+
await scaffoldMonorepo(monorepoRoot, config);
|
|
733
|
+
if (packageDir && answers.projectType !== "monorepo") {
|
|
734
|
+
await addPackageToMonorepo({
|
|
735
|
+
packageDir,
|
|
736
|
+
monorepoRoot,
|
|
737
|
+
projectType: answers.projectType,
|
|
738
|
+
config
|
|
713
739
|
});
|
|
714
|
-
gitSpinner.succeed("Initialized git repository");
|
|
715
|
-
} catch {
|
|
716
|
-
gitSpinner.warn("Failed to initialize git repository");
|
|
717
|
-
}
|
|
718
|
-
let installSucceeded = false;
|
|
719
|
-
if (answers.installDeps) {
|
|
720
|
-
const packageManager = PACKAGE_MANAGER;
|
|
721
|
-
const installSpinner = ora(
|
|
722
|
-
`Installing dependencies with ${packageManager}...`
|
|
723
|
-
).start();
|
|
724
|
-
try {
|
|
725
|
-
await runPackageManagerInstall(packageManager, targetDir);
|
|
726
|
-
installSpinner.succeed("Installed dependencies");
|
|
727
|
-
installSucceeded = true;
|
|
728
|
-
} catch {
|
|
729
|
-
installSpinner.warn(
|
|
730
|
-
`Failed to install dependencies. Run '${packageManager} install' manually.`
|
|
731
|
-
);
|
|
732
|
-
}
|
|
733
740
|
}
|
|
741
|
+
initGitRepo(monorepoRoot);
|
|
742
|
+
const installSucceeded = await installAtMonorepoRoot(
|
|
743
|
+
monorepoRoot,
|
|
744
|
+
answers.installDeps
|
|
745
|
+
);
|
|
734
746
|
console.log();
|
|
735
747
|
console.log(
|
|
736
748
|
chalk.green("\u2714"),
|
|
737
749
|
chalk.bold(isBareMonorepo ? `Created ${typeLabel} at` : "Created monorepo at"),
|
|
738
|
-
chalk.cyan(
|
|
750
|
+
chalk.cyan(monorepoRoot)
|
|
739
751
|
);
|
|
740
752
|
if (!isBareMonorepo) {
|
|
741
753
|
console.log(
|
|
@@ -745,11 +757,13 @@ async function createProject(options) {
|
|
|
745
757
|
);
|
|
746
758
|
}
|
|
747
759
|
console.log();
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
760
|
+
const devStarted = await maybeAutoRunWebapp(
|
|
761
|
+
packageDir,
|
|
762
|
+
answers.projectType,
|
|
763
|
+
installSucceeded
|
|
764
|
+
);
|
|
765
|
+
if (devStarted) return;
|
|
766
|
+
printNextStepsNew(answers, options, monorepoRoot);
|
|
753
767
|
}
|
|
754
768
|
}
|
|
755
769
|
function printWebappNextSteps(params) {
|
|
@@ -817,10 +831,10 @@ function printWebappNextSteps(params) {
|
|
|
817
831
|
}
|
|
818
832
|
}
|
|
819
833
|
async function warnIfMissingRootNpmrc(rootDir) {
|
|
820
|
-
const rootNpmrc =
|
|
834
|
+
const rootNpmrc = path6.join(rootDir, ".npmrc");
|
|
821
835
|
let contents = "";
|
|
822
|
-
if (await
|
|
823
|
-
contents = await
|
|
836
|
+
if (await fs6.pathExists(rootNpmrc)) {
|
|
837
|
+
contents = await fs6.readFile(rootNpmrc, "utf8");
|
|
824
838
|
}
|
|
825
839
|
if (contents.includes("@percepta:registry")) {
|
|
826
840
|
return;
|
|
@@ -835,7 +849,7 @@ async function warnIfMissingRootNpmrc(rootDir) {
|
|
|
835
849
|
" pnpm reads .npmrc from the workspace root, so add these lines to"
|
|
836
850
|
)
|
|
837
851
|
);
|
|
838
|
-
console.log(chalk.dim(` ${
|
|
852
|
+
console.log(chalk.dim(` ${path6.join(rootDir, ".npmrc")}:`));
|
|
839
853
|
console.log();
|
|
840
854
|
console.log(
|
|
841
855
|
chalk.cyan(" @percepta:registry=https://registry.npmjs.org/")
|
|
@@ -847,7 +861,7 @@ async function warnIfMissingRootNpmrc(rootDir) {
|
|
|
847
861
|
}
|
|
848
862
|
function printNextStepsNew(answers, options, targetDir) {
|
|
849
863
|
const pm = PACKAGE_MANAGER;
|
|
850
|
-
const relativePath =
|
|
864
|
+
const relativePath = path6.relative(process.cwd(), targetDir) || ".";
|
|
851
865
|
console.log("Next steps:");
|
|
852
866
|
console.log();
|
|
853
867
|
switch (answers.projectType) {
|
|
@@ -903,9 +917,9 @@ function printNextStepsNew(answers, options, targetDir) {
|
|
|
903
917
|
}
|
|
904
918
|
function printNextStepsExisting(answers, options, packageDir) {
|
|
905
919
|
const pm = PACKAGE_MANAGER;
|
|
906
|
-
const packageRelativePath =
|
|
907
|
-
const monorepoRoot =
|
|
908
|
-
const monorepoRelativePath =
|
|
920
|
+
const packageRelativePath = path6.relative(process.cwd(), packageDir) || ".";
|
|
921
|
+
const monorepoRoot = path6.dirname(path6.dirname(packageDir));
|
|
922
|
+
const monorepoRelativePath = path6.relative(process.cwd(), monorepoRoot) || ".";
|
|
909
923
|
console.log("Next steps:");
|
|
910
924
|
console.log();
|
|
911
925
|
switch (answers.projectType) {
|