@percepta/create 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/{chunk-GEVZERMP.js → chunk-7NPWSTCY.js} +3 -1
- package/dist/{chunk-R4FWPE4A.js → chunk-DCM7JOSC.js} +2 -2
- package/dist/index.js +371 -210
- package/dist/{init-Z4VGBHAK.js → init-NP6GRXLL.js} +1 -1
- package/dist/{status-MITGDLTT.js → status-BTHGN6QH.js} +1 -1
- package/dist/{sync-J4SFZHDX.js → sync-3Q27L7XZ.js} +1 -1
- package/dist/{upstream-AQI7P4EU.js → upstream-C5KFAHVR.js} +1 -1
- package/package.json +1 -1
- package/templates/webapp/.github/workflows/__APP_NAME__-ryvn-release.yaml +3 -2
- package/templates/webapp/AGENTS.md +8 -2
- package/templates/webapp/Dockerfile +0 -1
- package/templates/webapp/README.md +1 -0
- package/templates/webapp/agent-skills/database.md +1 -0
- package/templates/webapp/agent-skills/deploy.md +24 -27
- package/templates/webapp/agent-skills/oneshot.md +3 -3
- package/templates/webapp/deploy/README.md +8 -6
- package/templates/webapp/deploy/ryvn/__APP_NAME__.service.yaml +0 -2
- package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml +11 -27
- package/templates/webapp/drizzle.config.ts +15 -6
- package/templates/webapp/env.example.template +1 -0
- package/templates/webapp/eslint.config.mjs +7 -0
- package/templates/webapp/package.json.template +6 -6
- package/templates/webapp/scripts/open-ryvn-deploy-pr.ts +377 -0
- package/templates/webapp/scripts/seed.ts +1 -1
- package/templates/webapp/scripts/setup-database.ts +14 -0
- package/templates/webapp/src/app/global-error.tsx +2 -0
- package/templates/webapp/src/config/getEnvConfig.ts +1 -0
- package/templates/webapp/src/drizzle/db.ts +3 -0
- package/templates/webapp/src/drizzle/searchPath.test.ts +21 -0
- package/templates/webapp/src/drizzle/searchPath.ts +16 -0
- package/templates/webapp/src/styles/globals.css +0 -7
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
toSnakeCase,
|
|
8
8
|
toTitleCase,
|
|
9
9
|
validateProjectName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7NPWSTCY.js";
|
|
11
11
|
import {
|
|
12
12
|
derivePlaceholders,
|
|
13
13
|
writeManifest
|
|
@@ -17,10 +17,9 @@ import {
|
|
|
17
17
|
import { program } from "commander";
|
|
18
18
|
|
|
19
19
|
// src/commands/create.ts
|
|
20
|
-
import
|
|
20
|
+
import path7 from "path";
|
|
21
21
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
22
|
-
import
|
|
23
|
-
import fs4 from "fs-extra";
|
|
22
|
+
import fs7 from "fs-extra";
|
|
24
23
|
import chalk from "chalk";
|
|
25
24
|
import ora from "ora";
|
|
26
25
|
import { execSync, spawn } from "child_process";
|
|
@@ -255,14 +254,130 @@ 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
|
+
|
|
297
|
+
// src/utils/resolve-percepta-versions.ts
|
|
298
|
+
import path6 from "path";
|
|
299
|
+
import { execFile } from "child_process";
|
|
300
|
+
import { promisify } from "util";
|
|
301
|
+
import fs6 from "fs-extra";
|
|
302
|
+
var execFileAsync = promisify(execFile);
|
|
303
|
+
var DEPENDENCY_SECTIONS = [
|
|
304
|
+
"dependencies",
|
|
305
|
+
"devDependencies",
|
|
306
|
+
"optionalDependencies",
|
|
307
|
+
"peerDependencies"
|
|
308
|
+
];
|
|
309
|
+
function getPerceptaPackages(pkg) {
|
|
310
|
+
const names = /* @__PURE__ */ new Set();
|
|
311
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
312
|
+
const deps = pkg[section];
|
|
313
|
+
if (!deps) continue;
|
|
314
|
+
for (const name of Object.keys(deps)) {
|
|
315
|
+
if (name.startsWith("@percepta/")) {
|
|
316
|
+
names.add(name);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return [...names].sort();
|
|
321
|
+
}
|
|
322
|
+
async function npmViewDistTagLatest(packageName, cwd) {
|
|
323
|
+
const { stdout } = await execFileAsync(
|
|
324
|
+
"npm",
|
|
325
|
+
["view", packageName, "dist-tags.latest", "--silent"],
|
|
326
|
+
{
|
|
327
|
+
cwd,
|
|
328
|
+
encoding: "utf8",
|
|
329
|
+
timeout: 5e3
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
const version = stdout.trim();
|
|
333
|
+
return version.length > 0 ? version : null;
|
|
334
|
+
}
|
|
335
|
+
async function resolvePerceptaVersionsInPackageJson(packageJsonPath, lookupLatest = npmViewDistTagLatest) {
|
|
336
|
+
const cwd = path6.dirname(packageJsonPath);
|
|
337
|
+
const pkg = await fs6.readJson(packageJsonPath);
|
|
338
|
+
const packageNames = getPerceptaPackages(pkg);
|
|
339
|
+
const resolved = {};
|
|
340
|
+
const failed = [];
|
|
341
|
+
const results = await Promise.all(
|
|
342
|
+
packageNames.map(async (packageName) => {
|
|
343
|
+
try {
|
|
344
|
+
return {
|
|
345
|
+
packageName,
|
|
346
|
+
latest: await lookupLatest(packageName, cwd)
|
|
347
|
+
};
|
|
348
|
+
} catch {
|
|
349
|
+
return { packageName, latest: null };
|
|
350
|
+
}
|
|
351
|
+
})
|
|
352
|
+
);
|
|
353
|
+
for (const { packageName, latest } of results) {
|
|
354
|
+
if (!latest) {
|
|
355
|
+
failed.push(packageName);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
resolved[packageName] = latest;
|
|
359
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
360
|
+
const deps = pkg[section];
|
|
361
|
+
if (deps?.[packageName]) {
|
|
362
|
+
deps[packageName] = latest;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (Object.keys(resolved).length > 0) {
|
|
367
|
+
await fs6.writeJson(packageJsonPath, pkg, { spaces: 2 });
|
|
368
|
+
await fs6.appendFile(packageJsonPath, "\n");
|
|
369
|
+
}
|
|
370
|
+
return { resolved, failed };
|
|
371
|
+
}
|
|
372
|
+
|
|
258
373
|
// src/commands/create.ts
|
|
259
374
|
var PACKAGE_MANAGER = "pnpm";
|
|
260
375
|
function shPath(p) {
|
|
261
|
-
return p.split(
|
|
376
|
+
return p.split(path7.sep).join("/");
|
|
262
377
|
}
|
|
263
|
-
function runPackageManagerInstall(packageManager, cwd) {
|
|
378
|
+
function runPackageManagerInstall(packageManager, cwd, args = ["install"]) {
|
|
264
379
|
return new Promise((resolve, reject) => {
|
|
265
|
-
const child = spawn(packageManager,
|
|
380
|
+
const child = spawn(packageManager, args, {
|
|
266
381
|
cwd,
|
|
267
382
|
stdio: "ignore"
|
|
268
383
|
});
|
|
@@ -272,7 +387,7 @@ function runPackageManagerInstall(packageManager, cwd) {
|
|
|
272
387
|
else
|
|
273
388
|
reject(
|
|
274
389
|
new Error(
|
|
275
|
-
`${packageManager}
|
|
390
|
+
`${packageManager} ${args.join(" ")} exited with code ${code ?? "unknown"}`
|
|
276
391
|
)
|
|
277
392
|
);
|
|
278
393
|
});
|
|
@@ -376,48 +491,17 @@ async function autoRunWebapp(packageDir) {
|
|
|
376
491
|
return true;
|
|
377
492
|
}
|
|
378
493
|
function readTemplateVersions() {
|
|
379
|
-
const versionsPath =
|
|
380
|
-
|
|
494
|
+
const versionsPath = path7.resolve(
|
|
495
|
+
path7.dirname(fileURLToPath2(import.meta.url)),
|
|
381
496
|
"../template-versions.json"
|
|
382
497
|
);
|
|
383
498
|
try {
|
|
384
|
-
const content =
|
|
499
|
+
const content = fs7.readFileSync(versionsPath, "utf-8");
|
|
385
500
|
return JSON.parse(content);
|
|
386
501
|
} catch {
|
|
387
502
|
return {};
|
|
388
503
|
}
|
|
389
504
|
}
|
|
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
505
|
async function writeMosaicFiles(packageDir, config, projectType) {
|
|
422
506
|
const templateVersions = readTemplateVersions();
|
|
423
507
|
const manifest = {
|
|
@@ -431,8 +515,8 @@ async function writeMosaicFiles(packageDir, config, projectType) {
|
|
|
431
515
|
}
|
|
432
516
|
};
|
|
433
517
|
await writeManifest(packageDir, manifest);
|
|
434
|
-
const notesPath =
|
|
435
|
-
await
|
|
518
|
+
const notesPath = path7.join(packageDir, "mosaic-template-notes.md");
|
|
519
|
+
await fs7.writeFile(
|
|
436
520
|
notesPath,
|
|
437
521
|
`# Mosaic Divergence Notes
|
|
438
522
|
|
|
@@ -445,6 +529,133 @@ _None yet \u2014 freshly created from template._
|
|
|
445
529
|
`
|
|
446
530
|
);
|
|
447
531
|
}
|
|
532
|
+
async function scaffoldMonorepo(targetDir, config) {
|
|
533
|
+
const monoSpinner = ora("Copying monorepo template...").start();
|
|
534
|
+
try {
|
|
535
|
+
await copyTemplate(targetDir, "monorepo");
|
|
536
|
+
monoSpinner.succeed("Copied monorepo template");
|
|
537
|
+
} catch (error) {
|
|
538
|
+
monoSpinner.fail("Failed to copy monorepo template");
|
|
539
|
+
console.error(error);
|
|
540
|
+
process.exit(1);
|
|
541
|
+
}
|
|
542
|
+
const replaceSpinner = ora("Replacing monorepo placeholders...").start();
|
|
543
|
+
try {
|
|
544
|
+
const stats = await replacePlaceholders(targetDir, config);
|
|
545
|
+
replaceSpinner.succeed(
|
|
546
|
+
`Replaced placeholders in ${stats.modified} monorepo files`
|
|
547
|
+
);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
replaceSpinner.fail("Failed to replace monorepo placeholders");
|
|
550
|
+
console.error(error);
|
|
551
|
+
process.exit(1);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
async function addPackageToMonorepo(args) {
|
|
555
|
+
const { packageDir, monorepoRoot, projectType, config } = args;
|
|
556
|
+
const copySpinner = ora("Copying package template...").start();
|
|
557
|
+
try {
|
|
558
|
+
await copyTemplate(packageDir, projectType);
|
|
559
|
+
copySpinner.succeed("Copied package template");
|
|
560
|
+
} catch (error) {
|
|
561
|
+
copySpinner.fail("Failed to copy package template");
|
|
562
|
+
console.error(error);
|
|
563
|
+
process.exit(1);
|
|
564
|
+
}
|
|
565
|
+
const replaceSpinner = ora("Replacing package placeholders...").start();
|
|
566
|
+
try {
|
|
567
|
+
const stats = await replacePlaceholders(packageDir, config);
|
|
568
|
+
replaceSpinner.succeed(
|
|
569
|
+
`Replaced placeholders in ${stats.modified} package files`
|
|
570
|
+
);
|
|
571
|
+
} catch (error) {
|
|
572
|
+
replaceSpinner.fail("Failed to replace package placeholders");
|
|
573
|
+
console.error(error);
|
|
574
|
+
process.exit(1);
|
|
575
|
+
}
|
|
576
|
+
await writeMosaicFiles(packageDir, config, projectType);
|
|
577
|
+
if (projectType === "webapp") {
|
|
578
|
+
await resolvePerceptaPackageVersions(packageDir);
|
|
579
|
+
await generateEnvLocal(packageDir);
|
|
580
|
+
await relocateWorkflowsToRoot(packageDir, monorepoRoot, config.name);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
async function resolvePerceptaPackageVersions(packageDir) {
|
|
584
|
+
const packageJsonPath = path7.join(packageDir, "package.json");
|
|
585
|
+
if (!await fs7.pathExists(packageJsonPath)) return;
|
|
586
|
+
const spinner = ora("Resolving latest @percepta/* versions...").start();
|
|
587
|
+
try {
|
|
588
|
+
const result = await resolvePerceptaVersionsInPackageJson(packageJsonPath);
|
|
589
|
+
const count = Object.keys(result.resolved).length;
|
|
590
|
+
if (result.failed.length > 0) {
|
|
591
|
+
spinner.warn(
|
|
592
|
+
`Resolved ${count} @percepta/* versions; kept existing ranges for ${result.failed.join(", ")}`
|
|
593
|
+
);
|
|
594
|
+
} else {
|
|
595
|
+
spinner.succeed(`Resolved ${count} @percepta/* versions`);
|
|
596
|
+
}
|
|
597
|
+
} catch (error) {
|
|
598
|
+
spinner.warn(
|
|
599
|
+
"Could not resolve latest @percepta/* versions; kept template ranges"
|
|
600
|
+
);
|
|
601
|
+
console.log(chalk.dim(error.message));
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function initGitRepo(targetDir) {
|
|
605
|
+
const gitSpinner = ora("Initializing git repository...").start();
|
|
606
|
+
try {
|
|
607
|
+
execSync("git init", { cwd: targetDir, stdio: "ignore" });
|
|
608
|
+
execSync("git add -A", { cwd: targetDir, stdio: "ignore" });
|
|
609
|
+
execSync('git commit -m "Initial commit from @percepta/create"', {
|
|
610
|
+
cwd: targetDir,
|
|
611
|
+
stdio: "ignore"
|
|
612
|
+
});
|
|
613
|
+
gitSpinner.succeed("Initialized git repository");
|
|
614
|
+
} catch {
|
|
615
|
+
gitSpinner.warn("Failed to initialize git repository");
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
async function installAtMonorepoRoot(monorepoRoot, installDeps) {
|
|
619
|
+
if (!installDeps) return false;
|
|
620
|
+
const spinner = ora(
|
|
621
|
+
`Installing dependencies with ${PACKAGE_MANAGER}...`
|
|
622
|
+
).start();
|
|
623
|
+
try {
|
|
624
|
+
await runPackageManagerInstall(PACKAGE_MANAGER, monorepoRoot);
|
|
625
|
+
spinner.succeed("Installed dependencies");
|
|
626
|
+
return true;
|
|
627
|
+
} catch {
|
|
628
|
+
spinner.warn(
|
|
629
|
+
`Failed to install dependencies. Run '${PACKAGE_MANAGER} install' from monorepo root.`
|
|
630
|
+
);
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
async function installAtWebappPackage(packageDir, projectType, installDeps) {
|
|
635
|
+
if (!installDeps || !packageDir || projectType !== "webapp") {
|
|
636
|
+
return projectType !== "webapp";
|
|
637
|
+
}
|
|
638
|
+
const spinner = ora(
|
|
639
|
+
`Generating package lockfile with ${PACKAGE_MANAGER}...`
|
|
640
|
+
).start();
|
|
641
|
+
try {
|
|
642
|
+
await runPackageManagerInstall(PACKAGE_MANAGER, packageDir, [
|
|
643
|
+
"install",
|
|
644
|
+
"--ignore-workspace"
|
|
645
|
+
]);
|
|
646
|
+
spinner.succeed("Generated package lockfile");
|
|
647
|
+
return true;
|
|
648
|
+
} catch {
|
|
649
|
+
spinner.warn(
|
|
650
|
+
`Failed to generate package lockfile. Run '${PACKAGE_MANAGER} install --ignore-workspace' from ${packageDir}.`
|
|
651
|
+
);
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
async function maybeAutoRunWebapp(packageDir, projectType, installSucceeded) {
|
|
656
|
+
if (!packageDir || projectType !== "webapp" || !installSucceeded) return false;
|
|
657
|
+
return autoRunWebapp(packageDir);
|
|
658
|
+
}
|
|
448
659
|
function getProjectTypeLabel(projectType) {
|
|
449
660
|
switch (projectType) {
|
|
450
661
|
case "monorepo":
|
|
@@ -459,6 +670,35 @@ function getProjectTypeLabel(projectType) {
|
|
|
459
670
|
}
|
|
460
671
|
}
|
|
461
672
|
}
|
|
673
|
+
function requireNpmTokenForWebappInstall(projectType, installDeps) {
|
|
674
|
+
if (projectType !== "webapp" || !installDeps || process.env.NPM_TOKEN) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
console.log();
|
|
678
|
+
console.error(chalk.red("Error: NPM_TOKEN environment variable is not set."));
|
|
679
|
+
console.error(
|
|
680
|
+
chalk.dim(" Required to install private @percepta/* packages.")
|
|
681
|
+
);
|
|
682
|
+
console.error();
|
|
683
|
+
console.error(" 1. Grab the npm token from 1Password:");
|
|
684
|
+
console.error(
|
|
685
|
+
chalk.cyan(
|
|
686
|
+
" https://start.1password.com/open/i?a=5TX2B4O3QNE4FNQ2A7ZJZDRRBI&v=j7trpyuqh7gt635dtuj6y4pwjm&i=cmmdi5trji7ctkn3fseakf4mgi&h=aitco.1password.com"
|
|
687
|
+
)
|
|
688
|
+
);
|
|
689
|
+
console.error(" 2. Add to ~/.zshrc:");
|
|
690
|
+
console.error(chalk.cyan(' export NPM_TOKEN="<paste-token>"'));
|
|
691
|
+
console.error(
|
|
692
|
+
" 3. Open a new terminal (or " + chalk.cyan("source ~/.zshrc") + ") and re-run."
|
|
693
|
+
);
|
|
694
|
+
console.error();
|
|
695
|
+
console.error(
|
|
696
|
+
chalk.dim(
|
|
697
|
+
" Or pass --skip-install to scaffold without running install."
|
|
698
|
+
)
|
|
699
|
+
);
|
|
700
|
+
process.exit(1);
|
|
701
|
+
}
|
|
462
702
|
async function createProject(options) {
|
|
463
703
|
if (options.type !== void 0 && !isValidProjectType(options.type)) {
|
|
464
704
|
console.error(
|
|
@@ -511,8 +751,9 @@ async function createProject(options) {
|
|
|
511
751
|
let answers;
|
|
512
752
|
if (options.yes) {
|
|
513
753
|
const projectType = options.type || "webapp";
|
|
754
|
+
requireNpmTokenForWebappInstall(projectType, !options.skipInstall);
|
|
514
755
|
const kebabName = toKebabCase(projectName);
|
|
515
|
-
const directory = monorepoContext.found && monorepoContext.packageDir ?
|
|
756
|
+
const directory = monorepoContext.found && monorepoContext.packageDir ? path7.join(monorepoContext.packageDir, kebabName) : path7.resolve(cwd, kebabName);
|
|
516
757
|
answers = {
|
|
517
758
|
projectType,
|
|
518
759
|
directory,
|
|
@@ -525,10 +766,11 @@ async function createProject(options) {
|
|
|
525
766
|
projectType: options.type,
|
|
526
767
|
name: projectName ? toKebabCase(projectName) : void 0,
|
|
527
768
|
skipInstall: options.skipInstall,
|
|
528
|
-
monorepoContext
|
|
769
|
+
monorepoContext,
|
|
770
|
+
beforeNamePrompt: (projectType) => requireNpmTokenForWebappInstall(projectType, !options.skipInstall)
|
|
529
771
|
});
|
|
530
772
|
if (monorepoContext.found && monorepoContext.packageDir && !answers.directory) {
|
|
531
|
-
answers.directory =
|
|
773
|
+
answers.directory = path7.join(monorepoContext.packageDir, answers.name);
|
|
532
774
|
}
|
|
533
775
|
}
|
|
534
776
|
const config = {
|
|
@@ -540,7 +782,8 @@ async function createProject(options) {
|
|
|
540
782
|
};
|
|
541
783
|
const typeLabel = getProjectTypeLabel(answers.projectType);
|
|
542
784
|
if (monorepoContext.found) {
|
|
543
|
-
const
|
|
785
|
+
const monorepoRoot = monorepoContext.rootDir;
|
|
786
|
+
const packageDir = monorepoContext.packageDir ? path7.join(monorepoContext.packageDir, answers.name) : answers.directory;
|
|
544
787
|
console.log(chalk.dim(" Package type:"), typeLabel);
|
|
545
788
|
console.log(chalk.dim(" Target:"), packageDir);
|
|
546
789
|
console.log(chalk.dim(" Name:"), config.name);
|
|
@@ -549,8 +792,8 @@ async function createProject(options) {
|
|
|
549
792
|
console.log(chalk.dim(" Database:"), config.dbName);
|
|
550
793
|
}
|
|
551
794
|
console.log();
|
|
552
|
-
if (await
|
|
553
|
-
const files = await
|
|
795
|
+
if (await fs7.pathExists(packageDir)) {
|
|
796
|
+
const files = await fs7.readdir(packageDir);
|
|
554
797
|
if (files.length > 0) {
|
|
555
798
|
console.error(
|
|
556
799
|
chalk.red(`Error: Directory ${packageDir} is not empty.`)
|
|
@@ -558,81 +801,51 @@ async function createProject(options) {
|
|
|
558
801
|
process.exit(1);
|
|
559
802
|
}
|
|
560
803
|
}
|
|
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(
|
|
804
|
+
if (answers.projectType !== "monorepo") {
|
|
805
|
+
await addPackageToMonorepo({
|
|
587
806
|
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
|
-
}
|
|
807
|
+
monorepoRoot,
|
|
808
|
+
projectType: answers.projectType,
|
|
809
|
+
config
|
|
810
|
+
});
|
|
611
811
|
}
|
|
812
|
+
await warnIfMissingRootNpmrc(monorepoRoot);
|
|
813
|
+
const rootInstallSucceeded = await installAtMonorepoRoot(
|
|
814
|
+
monorepoRoot,
|
|
815
|
+
answers.installDeps
|
|
816
|
+
);
|
|
817
|
+
const packageInstallSucceeded = await installAtWebappPackage(
|
|
818
|
+
packageDir,
|
|
819
|
+
answers.projectType,
|
|
820
|
+
answers.installDeps
|
|
821
|
+
);
|
|
822
|
+
const installSucceeded = answers.projectType === "webapp" ? rootInstallSucceeded && packageInstallSucceeded : rootInstallSucceeded;
|
|
612
823
|
console.log();
|
|
613
824
|
console.log(
|
|
614
825
|
chalk.green("\u2714"),
|
|
615
826
|
chalk.bold(`Created ${typeLabel} at`),
|
|
616
|
-
chalk.cyan(
|
|
827
|
+
chalk.cyan(path7.relative(monorepoRoot, packageDir))
|
|
617
828
|
);
|
|
618
829
|
console.log();
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
830
|
+
const devStarted = await maybeAutoRunWebapp(
|
|
831
|
+
packageDir,
|
|
832
|
+
answers.projectType,
|
|
833
|
+
installSucceeded
|
|
834
|
+
);
|
|
835
|
+
if (devStarted) return;
|
|
623
836
|
printNextStepsExisting(answers, options, packageDir);
|
|
624
837
|
} else {
|
|
625
838
|
const isBareMonorepo = answers.projectType === "monorepo";
|
|
626
|
-
const
|
|
627
|
-
const packageDir = isBareMonorepo ? null :
|
|
839
|
+
const monorepoRoot = answers.directory;
|
|
840
|
+
const packageDir = isBareMonorepo ? null : path7.join(monorepoRoot, "packages", answers.name);
|
|
628
841
|
if (isBareMonorepo) {
|
|
629
842
|
console.log(chalk.dim(" Type:"), typeLabel);
|
|
630
|
-
console.log(chalk.dim(" Directory:"),
|
|
843
|
+
console.log(chalk.dim(" Directory:"), monorepoRoot);
|
|
631
844
|
console.log(chalk.dim(" Name:"), config.name);
|
|
632
845
|
console.log(chalk.dim(" Title:"), config.title);
|
|
633
846
|
} else {
|
|
634
847
|
console.log(chalk.dim(" Package type:"), typeLabel);
|
|
635
|
-
console.log(chalk.dim(" Monorepo directory:"),
|
|
848
|
+
console.log(chalk.dim(" Monorepo directory:"), monorepoRoot);
|
|
636
849
|
console.log(chalk.dim(" Package:"), `packages/${answers.name}/`);
|
|
637
850
|
console.log(chalk.dim(" Name:"), config.name);
|
|
638
851
|
console.log(chalk.dim(" Title:"), config.title);
|
|
@@ -641,101 +854,40 @@ async function createProject(options) {
|
|
|
641
854
|
}
|
|
642
855
|
}
|
|
643
856
|
console.log();
|
|
644
|
-
if (await
|
|
645
|
-
const files = await
|
|
857
|
+
if (await fs7.pathExists(monorepoRoot)) {
|
|
858
|
+
const files = await fs7.readdir(monorepoRoot);
|
|
646
859
|
if (files.length > 0) {
|
|
647
860
|
console.error(
|
|
648
|
-
chalk.red(`Error: Directory ${
|
|
861
|
+
chalk.red(`Error: Directory ${monorepoRoot} is not empty.`)
|
|
649
862
|
);
|
|
650
863
|
process.exit(1);
|
|
651
864
|
}
|
|
652
865
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
await
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
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`
|
|
692
|
-
);
|
|
693
|
-
} catch (error) {
|
|
694
|
-
pkgReplaceSpinner.fail("Failed to replace package placeholders");
|
|
695
|
-
console.error(error);
|
|
696
|
-
process.exit(1);
|
|
697
|
-
}
|
|
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
|
-
}
|
|
706
|
-
const gitSpinner = ora("Initializing git repository...").start();
|
|
707
|
-
try {
|
|
708
|
-
execSync("git init", { cwd: targetDir, stdio: "ignore" });
|
|
709
|
-
execSync("git add -A", { cwd: targetDir, stdio: "ignore" });
|
|
710
|
-
execSync('git commit -m "Initial commit from @percepta/create"', {
|
|
711
|
-
cwd: targetDir,
|
|
712
|
-
stdio: "ignore"
|
|
866
|
+
await scaffoldMonorepo(monorepoRoot, config);
|
|
867
|
+
if (packageDir && answers.projectType !== "monorepo") {
|
|
868
|
+
await addPackageToMonorepo({
|
|
869
|
+
packageDir,
|
|
870
|
+
monorepoRoot,
|
|
871
|
+
projectType: answers.projectType,
|
|
872
|
+
config
|
|
713
873
|
});
|
|
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
874
|
}
|
|
875
|
+
initGitRepo(monorepoRoot);
|
|
876
|
+
const rootInstallSucceeded = await installAtMonorepoRoot(
|
|
877
|
+
monorepoRoot,
|
|
878
|
+
answers.installDeps
|
|
879
|
+
);
|
|
880
|
+
const packageInstallSucceeded = await installAtWebappPackage(
|
|
881
|
+
packageDir,
|
|
882
|
+
answers.projectType,
|
|
883
|
+
answers.installDeps
|
|
884
|
+
);
|
|
885
|
+
const installSucceeded = answers.projectType === "webapp" ? rootInstallSucceeded && packageInstallSucceeded : rootInstallSucceeded;
|
|
734
886
|
console.log();
|
|
735
887
|
console.log(
|
|
736
888
|
chalk.green("\u2714"),
|
|
737
889
|
chalk.bold(isBareMonorepo ? `Created ${typeLabel} at` : "Created monorepo at"),
|
|
738
|
-
chalk.cyan(
|
|
890
|
+
chalk.cyan(monorepoRoot)
|
|
739
891
|
);
|
|
740
892
|
if (!isBareMonorepo) {
|
|
741
893
|
console.log(
|
|
@@ -745,11 +897,13 @@ async function createProject(options) {
|
|
|
745
897
|
);
|
|
746
898
|
}
|
|
747
899
|
console.log();
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
900
|
+
const devStarted = await maybeAutoRunWebapp(
|
|
901
|
+
packageDir,
|
|
902
|
+
answers.projectType,
|
|
903
|
+
installSucceeded
|
|
904
|
+
);
|
|
905
|
+
if (devStarted) return;
|
|
906
|
+
printNextStepsNew(answers, options, monorepoRoot);
|
|
753
907
|
}
|
|
754
908
|
}
|
|
755
909
|
function printWebappNextSteps(params) {
|
|
@@ -762,12 +916,15 @@ function printWebappNextSteps(params) {
|
|
|
762
916
|
} = params;
|
|
763
917
|
const repoRel = shPath(monorepoRelativePath) || ".";
|
|
764
918
|
const pkgFromRoot = `packages/${answers.name}`;
|
|
919
|
+
const packageInstallStep = `${pm} install --ignore-workspace`;
|
|
765
920
|
const pnpmSteps = ["pnpm run setup", "pnpm dev"];
|
|
766
921
|
if (variant === "new") {
|
|
767
922
|
const oneLinerParts2 = [];
|
|
768
923
|
if (repoRel !== ".") oneLinerParts2.push(`cd ${repoRel}`);
|
|
769
924
|
if (!answers.installDeps) oneLinerParts2.push(`${pm} install`);
|
|
770
|
-
oneLinerParts2.push(`cd ${pkgFromRoot}
|
|
925
|
+
oneLinerParts2.push(`cd ${pkgFromRoot}`);
|
|
926
|
+
if (!answers.installDeps) oneLinerParts2.push(packageInstallStep);
|
|
927
|
+
oneLinerParts2.push(...pnpmSteps);
|
|
771
928
|
console.log(chalk.bold("Copy-paste (from your current directory):"));
|
|
772
929
|
console.log();
|
|
773
930
|
console.log(chalk.cyan(` ${oneLinerParts2.join(" && ")}`));
|
|
@@ -782,6 +939,9 @@ function printWebappNextSteps(params) {
|
|
|
782
939
|
console.log(chalk.dim(` ${step2++}.`), `${pm} install`);
|
|
783
940
|
}
|
|
784
941
|
console.log(chalk.dim(` ${step2++}.`), `cd ${pkgFromRoot}`);
|
|
942
|
+
if (!answers.installDeps) {
|
|
943
|
+
console.log(chalk.dim(` ${step2++}.`), packageInstallStep);
|
|
944
|
+
}
|
|
785
945
|
for (const cmd of pnpmSteps) {
|
|
786
946
|
console.log(chalk.dim(` ${step2++}.`), cmd);
|
|
787
947
|
}
|
|
@@ -791,7 +951,7 @@ function printWebappNextSteps(params) {
|
|
|
791
951
|
const oneLinerParts = [];
|
|
792
952
|
if (!answers.installDeps) {
|
|
793
953
|
if (repoRel !== ".") oneLinerParts.push(`cd ${repoRel}`);
|
|
794
|
-
oneLinerParts.push(`${pm} install`, `cd ${pkgFromRoot}
|
|
954
|
+
oneLinerParts.push(`${pm} install`, `cd ${pkgFromRoot}`, packageInstallStep);
|
|
795
955
|
} else if (pkgRel !== ".") {
|
|
796
956
|
oneLinerParts.push(`cd ${pkgRel}`);
|
|
797
957
|
}
|
|
@@ -809,6 +969,7 @@ function printWebappNextSteps(params) {
|
|
|
809
969
|
}
|
|
810
970
|
console.log(chalk.dim(` ${step++}.`), `${pm} install`);
|
|
811
971
|
console.log(chalk.dim(` ${step++}.`), `cd ${pkgFromRoot}`);
|
|
972
|
+
console.log(chalk.dim(` ${step++}.`), packageInstallStep);
|
|
812
973
|
} else if (pkgRel !== ".") {
|
|
813
974
|
console.log(chalk.dim(` ${step++}.`), `cd ${pkgRel}`);
|
|
814
975
|
}
|
|
@@ -817,10 +978,10 @@ function printWebappNextSteps(params) {
|
|
|
817
978
|
}
|
|
818
979
|
}
|
|
819
980
|
async function warnIfMissingRootNpmrc(rootDir) {
|
|
820
|
-
const rootNpmrc =
|
|
981
|
+
const rootNpmrc = path7.join(rootDir, ".npmrc");
|
|
821
982
|
let contents = "";
|
|
822
|
-
if (await
|
|
823
|
-
contents = await
|
|
983
|
+
if (await fs7.pathExists(rootNpmrc)) {
|
|
984
|
+
contents = await fs7.readFile(rootNpmrc, "utf8");
|
|
824
985
|
}
|
|
825
986
|
if (contents.includes("@percepta:registry")) {
|
|
826
987
|
return;
|
|
@@ -835,7 +996,7 @@ async function warnIfMissingRootNpmrc(rootDir) {
|
|
|
835
996
|
" pnpm reads .npmrc from the workspace root, so add these lines to"
|
|
836
997
|
)
|
|
837
998
|
);
|
|
838
|
-
console.log(chalk.dim(` ${
|
|
999
|
+
console.log(chalk.dim(` ${path7.join(rootDir, ".npmrc")}:`));
|
|
839
1000
|
console.log();
|
|
840
1001
|
console.log(
|
|
841
1002
|
chalk.cyan(" @percepta:registry=https://registry.npmjs.org/")
|
|
@@ -847,7 +1008,7 @@ async function warnIfMissingRootNpmrc(rootDir) {
|
|
|
847
1008
|
}
|
|
848
1009
|
function printNextStepsNew(answers, options, targetDir) {
|
|
849
1010
|
const pm = PACKAGE_MANAGER;
|
|
850
|
-
const relativePath =
|
|
1011
|
+
const relativePath = path7.relative(process.cwd(), targetDir) || ".";
|
|
851
1012
|
console.log("Next steps:");
|
|
852
1013
|
console.log();
|
|
853
1014
|
switch (answers.projectType) {
|
|
@@ -903,9 +1064,9 @@ function printNextStepsNew(answers, options, targetDir) {
|
|
|
903
1064
|
}
|
|
904
1065
|
function printNextStepsExisting(answers, options, packageDir) {
|
|
905
1066
|
const pm = PACKAGE_MANAGER;
|
|
906
|
-
const packageRelativePath =
|
|
907
|
-
const monorepoRoot =
|
|
908
|
-
const monorepoRelativePath =
|
|
1067
|
+
const packageRelativePath = path7.relative(process.cwd(), packageDir) || ".";
|
|
1068
|
+
const monorepoRoot = path7.dirname(path7.dirname(packageDir));
|
|
1069
|
+
const monorepoRelativePath = path7.relative(process.cwd(), monorepoRoot) || ".";
|
|
909
1070
|
console.log("Next steps:");
|
|
910
1071
|
console.log();
|
|
911
1072
|
switch (answers.projectType) {
|
|
@@ -950,25 +1111,25 @@ program.command("status").description("Show template sync status for current app
|
|
|
950
1111
|
"--mosaic-template-path <path>",
|
|
951
1112
|
"Path to local mosaic repo checkout"
|
|
952
1113
|
).action(async (options) => {
|
|
953
|
-
const { statusCommand } = await import("./status-
|
|
1114
|
+
const { statusCommand } = await import("./status-BTHGN6QH.js");
|
|
954
1115
|
await statusCommand(options);
|
|
955
1116
|
});
|
|
956
1117
|
program.command("sync").description("Generate downstream sync context (template \u2192 app)").option(
|
|
957
1118
|
"--mosaic-template-path <path>",
|
|
958
1119
|
"Path to local mosaic repo checkout"
|
|
959
1120
|
).option("--to <version>", "Target template version (default: latest)").action(async (options) => {
|
|
960
|
-
const { syncCommand } = await import("./sync-
|
|
1121
|
+
const { syncCommand } = await import("./sync-3Q27L7XZ.js");
|
|
961
1122
|
await syncCommand(options);
|
|
962
1123
|
});
|
|
963
1124
|
program.command("upstream").description("Generate upstream context (app \u2192 template)").option(
|
|
964
1125
|
"--mosaic-template-path <path>",
|
|
965
1126
|
"Path to local mosaic repo checkout"
|
|
966
1127
|
).option("--files <patterns...>", "Specific files to propose upstream").action(async (options) => {
|
|
967
|
-
const { upstreamCommand } = await import("./upstream-
|
|
1128
|
+
const { upstreamCommand } = await import("./upstream-C5KFAHVR.js");
|
|
968
1129
|
await upstreamCommand(options);
|
|
969
1130
|
});
|
|
970
1131
|
program.command("init").description("Add .mosaic-template.json to an existing app").option("-t, --type <type>", "Template type (e.g., webapp, library)").option("--template-version <version>", "Template version to set").action(async (options) => {
|
|
971
|
-
const { initCommand } = await import("./init-
|
|
1132
|
+
const { initCommand } = await import("./init-NP6GRXLL.js");
|
|
972
1133
|
await initCommand(options);
|
|
973
1134
|
});
|
|
974
1135
|
program.parse();
|