@nextsparkjs/cli 0.1.0-beta.60 → 0.1.0-beta.62

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.
Files changed (2) hide show
  1. package/dist/cli.js +183 -2
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  // src/cli.ts
13
13
  import { config } from "dotenv";
14
14
  import { Command } from "commander";
15
- import chalk16 from "chalk";
15
+ import chalk17 from "chalk";
16
16
 
17
17
  // src/commands/dev.ts
18
18
  import { spawn } from "child_process";
@@ -3861,6 +3861,186 @@ async function dbSeedCommand() {
3861
3861
  await dbMigrateCommand();
3862
3862
  }
3863
3863
 
3864
+ // src/commands/sync-app.ts
3865
+ import { existsSync as existsSync10, readdirSync as readdirSync2, mkdirSync as mkdirSync3, copyFileSync, readFileSync as readFileSync9 } from "fs";
3866
+ import { join as join10, dirname as dirname3, relative } from "path";
3867
+ import chalk16 from "chalk";
3868
+ import ora10 from "ora";
3869
+ var EXCLUDED_TEMPLATE_PATTERNS = ["(templates)"];
3870
+ var MAX_VERBOSE_FILES = 10;
3871
+ var MAX_SUMMARY_FILES = 5;
3872
+ function getAllFiles(dir, baseDir = dir) {
3873
+ const files = [];
3874
+ if (!existsSync10(dir)) {
3875
+ return files;
3876
+ }
3877
+ const entries = readdirSync2(dir, { withFileTypes: true });
3878
+ for (const entry of entries) {
3879
+ const fullPath = join10(dir, entry.name);
3880
+ const relativePath = relative(baseDir, fullPath);
3881
+ if (entry.isDirectory()) {
3882
+ files.push(...getAllFiles(fullPath, baseDir));
3883
+ } else if (entry.isFile()) {
3884
+ if (entry.name !== ".DS_Store" && entry.name !== "README.md") {
3885
+ files.push(relativePath);
3886
+ }
3887
+ }
3888
+ }
3889
+ return files;
3890
+ }
3891
+ function copyFile(source, target) {
3892
+ const targetDir = dirname3(target);
3893
+ if (!existsSync10(targetDir)) {
3894
+ mkdirSync3(targetDir, { recursive: true });
3895
+ }
3896
+ copyFileSync(source, target);
3897
+ }
3898
+ function backupDirectory(source, target) {
3899
+ if (!existsSync10(source)) {
3900
+ return;
3901
+ }
3902
+ const files = getAllFiles(source);
3903
+ for (const file of files) {
3904
+ const sourcePath = join10(source, file);
3905
+ const targetPath = join10(target, file);
3906
+ copyFile(sourcePath, targetPath);
3907
+ }
3908
+ }
3909
+ function getCoreVersion2(coreDir) {
3910
+ try {
3911
+ const pkgPath = join10(coreDir, "package.json");
3912
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
3913
+ return pkg.version || "unknown";
3914
+ } catch {
3915
+ return "unknown";
3916
+ }
3917
+ }
3918
+ async function syncAppCommand(options) {
3919
+ const spinner = ora10({ text: "Preparing sync...", isSilent: options.dryRun }).start();
3920
+ try {
3921
+ const coreDir = getCoreDir();
3922
+ const projectRoot = getProjectRoot();
3923
+ const coreVersion = getCoreVersion2(coreDir);
3924
+ const templatesDir = join10(coreDir, "templates", "app");
3925
+ const appDir = join10(projectRoot, "app");
3926
+ if (!existsSync10(templatesDir)) {
3927
+ spinner.fail("Templates directory not found in @nextsparkjs/core");
3928
+ console.error(chalk16.red(`
3929
+ Expected path: ${templatesDir}`));
3930
+ process.exit(1);
3931
+ }
3932
+ if (!existsSync10(appDir)) {
3933
+ spinner.fail("No /app directory found");
3934
+ console.error(chalk16.red("\n This project does not have an /app folder."));
3935
+ console.error(chalk16.yellow(' Run "nextspark init" first to initialize your project.\n'));
3936
+ process.exit(1);
3937
+ }
3938
+ spinner.text = "Scanning template files...";
3939
+ const templateFiles = getAllFiles(templatesDir).filter((f) => !EXCLUDED_TEMPLATE_PATTERNS.some((pattern) => f.startsWith(pattern)));
3940
+ const existingAppFiles = getAllFiles(appDir);
3941
+ const customFiles = existingAppFiles.filter((f) => !templateFiles.includes(f));
3942
+ const filesToUpdate = templateFiles;
3943
+ spinner.succeed("Scan complete");
3944
+ console.log(chalk16.cyan(`
3945
+ Syncing /app with @nextsparkjs/core@${coreVersion}...
3946
+ `));
3947
+ if (options.dryRun) {
3948
+ console.log(chalk16.yellow(" [DRY RUN] No changes will be made\n"));
3949
+ }
3950
+ if (options.verbose) {
3951
+ console.log(chalk16.gray(" Files to sync:"));
3952
+ for (const file of filesToUpdate) {
3953
+ const targetPath = join10(appDir, file);
3954
+ const status = existsSync10(targetPath) ? chalk16.yellow("update") : chalk16.green("create");
3955
+ console.log(chalk16.gray(` ${status} ${file}`));
3956
+ }
3957
+ console.log();
3958
+ }
3959
+ console.log(chalk16.white(` Template files: ${filesToUpdate.length}`));
3960
+ console.log(chalk16.white(` Custom files preserved: ${customFiles.length}`));
3961
+ if (customFiles.length > 0 && options.verbose) {
3962
+ console.log(chalk16.gray("\n Custom files (will be preserved):"));
3963
+ for (const file of customFiles.slice(0, MAX_VERBOSE_FILES)) {
3964
+ console.log(chalk16.gray(` - ${file}`));
3965
+ }
3966
+ if (customFiles.length > MAX_VERBOSE_FILES) {
3967
+ console.log(chalk16.gray(` ... and ${customFiles.length - MAX_VERBOSE_FILES} more`));
3968
+ }
3969
+ }
3970
+ if (!options.force && !options.dryRun) {
3971
+ console.log(chalk16.yellow(`
3972
+ This will overwrite ${filesToUpdate.length} core template files.`));
3973
+ console.log(chalk16.gray(" Run with --dry-run to preview changes, or --force to skip this prompt.\n"));
3974
+ try {
3975
+ const { confirm: confirm6 } = await import("@inquirer/prompts");
3976
+ const confirmed = await confirm6({
3977
+ message: "Proceed with sync?",
3978
+ default: true
3979
+ });
3980
+ if (!confirmed) {
3981
+ console.log(chalk16.yellow("\n Sync cancelled.\n"));
3982
+ process.exit(0);
3983
+ }
3984
+ } catch (promptError) {
3985
+ console.error(chalk16.red("\n Failed to load confirmation prompt. Use --force to skip.\n"));
3986
+ process.exit(1);
3987
+ }
3988
+ }
3989
+ if (options.backup && !options.dryRun) {
3990
+ const backupDir = join10(projectRoot, `app.backup.v${coreVersion}.${Date.now()}`);
3991
+ spinner.start("Creating backup...");
3992
+ backupDirectory(appDir, backupDir);
3993
+ spinner.succeed(`Backup created: ${relative(projectRoot, backupDir)}`);
3994
+ }
3995
+ if (!options.dryRun) {
3996
+ spinner.start("Syncing files...");
3997
+ let updated = 0;
3998
+ let created = 0;
3999
+ for (const file of filesToUpdate) {
4000
+ const sourcePath = join10(templatesDir, file);
4001
+ const targetPath = join10(appDir, file);
4002
+ const isNew = !existsSync10(targetPath);
4003
+ copyFile(sourcePath, targetPath);
4004
+ if (isNew) {
4005
+ created++;
4006
+ } else {
4007
+ updated++;
4008
+ }
4009
+ if (options.verbose) {
4010
+ spinner.text = `Syncing: ${file}`;
4011
+ }
4012
+ }
4013
+ spinner.succeed(`Synced ${filesToUpdate.length} files (${updated} updated, ${created} created)`);
4014
+ }
4015
+ console.log(chalk16.green("\n \u2705 Sync complete!\n"));
4016
+ if (customFiles.length > 0) {
4017
+ console.log(chalk16.gray(` Preserved ${customFiles.length} custom file(s):`));
4018
+ for (const file of customFiles.slice(0, MAX_SUMMARY_FILES)) {
4019
+ console.log(chalk16.gray(` - app/${file}`));
4020
+ }
4021
+ if (customFiles.length > MAX_SUMMARY_FILES) {
4022
+ console.log(chalk16.gray(` ... and ${customFiles.length - MAX_SUMMARY_FILES} more
4023
+ `));
4024
+ } else {
4025
+ console.log();
4026
+ }
4027
+ }
4028
+ } catch (error) {
4029
+ spinner.fail("Sync failed");
4030
+ if (error instanceof Error) {
4031
+ console.error(chalk16.red(`
4032
+ Error: ${error.message}
4033
+ `));
4034
+ if (options.verbose && error.stack) {
4035
+ console.error(chalk16.gray(` Stack trace:
4036
+ ${error.stack}
4037
+ `));
4038
+ }
4039
+ }
4040
+ process.exit(1);
4041
+ }
4042
+ }
4043
+
3864
4044
  // src/cli.ts
3865
4045
  config();
3866
4046
  var program = new Command();
@@ -3882,8 +4062,9 @@ db.command("migrate").description("Run database migrations").action(dbMigrateCom
3882
4062
  db.command("seed").description("Seed database with sample data").action(dbSeedCommand);
3883
4063
  program.command("db:migrate").description("Run database migrations (alias)").action(dbMigrateCommand);
3884
4064
  program.command("db:seed").description("Seed database with sample data (alias)").action(dbSeedCommand);
4065
+ program.command("sync:app").description("Sync /app folder with @nextsparkjs/core templates").option("--dry-run", "Preview changes without applying").option("-f, --force", "Skip confirmation prompt").option("--backup", "Backup existing files before overwriting").option("-v, --verbose", "Show detailed file operations").action(syncAppCommand);
3885
4066
  program.showHelpAfterError();
3886
4067
  program.configureOutput({
3887
- writeErr: (str) => process.stderr.write(chalk16.red(str))
4068
+ writeErr: (str) => process.stderr.write(chalk17.red(str))
3888
4069
  });
3889
4070
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/cli",
3
- "version": "0.1.0-beta.60",
3
+ "version": "0.1.0-beta.62",
4
4
  "description": "NextSpark CLI - Complete development toolkit",
5
5
  "type": "module",
6
6
  "bin": {