@nanoforge-dev/cli 1.0.0 → 1.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/dist/nf.js CHANGED
@@ -40,7 +40,7 @@ var require_package = __commonJS({
40
40
  module2.exports = {
41
41
  $schema: "https://json.schemastore.org/package.json",
42
42
  name: "@nanoforge-dev/cli",
43
- version: "1.0.0",
43
+ version: "1.1.0",
44
44
  description: "NanoForge CLI",
45
45
  keywords: [
46
46
  "nanoforge",
@@ -82,55 +82,49 @@ var require_package = __commonJS({
82
82
  prepare: "husky"
83
83
  },
84
84
  dependencies: {
85
- "@angular-devkit/schematics": "^21.0.1",
86
- "@angular-devkit/schematics-cli": "^21.0.1",
87
- "@inquirer/prompts": "^7.9.0",
88
- "@nanoforge-dev/loader-client": "^1.0.1",
89
- "@nanoforge-dev/loader-server": "^1.0.1",
90
- "@nanoforge-dev/schematics": "^1.0.2",
91
- ansis: "^4.2.0",
92
- chokidar: "^4.0.3",
93
- "class-transformer": "^0.5.1",
94
- "class-validator": "^0.14.2",
95
- "cli-table3": "^0.6.5",
96
- commander: "^14.0.2",
97
- "node-emoji": "^2.2.0",
98
- ora: "^9.0.0",
99
- "reflect-metadata": "^0.2.2"
85
+ "@angular-devkit/schematics": "catalog:schematics",
86
+ "@angular-devkit/schematics-cli": "catalog:schematics",
87
+ "@inquirer/prompts": "catalog:cli",
88
+ "@nanoforge-dev/loader-client": "catalog:loader",
89
+ "@nanoforge-dev/loader-server": "catalog:loader",
90
+ "@nanoforge-dev/schematics": "catalog:schematics",
91
+ ansis: "catalog:cli",
92
+ bun: "catalog:core",
93
+ chokidar: "catalog:libs",
94
+ "class-transformer": "catalog:libs",
95
+ "class-validator": "catalog:libs",
96
+ commander: "catalog:cli",
97
+ "node-emoji": "catalog:cli",
98
+ ora: "catalog:cli",
99
+ "reflect-metadata": "catalog:libs"
100
100
  },
101
101
  devDependencies: {
102
- "@commitlint/cli": "^20.1.0",
103
- "@commitlint/config-conventional": "^20.0.0",
104
- "@eslint/js": "^9.39.0",
105
- "@favware/cliff-jumper": "^6.0.0",
106
- "@trivago/prettier-plugin-sort-imports": "^5.2.2",
107
- "@types/inquirer": "^9.0.9",
108
- "@types/node": "^24.10.1",
109
- "@typescript-eslint/eslint-plugin": "^8.46.2",
110
- "@typescript-eslint/parser": "^8.46.2",
111
- eslint: "^9.39.0",
112
- "eslint-config-prettier": "^10.1.8",
113
- "eslint-formatter-pretty": "^7.0.0",
114
- "eslint-plugin-prettier": "^5.5.4",
115
- globals: "^16.5.0",
116
- husky: "^9.1.7",
117
- "lint-staged": "^16.2.6",
118
- prettier: "^3.6.2",
119
- taze: "^19.9.0",
120
- tsup: "^8.5.1",
121
- typescript: "^5.9.3",
122
- "typescript-eslint": "^8.46.2"
102
+ "@commitlint/cli": "catalog:ci",
103
+ "@commitlint/config-conventional": "catalog:ci",
104
+ "@favware/cliff-jumper": "catalog:ci",
105
+ "@nanoforge-dev/actions": "catalog:ci",
106
+ "@nanoforge-dev/utils-eslint-config": "catalog:lint",
107
+ "@nanoforge-dev/utils-prettier-config": "catalog:lint",
108
+ "@trivago/prettier-plugin-sort-imports": "catalog:lint",
109
+ "@types/inquirer": "catalog:cli",
110
+ "@types/node": "catalog:core",
111
+ eslint: "catalog:lint",
112
+ husky: "catalog:ci",
113
+ "lint-staged": "catalog:ci",
114
+ prettier: "catalog:lint",
115
+ tsup: "catalog:build",
116
+ typescript: "catalog:build"
123
117
  },
124
- packageManager: "pnpm@10.24.0",
118
+ packageManager: "pnpm@10.28.1",
125
119
  engines: {
126
- node: "24.11.1"
120
+ node: "25"
127
121
  },
128
122
  publishConfig: {
129
123
  access: "public"
130
124
  },
131
125
  "lint-staged": {
132
- "**/*.ts": [
133
- "prettier --write"
126
+ "**": [
127
+ "prettier --ignore-unknown --write"
134
128
  ],
135
129
  "src/**/*.ts": [
136
130
  "eslint --fix"
@@ -157,7 +151,7 @@ var loadLocalBinCommandLoader = /* @__PURE__ */ __name(async () => {
157
151
  }, "loadLocalBinCommandLoader");
158
152
 
159
153
  // src/command/command.loader.ts
160
- import { red as red6 } from "ansis";
154
+ import { red as red8 } from "ansis";
161
155
 
162
156
  // src/lib/ui/messages.ts
163
157
  import { green } from "ansis";
@@ -187,7 +181,9 @@ var Emojis = {
187
181
  // src/lib/ui/messages.ts
188
182
  var Messages = {
189
183
  BUILD_START: "NanoForge Build",
190
- BUILD_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Building ${part}...`, "BUILD_PART_IN_PROGRESS"),
184
+ BUILD_WATCH_START: "Start watching mode",
185
+ BUILD_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Building ${part}`, "BUILD_PART_IN_PROGRESS"),
186
+ BUILD_PART_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((part) => `${part} updated. Rebuilding`, "BUILD_PART_WATCH_IN_PROGRESS"),
191
187
  BUILD_NOTHING: "Nothing to build, terminated.",
192
188
  BUILD_SUCCESS: `${Emojis.ROCKET} Build succeeded !`,
193
189
  BUILD_PART_FAILED: /* @__PURE__ */ __name((part, commandToRunManually) => `${Emojis.SCREAM} Build of ${part} failed !
@@ -204,8 +200,16 @@ In case you don't see any errors above, consider manually running the failed com
204
200
  NEW_STRICT_QUESTION: "Do you want to use types strict mode ?",
205
201
  NEW_SERVER_QUESTION: "Do you want generate a server to create a multiplayer game ?",
206
202
  NEW_SKIP_INSTALL_QUESTION: "Do you want to skip installation ?",
203
+ GENERATE_START: "NanoForge Generate",
204
+ GENERATE_WATCH_START: "Start watching mode",
205
+ GENERATE_SUCCESS: `${Emojis.ROCKET} Generate succeeded !`,
206
+ GENERATE_FAILED: `${Emojis.SCREAM} Generate failed !`,
207
+ DEV_START: "NanoForge Dev mode",
208
+ DEV_SUCCESS: "Dev mode ended",
209
+ DEV_FAILED: `${Emojis.SCREAM} Dev failed !`,
207
210
  SCHEMATICS_START: "Schematics execution",
208
211
  SCHEMATIC_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Executing schematic ${name}...`, "SCHEMATIC_IN_PROGRESS"),
212
+ SCHEMATIC_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Update watched. Executing schematic ${name}...`, "SCHEMATIC_WATCH_IN_PROGRESS"),
209
213
  SCHEMATIC_SUCCESS: /* @__PURE__ */ __name((name) => `${Emojis.ROCKET} Schematic ${name} executed successfully !`, "SCHEMATIC_SUCCESS"),
210
214
  SCHEMATIC_FAILED: /* @__PURE__ */ __name((name) => `${Emojis.SCREAM} Schematic ${name} execution failed. See error below for more details.`, "SCHEMATIC_FAILED"),
211
215
  PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS: `Installation in progress... ${Emojis.COFFEE}`,
@@ -230,7 +234,9 @@ var Prefixes = {
230
234
 
231
235
  // src/action/actions/build.action.ts
232
236
  import * as ansis from "ansis";
233
- import * as process3 from "process";
237
+ import { watch } from "chokidar";
238
+ import * as console2 from "console";
239
+ import { dirname, join as join3 } from "path";
234
240
 
235
241
  // src/lib/input/base-inputs.ts
236
242
  var getStringInput = /* @__PURE__ */ __name((input2, field) => {
@@ -279,6 +285,16 @@ var getConfigInput = /* @__PURE__ */ __name((inputs) => {
279
285
  return getStringInputWithDefault(inputs, "config", ".");
280
286
  }, "getConfigInput");
281
287
 
288
+ // src/lib/input/inputs/watch.input.ts
289
+ var getWatchInput = /* @__PURE__ */ __name((inputs) => {
290
+ return getBooleanInputWithDefault(inputs, "watch", false);
291
+ }, "getWatchInput");
292
+
293
+ // src/lib/input/inputs/dev/generate.input.ts
294
+ var getDevGenerateInput = /* @__PURE__ */ __name((inputs) => {
295
+ return getBooleanInputWithDefault(inputs, "generate", false);
296
+ }, "getDevGenerateInput");
297
+
282
298
  // src/lib/question/questions/confirm.question.ts
283
299
  import { confirm } from "@inquirer/prompts";
284
300
 
@@ -360,6 +376,10 @@ var getInstallNamesInputOrAsk = /* @__PURE__ */ __name((inputs) => {
360
376
  );
361
377
  }, "getInstallNamesInputOrAsk");
362
378
 
379
+ // src/lib/package-manager/package-manager.factory.ts
380
+ import fs from "fs";
381
+ import { resolve as resolve2 } from "path";
382
+
363
383
  // src/lib/runner/runner.factory.ts
364
384
  import { yellow } from "ansis";
365
385
 
@@ -382,7 +402,7 @@ var AbstractRunner = class {
382
402
  shell: true,
383
403
  env: { ...process2.env, ...env2 }
384
404
  };
385
- return new Promise((resolve, reject) => {
405
+ return new Promise((resolve3, reject) => {
386
406
  const child = spawn(
387
407
  `${this.binary} ${[...this.args, ...args].join(" ")}`,
388
408
  options
@@ -398,7 +418,7 @@ var AbstractRunner = class {
398
418
  );
399
419
  child.on("close", (code) => {
400
420
  if (code === 0) {
401
- resolve(collect && res.length ? res.join("\n") : null);
421
+ resolve3(collect && res.length ? res.join("\n") : null);
402
422
  } else {
403
423
  if (failSpinner) failSpinner();
404
424
  console.error(
@@ -431,15 +451,48 @@ var BunRunner = class extends AbstractRunner {
431
451
  };
432
452
 
433
453
  // src/lib/utils/path.ts
434
- import { join as join2 } from "path";
454
+ import { resolve } from "path";
435
455
  var getCwd = /* @__PURE__ */ __name((directory) => {
436
- return directory.startsWith("/") ? directory : join2(process.cwd(), directory);
456
+ return resolve(directory);
437
457
  }, "getCwd");
438
458
  var getModulePath = /* @__PURE__ */ __name((name, removeLast = false) => {
439
459
  const path = import.meta.resolve(name).replace(/^file:\/\//, "");
440
460
  if (removeLast) return path.split("/").slice(0, -1).join("/");
441
461
  return path;
442
462
  }, "getModulePath");
463
+ var getNodeBinaryPath = /* @__PURE__ */ __name((name) => {
464
+ return resolve("node_modules", ".bin", name);
465
+ }, "getNodeBinaryPath");
466
+
467
+ // src/lib/runner/runners/local-bun.runner.ts
468
+ var LocalBunRunner = class extends AbstractRunner {
469
+ static {
470
+ __name(this, "LocalBunRunner");
471
+ }
472
+ constructor() {
473
+ super(getNodeBinaryPath("bun"));
474
+ }
475
+ };
476
+
477
+ // src/lib/runner/runners/npm.runner.ts
478
+ var NpmRunner = class extends AbstractRunner {
479
+ static {
480
+ __name(this, "NpmRunner");
481
+ }
482
+ constructor() {
483
+ super("npm");
484
+ }
485
+ };
486
+
487
+ // src/lib/runner/runners/pnpm.runner.ts
488
+ var PnpmRunner = class extends AbstractRunner {
489
+ static {
490
+ __name(this, "PnpmRunner");
491
+ }
492
+ constructor() {
493
+ super("pnpm");
494
+ }
495
+ };
443
496
 
444
497
  // src/lib/runner/runners/schematic.runner.ts
445
498
  var SchematicRunner = class _SchematicRunner extends AbstractRunner {
@@ -462,6 +515,16 @@ var SchematicRunner = class _SchematicRunner extends AbstractRunner {
462
515
  }
463
516
  };
464
517
 
518
+ // src/lib/runner/runners/yarn.runner.ts
519
+ var YarnRunner = class extends AbstractRunner {
520
+ static {
521
+ __name(this, "YarnRunner");
522
+ }
523
+ constructor() {
524
+ super("yarn");
525
+ }
526
+ };
527
+
465
528
  // src/lib/runner/runner.factory.ts
466
529
  var RunnerFactory = class {
467
530
  static {
@@ -471,8 +534,16 @@ var RunnerFactory = class {
471
534
  switch (runner) {
472
535
  case 0 /* BUN */:
473
536
  return new BunRunner();
474
- case 1 /* SCHEMATIC */:
537
+ case 1 /* LOCAL_BUN */:
538
+ return new LocalBunRunner();
539
+ case 2 /* NPM */:
540
+ return new NpmRunner();
541
+ case 3 /* PNPM */:
542
+ return new PnpmRunner();
543
+ case 4 /* SCHEMATIC */:
475
544
  return new SchematicRunner();
545
+ case 5 /* YARN */:
546
+ return new YarnRunner();
476
547
  default:
477
548
  console.info(yellow`[WARN] Unsupported runner: ${runner}`);
478
549
  throw Error(`Unsupported runner: ${runner}`);
@@ -529,9 +600,11 @@ var AbstractPackageManager = class {
529
600
  const command = [this.cli.add, this.cli.saveDevFlag];
530
601
  return this.add(command, directory, dependencies);
531
602
  }
532
- async build(name, directory, entry, output, flags) {
603
+ async build(name, directory, entry, output, flags, watch3) {
533
604
  if (!this.cli.build) throw new Error(`Package manager ${this.name} does not support building`);
534
- const spinner = SPINNER(Messages.BUILD_PART_IN_PROGRESS(name));
605
+ const spinner = SPINNER(
606
+ (watch3 ? Messages.BUILD_PART_WATCH_IN_PROGRESS : Messages.BUILD_PART_IN_PROGRESS)(name)
607
+ );
535
608
  spinner.start();
536
609
  try {
537
610
  const commandArgs = [
@@ -561,7 +634,6 @@ var AbstractPackageManager = class {
561
634
  }
562
635
  }
563
636
  async run(name, directory, file, env2 = {}, flags = [], silent = false) {
564
- if (!this.cli.run) throw new Error(`Package manager ${this.name} does not support running`);
565
637
  try {
566
638
  console.info(Messages.RUN_PART_IN_PROGRESS(name));
567
639
  const commandArgs = [...flags, this.cli.run];
@@ -578,6 +650,15 @@ var AbstractPackageManager = class {
578
650
  return false;
579
651
  }
580
652
  }
653
+ async runDev(directory, command, env2 = {}, flags = [], collect = true) {
654
+ try {
655
+ const commandArgs = [this.cli.run, command, ...flags];
656
+ await this.runner.run(commandArgs, collect, getCwd(directory), env2);
657
+ return true;
658
+ } catch {
659
+ return false;
660
+ }
661
+ }
581
662
  async add(args, directory, dependencies) {
582
663
  if (!dependencies.length) {
583
664
  console.info();
@@ -649,7 +730,6 @@ var BunPackageManager = class extends AbstractPackageManager {
649
730
  add: "add",
650
731
  update: "update",
651
732
  remove: "remove",
652
- build: "build",
653
733
  run: "run",
654
734
  saveFlag: "--save",
655
735
  saveDevFlag: "--dev",
@@ -658,6 +738,108 @@ var BunPackageManager = class extends AbstractPackageManager {
658
738
  }
659
739
  };
660
740
 
741
+ // src/lib/package-manager/package-managers/local-bun.package-manager.ts
742
+ var LocalBunPackageManager = class extends AbstractPackageManager {
743
+ static {
744
+ __name(this, "LocalBunPackageManager");
745
+ }
746
+ constructor() {
747
+ super(RunnerFactory.create(1 /* LOCAL_BUN */));
748
+ }
749
+ get name() {
750
+ return "local_bun" /* LOCAL_BUN */.toUpperCase();
751
+ }
752
+ get cli() {
753
+ return {
754
+ install: "install",
755
+ add: "add",
756
+ update: "update",
757
+ remove: "remove",
758
+ run: "run",
759
+ build: "build",
760
+ runFile: "run",
761
+ saveFlag: "--save",
762
+ saveDevFlag: "--dev",
763
+ silentFlag: "--silent"
764
+ };
765
+ }
766
+ };
767
+
768
+ // src/lib/package-manager/package-managers/npm.package-manager.ts
769
+ var NpmPackageManager = class extends AbstractPackageManager {
770
+ static {
771
+ __name(this, "NpmPackageManager");
772
+ }
773
+ constructor() {
774
+ super(RunnerFactory.create(2 /* NPM */));
775
+ }
776
+ get name() {
777
+ return "npm" /* NPM */.toUpperCase();
778
+ }
779
+ get cli() {
780
+ return {
781
+ install: "install",
782
+ add: "install",
783
+ update: "update",
784
+ remove: "uninstall",
785
+ run: "run",
786
+ saveFlag: "--save",
787
+ saveDevFlag: "--save-dev",
788
+ silentFlag: "--silent"
789
+ };
790
+ }
791
+ };
792
+
793
+ // src/lib/package-manager/package-managers/pnpm.package-manager.ts
794
+ var PnpmPackageManager = class extends AbstractPackageManager {
795
+ static {
796
+ __name(this, "PnpmPackageManager");
797
+ }
798
+ constructor() {
799
+ super(RunnerFactory.create(3 /* PNPM */));
800
+ }
801
+ get name() {
802
+ return "pnpm" /* PNPM */.toUpperCase();
803
+ }
804
+ get cli() {
805
+ return {
806
+ install: "install",
807
+ add: "add",
808
+ update: "update",
809
+ remove: "remove",
810
+ run: "run",
811
+ saveFlag: "-P",
812
+ saveDevFlag: "-D",
813
+ silentFlag: "--silent"
814
+ };
815
+ }
816
+ };
817
+
818
+ // src/lib/package-manager/package-managers/yarn.package-manager.ts
819
+ var YarnPackageManager = class extends AbstractPackageManager {
820
+ static {
821
+ __name(this, "YarnPackageManager");
822
+ }
823
+ constructor() {
824
+ super(RunnerFactory.create(5 /* YARN */));
825
+ }
826
+ get name() {
827
+ return "yarn" /* YARN */.toUpperCase();
828
+ }
829
+ get cli() {
830
+ return {
831
+ install: "install",
832
+ add: "add",
833
+ update: "update",
834
+ remove: "remove",
835
+ run: "run",
836
+ saveFlag: "",
837
+ saveDevFlag: "-D",
838
+ silentFlag: "--silent"
839
+ };
840
+ }
841
+ };
842
+
661
843
  // src/lib/package-manager/package-manager.factory.ts
662
844
  var PackageManagerFactory = class {
663
845
  static {
@@ -667,10 +849,39 @@ var PackageManagerFactory = class {
667
849
  switch (name) {
668
850
  case "bun" /* BUN */:
669
851
  return new BunPackageManager();
852
+ case "local_bun" /* LOCAL_BUN */:
853
+ return new LocalBunPackageManager();
854
+ case "npm" /* NPM */:
855
+ return new NpmPackageManager();
856
+ case "pnpm" /* PNPM */:
857
+ return new PnpmPackageManager();
858
+ case "yarn" /* YARN */:
859
+ return new YarnPackageManager();
670
860
  default:
671
861
  throw new Error(`Package manager ${name} is not managed.`);
672
862
  }
673
863
  }
864
+ static async find(directory = ".") {
865
+ const DEFAULT_PACKAGE_MANAGER = "npm" /* NPM */;
866
+ try {
867
+ const files = await fs.promises.readdir(resolve2(directory));
868
+ if (files.includes("bun.lock")) {
869
+ return this.create("bun" /* BUN */);
870
+ }
871
+ if (files.includes("package-lock.json")) {
872
+ return this.create("npm" /* NPM */);
873
+ }
874
+ if (files.includes("pnpm-lock.yaml")) {
875
+ return this.create("pnpm" /* PNPM */);
876
+ }
877
+ if (files.includes("yarn.lock")) {
878
+ return this.create("yarn" /* YARN */);
879
+ }
880
+ return this.create(DEFAULT_PACKAGE_MANAGER);
881
+ } catch {
882
+ return this.create(DEFAULT_PACKAGE_MANAGER);
883
+ }
884
+ }
674
885
  };
675
886
 
676
887
  // src/lib/config/config.type.ts
@@ -796,7 +1007,7 @@ __decorateClass([
796
1007
  import { plainToInstance } from "class-transformer";
797
1008
  import { validate } from "class-validator";
798
1009
  import { existsSync as existsSync2, readFileSync } from "fs";
799
- import { join as join3 } from "path";
1010
+ import { join as join2 } from "path";
800
1011
 
801
1012
  // src/lib/utils/object.ts
802
1013
  var isObject = /* @__PURE__ */ __name((item) => {
@@ -851,10 +1062,10 @@ var CONFIG_DEFAULTS = {
851
1062
  var config;
852
1063
  var getConfigPath = /* @__PURE__ */ __name((directory, name) => {
853
1064
  if (name) {
854
- return join3(directory, name);
1065
+ return join2(directory, name);
855
1066
  } else {
856
1067
  for (const n of ["nanoforge.config.json"]) {
857
- const path = join3(directory, n);
1068
+ const path = join2(directory, n);
858
1069
  if (existsSync2(path)) return path;
859
1070
  }
860
1071
  throw new Error(`Unsupported config: ${name}`);
@@ -900,32 +1111,38 @@ var BuildAction = class extends AbstractAction {
900
1111
  __name(this, "BuildAction");
901
1112
  }
902
1113
  async handle(_args, options) {
903
- console.info(Messages.BUILD_START);
904
- console.info();
1114
+ console2.info(Messages.BUILD_START);
1115
+ console2.info();
905
1116
  try {
906
1117
  const directory = getDirectoryInput(options);
907
1118
  const config2 = await getConfig(options, directory);
1119
+ const watch3 = getWatchInput(options);
908
1120
  const client = getPart(
909
1121
  config2.client.build,
910
1122
  options.get("clientDirectory")?.value,
911
1123
  "client"
912
1124
  );
913
- let res = await buildPart("Client", client, directory);
1125
+ let res = await buildPart("Client", client, directory, { watch: watch3 });
914
1126
  if (config2.server.enable) {
915
1127
  const server = getPart(
916
1128
  config2.server.build,
917
1129
  options.get("serverDirectory")?.value,
918
1130
  "server"
919
1131
  );
920
- res = await buildPart("Server", server, directory) ? res : false;
1132
+ res = await buildPart("Server", server, directory, { watch: watch3 }) ? res : false;
921
1133
  }
922
- console.info();
923
- if (!res) console.info(Messages.BUILD_FAILED);
924
- else console.info(Messages.BUILD_SUCCESS);
925
- process3.exit(0);
1134
+ console2.info();
1135
+ if (watch3) {
1136
+ console2.info(Messages.BUILD_WATCH_START);
1137
+ console2.info();
1138
+ return;
1139
+ }
1140
+ if (!res) console2.info(Messages.BUILD_FAILED);
1141
+ else console2.info(Messages.BUILD_SUCCESS);
1142
+ process.exit(0);
926
1143
  } catch (e) {
927
- console.error(e);
928
- process3.exit(1);
1144
+ console2.error(e);
1145
+ process.exit(1);
929
1146
  }
930
1147
  }
931
1148
  };
@@ -936,26 +1153,76 @@ var getPart = /* @__PURE__ */ __name((config2, directoryOption, target) => {
936
1153
  target
937
1154
  };
938
1155
  }, "getPart");
939
- var buildPart = /* @__PURE__ */ __name(async (name, part, directory) => {
940
- const packageManagerName = "bun" /* BUN */;
1156
+ var buildPart = /* @__PURE__ */ __name(async (name, part, directory, options) => {
1157
+ const packageManagerName = "local_bun" /* LOCAL_BUN */;
1158
+ const packageManager = PackageManagerFactory.create(packageManagerName);
1159
+ const build = /* @__PURE__ */ __name(async (watch3 = false) => {
1160
+ try {
1161
+ return await packageManager.build(
1162
+ name,
1163
+ directory,
1164
+ part.entry,
1165
+ part.output,
1166
+ [
1167
+ "--asset-naming",
1168
+ "[name].[ext]",
1169
+ "--target",
1170
+ part.target === "client" ? "browser" : "node"
1171
+ ],
1172
+ watch3
1173
+ );
1174
+ } catch (error4) {
1175
+ if (error4 && error4.message) {
1176
+ console2.error(ansis.red(error4.message));
1177
+ }
1178
+ return false;
1179
+ }
1180
+ }, "build");
1181
+ if (options?.watch)
1182
+ watch(dirname(join3(getCwd(directory), part.entry))).on("change", () => build(true));
1183
+ return await build();
1184
+ }, "buildPart");
1185
+
1186
+ // src/action/actions/dev.action.ts
1187
+ import * as ansis2 from "ansis";
1188
+ var DevAction = class extends AbstractAction {
1189
+ static {
1190
+ __name(this, "DevAction");
1191
+ }
1192
+ async handle(_args, options) {
1193
+ console.info(Messages.DEV_START);
1194
+ console.info();
1195
+ try {
1196
+ const directory = getDirectoryInput(options);
1197
+ const generate = getDevGenerateInput(options);
1198
+ await Promise.all([
1199
+ generate ? runAction("generate", [], directory, false) : void 0,
1200
+ runAction("build", [], directory, false),
1201
+ runAction("start", [], directory, true)
1202
+ ]);
1203
+ console.info(Messages.DEV_SUCCESS);
1204
+ process.exit(0);
1205
+ } catch (e) {
1206
+ console.error(Messages.DEV_FAILED);
1207
+ console.error(e);
1208
+ process.exit(1);
1209
+ }
1210
+ }
1211
+ };
1212
+ var runAction = /* @__PURE__ */ __name(async (command, params, directory, stdout = false) => {
941
1213
  try {
942
- const packageManager = PackageManagerFactory.create(packageManagerName);
943
- return await packageManager.build(name, directory, part.entry, part.output, [
944
- "--asset-naming",
945
- "[name].[ext]",
946
- "--target",
947
- part.target === "client" ? "browser" : "node"
948
- ]);
949
- } catch (error3) {
950
- if (error3 && error3.message) {
951
- console.error(ansis.red(error3.message));
1214
+ const packageManager = await PackageManagerFactory.find(directory);
1215
+ await packageManager.runDev(directory, "nf", {}, [command, ...params, "--watch"], !stdout);
1216
+ } catch (error4) {
1217
+ if (error4 && error4.message) {
1218
+ console.error(ansis2.red(error4.message));
952
1219
  }
953
- return false;
954
1220
  }
955
- }, "buildPart");
1221
+ }, "runAction");
956
1222
 
957
1223
  // src/action/actions/generate.action.ts
958
- import * as console2 from "console";
1224
+ import * as console3 from "console";
1225
+ import { join as join4 } from "path";
959
1226
 
960
1227
  // src/lib/schematics/abstract.collection.ts
961
1228
  var AbstractCollection = class {
@@ -1045,7 +1312,7 @@ var CollectionFactory = class {
1045
1312
  __name(this, "CollectionFactory");
1046
1313
  }
1047
1314
  static create(collection, directory) {
1048
- const schematicRunner = RunnerFactory.create(1 /* SCHEMATIC */);
1315
+ const schematicRunner = RunnerFactory.create(4 /* SCHEMATIC */);
1049
1316
  if (collection === "@nanoforge-dev/schematics" /* NANOFORGE */) {
1050
1317
  return new NanoforgeCollection(schematicRunner, directory);
1051
1318
  } else {
@@ -1106,6 +1373,9 @@ var SchematicOption = class {
1106
1373
  }
1107
1374
  };
1108
1375
 
1376
+ // src/action/common/schematics.ts
1377
+ import { watch as watch2 } from "chokidar";
1378
+
1109
1379
  // src/action/common/spinner.ts
1110
1380
  import ora2 from "ora";
1111
1381
  var getSpinner = /* @__PURE__ */ __name((message) => ora2({
@@ -1113,16 +1383,22 @@ var getSpinner = /* @__PURE__ */ __name((message) => ora2({
1113
1383
  }), "getSpinner");
1114
1384
 
1115
1385
  // src/action/common/schematics.ts
1116
- var executeSchematic = /* @__PURE__ */ __name(async (name, collection, schematicName, options) => {
1117
- const spinner = getSpinner(Messages.SCHEMATIC_IN_PROGRESS(name));
1118
- spinner.start();
1119
- await collection.execute(
1120
- schematicName,
1121
- mapSchematicOptions(options),
1122
- void 0,
1123
- () => spinner.fail(Messages.SCHEMATIC_FAILED(name))
1124
- );
1125
- spinner.succeed(Messages.SCHEMATIC_SUCCESS(name));
1386
+ var executeSchematic = /* @__PURE__ */ __name(async (name, collection, schematicName, options, fileToWatch) => {
1387
+ const execute = /* @__PURE__ */ __name(async (watch3 = false) => {
1388
+ const spinner = getSpinner(
1389
+ (watch3 ? Messages.SCHEMATIC_WATCH_IN_PROGRESS : Messages.SCHEMATIC_IN_PROGRESS)(name)
1390
+ );
1391
+ spinner.start();
1392
+ await collection.execute(
1393
+ schematicName,
1394
+ mapSchematicOptions(options),
1395
+ void 0,
1396
+ () => spinner.fail(Messages.SCHEMATIC_FAILED(name))
1397
+ );
1398
+ spinner.succeed(Messages.SCHEMATIC_SUCCESS(name));
1399
+ }, "execute");
1400
+ if (fileToWatch) watch2(fileToWatch).on("change", () => execute(true));
1401
+ return await execute();
1126
1402
  }, "executeSchematic");
1127
1403
  var mapSchematicOptions = /* @__PURE__ */ __name((inputs) => {
1128
1404
  return Object.entries(inputs).reduce((old, [key, value]) => {
@@ -1140,18 +1416,25 @@ var GenerateAction = class extends AbstractAction {
1140
1416
  __name(this, "GenerateAction");
1141
1417
  }
1142
1418
  async handle(_args, options) {
1143
- console2.info(Messages.NEW_START);
1419
+ console3.info(Messages.GENERATE_START);
1420
+ console3.info();
1144
1421
  try {
1145
1422
  const directory = getDirectoryInput(options);
1146
1423
  const config2 = await getConfig(options, directory);
1424
+ const watch3 = getWatchInput(options);
1147
1425
  const values = await getSchemaValues(config2);
1148
- await generateFiles(values, directory);
1149
- console2.info();
1150
- console2.info(Messages.NEW_SUCCESS);
1426
+ await generateFiles(values, directory, watch3);
1427
+ console3.info();
1428
+ if (watch3) {
1429
+ console3.info(Messages.GENERATE_WATCH_START);
1430
+ console3.info();
1431
+ return;
1432
+ }
1433
+ console3.info(Messages.GENERATE_SUCCESS);
1151
1434
  process.exit(0);
1152
1435
  } catch (e) {
1153
- console2.error(Messages.NEW_FAILED);
1154
- console2.error(e);
1436
+ console3.error(Messages.GENERATE_FAILED);
1437
+ console3.error(e);
1155
1438
  process.exit(1);
1156
1439
  }
1157
1440
  }
@@ -1165,33 +1448,43 @@ var getSchemaValues = /* @__PURE__ */ __name(async (config2) => {
1165
1448
  initFunctions: config2.initFunctions
1166
1449
  };
1167
1450
  }, "getSchemaValues");
1168
- var generateFiles = /* @__PURE__ */ __name(async (values, directory) => {
1169
- console2.info();
1451
+ var generateFiles = /* @__PURE__ */ __name(async (values, directory, watch3) => {
1170
1452
  const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1171
- console2.info();
1172
- console2.info(Messages.SCHEMATICS_START);
1173
- console2.info();
1174
- await executeSchematic("Client main file", collection, "part-main", {
1175
- name: values.name,
1176
- part: "client",
1177
- directory: values.directory,
1178
- language: values.language,
1179
- initFunctions: values.initFunctions
1180
- });
1181
- if (values.server) {
1182
- await executeSchematic("Server main file", collection, "part-main", {
1453
+ console3.info(Messages.SCHEMATICS_START);
1454
+ console3.info();
1455
+ await executeSchematic(
1456
+ "Client main file",
1457
+ collection,
1458
+ "part-main",
1459
+ {
1183
1460
  name: values.name,
1184
- part: "server",
1461
+ part: "client",
1185
1462
  directory: values.directory,
1186
1463
  language: values.language,
1187
1464
  initFunctions: values.initFunctions
1188
- });
1465
+ },
1466
+ watch3 ? join4(getCwd(directory), values.directory, ".nanoforge", "client.save.json") : void 0
1467
+ );
1468
+ if (values.server) {
1469
+ await executeSchematic(
1470
+ "Server main file",
1471
+ collection,
1472
+ "part-main",
1473
+ {
1474
+ name: values.name,
1475
+ part: "server",
1476
+ directory: values.directory,
1477
+ language: values.language,
1478
+ initFunctions: values.initFunctions
1479
+ },
1480
+ join4(getCwd(directory), values.directory, ".nanoforge", "server.save.json")
1481
+ );
1189
1482
  }
1190
1483
  }, "generateFiles");
1191
1484
 
1192
1485
  // src/action/actions/install.action.ts
1193
- import * as ansis2 from "ansis";
1194
- import * as process4 from "process";
1486
+ import * as ansis3 from "ansis";
1487
+ import * as process3 from "process";
1195
1488
  var InstallAction = class extends AbstractAction {
1196
1489
  static {
1197
1490
  __name(this, "InstallAction");
@@ -1203,25 +1496,28 @@ var InstallAction = class extends AbstractAction {
1203
1496
  const names = await getInstallNamesInputOrAsk(args);
1204
1497
  const directory = getDirectoryInput(options);
1205
1498
  await installPackages(names, directory);
1206
- process4.exit(0);
1499
+ process3.exit(0);
1207
1500
  } catch (e) {
1208
1501
  console.error(e);
1209
- process4.exit(1);
1502
+ process3.exit(1);
1210
1503
  }
1211
1504
  }
1212
1505
  };
1213
1506
  var installPackages = /* @__PURE__ */ __name(async (names, directory) => {
1214
- const packageManagerName = "bun" /* BUN */;
1215
1507
  try {
1216
- const packageManager = PackageManagerFactory.create(packageManagerName);
1508
+ const packageManager = await PackageManagerFactory.find(directory);
1217
1509
  await packageManager.addProduction(directory, names);
1218
- } catch (error3) {
1219
- if (error3 && error3.message) {
1220
- console.error(ansis2.red(error3.message));
1510
+ } catch (error4) {
1511
+ if (error4 && error4.message) {
1512
+ console.error(ansis3.red(error4.message));
1221
1513
  }
1222
1514
  }
1223
1515
  }, "installPackages");
1224
1516
 
1517
+ // src/action/actions/new.action.ts
1518
+ import * as ansis4 from "ansis";
1519
+ import console4 from "console";
1520
+
1225
1521
  // src/lib/input/inputs/new/init-functions.input.ts
1226
1522
  var getNewInitFunctionsWithDefault = /* @__PURE__ */ __name((inputs) => {
1227
1523
  return getBooleanInputWithDefault(inputs, "initFunctions", false);
@@ -1315,16 +1611,17 @@ var NewAction = class extends AbstractAction {
1315
1611
  __name(this, "NewAction");
1316
1612
  }
1317
1613
  async handle(_args, options) {
1318
- console.info(Messages.NEW_START);
1614
+ console4.info(Messages.NEW_START);
1319
1615
  try {
1320
1616
  const directory = getDirectoryInput(options);
1321
1617
  const values = await getSchemaValues2(options);
1322
1618
  await generateApplicationFiles(values, directory);
1323
- console.info();
1324
- console.info(Messages.NEW_SUCCESS);
1619
+ if (!values.skipInstall) await runInstall(directory, values.packageManager);
1620
+ console4.info();
1621
+ console4.info(Messages.NEW_SUCCESS);
1325
1622
  process.exit(0);
1326
1623
  } catch {
1327
- console.error(Messages.NEW_FAILED);
1624
+ console4.error(Messages.NEW_FAILED);
1328
1625
  process.exit(1);
1329
1626
  }
1330
1627
  }
@@ -1342,11 +1639,11 @@ var getSchemaValues2 = /* @__PURE__ */ __name(async (inputs) => {
1342
1639
  };
1343
1640
  }, "getSchemaValues");
1344
1641
  var generateApplicationFiles = /* @__PURE__ */ __name(async (values, directory) => {
1345
- console.info();
1642
+ console4.info();
1346
1643
  const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1347
- console.info();
1348
- console.info(Messages.SCHEMATICS_START);
1349
- console.info();
1644
+ console4.info();
1645
+ console4.info(Messages.SCHEMATICS_START);
1646
+ console4.info();
1350
1647
  await executeSchematic("Application", collection, "application", {
1351
1648
  name: values.name,
1352
1649
  directory: values.directory,
@@ -1391,56 +1688,78 @@ var generateApplicationFiles = /* @__PURE__ */ __name(async (values, directory)
1391
1688
  });
1392
1689
  }
1393
1690
  }, "generateApplicationFiles");
1691
+ var runInstall = /* @__PURE__ */ __name(async (directory, pkgManagerName) => {
1692
+ try {
1693
+ const packageManager = PackageManagerFactory.create(pkgManagerName);
1694
+ await packageManager.install(directory);
1695
+ } catch (error4) {
1696
+ if (error4 && error4.message) {
1697
+ console4.error(ansis4.red(error4.message));
1698
+ }
1699
+ }
1700
+ }, "runInstall");
1394
1701
 
1395
1702
  // src/action/actions/start.action.ts
1396
- import * as ansis3 from "ansis";
1397
- import * as console3 from "console";
1398
- import { join as join4 } from "path";
1703
+ import * as ansis5 from "ansis";
1704
+ import * as console5 from "console";
1705
+ import { join as join5 } from "path";
1399
1706
  var StartAction = class extends AbstractAction {
1400
1707
  static {
1401
1708
  __name(this, "StartAction");
1402
1709
  }
1403
1710
  async handle(_args, options) {
1404
- console3.info(Messages.RUN_START);
1405
- console3.info();
1711
+ console5.info(Messages.RUN_START);
1712
+ console5.info();
1406
1713
  try {
1407
1714
  const directory = getDirectoryInput(options);
1408
1715
  const config2 = await getConfig(options, directory);
1409
1716
  const clientDir = config2.client.runtime.dir;
1410
1717
  const serverDir = config2.server.runtime.dir;
1411
1718
  const clientPort = getStringInputWithDefault(options, "clientPort", config2.client.port);
1719
+ const watch3 = getWatchInput(options);
1412
1720
  await Promise.all([
1413
- config2.server.enable ? this.startServer(directory, serverDir) : void 0,
1414
- this.startClient(clientPort, directory, clientDir)
1721
+ config2.server.enable ? this.startServer(directory, serverDir, watch3) : void 0,
1722
+ this.startClient(clientPort, directory, clientDir, {
1723
+ watch: watch3,
1724
+ serverGameDir: config2.server.enable ? serverDir : void 0
1725
+ })
1415
1726
  ]);
1416
1727
  process.exit(0);
1417
1728
  } catch (e) {
1418
- console3.error(e);
1729
+ console5.error(e);
1419
1730
  process.exit(1);
1420
1731
  }
1421
1732
  }
1422
- async startClient(port, directory, gameDir) {
1733
+ async startClient(port, directory, gameDir, options) {
1423
1734
  const path = getModulePath("@nanoforge-dev/loader-client/package.json", true);
1424
- return runPart("Client", path, {
1735
+ const params = {
1425
1736
  PORT: port,
1426
- GAME_DIR: getCwd(join4(directory, gameDir))
1427
- });
1737
+ GAME_DIR: getCwd(join5(directory, gameDir))
1738
+ };
1739
+ if (options?.watch) {
1740
+ params["WATCH"] = "true";
1741
+ if (options?.serverGameDir) {
1742
+ params["WATCH_SERVER_GAME_DIR"] = getCwd(join5(directory, options.serverGameDir));
1743
+ }
1744
+ }
1745
+ return runPart("Client", path, params);
1428
1746
  }
1429
- startServer(directory, gameDir) {
1747
+ startServer(directory, gameDir, watch3) {
1430
1748
  const path = getModulePath("@nanoforge-dev/loader-server/package.json", true);
1431
- return runPart("Server", path, {
1432
- GAME_DIR: getCwd(join4(directory, gameDir))
1433
- });
1749
+ const params = {
1750
+ GAME_DIR: getCwd(join5(directory, gameDir))
1751
+ };
1752
+ if (watch3) params["WATCH"] = "true";
1753
+ return runPart("Server", path, params);
1434
1754
  }
1435
1755
  };
1436
1756
  var runPart = /* @__PURE__ */ __name(async (part, directory, env2, flags) => {
1437
- const packageManagerName = "bun" /* BUN */;
1438
1757
  try {
1439
- const packageManager = PackageManagerFactory.create(packageManagerName);
1758
+ const packageManager = await PackageManagerFactory.find(directory);
1440
1759
  await packageManager.run(part, directory, "start", env2, flags, true);
1441
- } catch (error3) {
1442
- if (error3 && error3.message) {
1443
- console3.error(ansis3.red(error3.message));
1760
+ } catch (error4) {
1761
+ if (error4 && error4.message) {
1762
+ console5.error(ansis5.red(error4.message));
1444
1763
  }
1445
1764
  }
1446
1765
  }, "runPart");
@@ -1461,12 +1780,30 @@ var BuildCommand = class extends AbstractCommand {
1461
1780
  __name(this, "BuildCommand");
1462
1781
  }
1463
1782
  load(program2) {
1464
- program2.command("build").description("build your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--client-outDir [clientDirectory]", "specify the output directory of the client").option("--server-outDir [serverDirectory]", "specify the output directory of the server").action(async (rawOptions) => {
1783
+ program2.command("build").description("build your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--client-outDir [clientDirectory]", "specify the output directory of the client").option("--server-outDir [serverDirectory]", "specify the output directory of the server").option("--watch", "build app in watching mode", false).action(async (rawOptions) => {
1465
1784
  const options = /* @__PURE__ */ new Map();
1466
1785
  options.set("directory", { value: rawOptions.directory });
1467
1786
  options.set("config", { value: rawOptions.config });
1468
1787
  options.set("clientDirectory", { value: rawOptions.clientOutDir });
1469
1788
  options.set("serverDirectory", { value: rawOptions.serverOutDir });
1789
+ options.set("watch", { value: rawOptions.watch });
1790
+ const args = /* @__PURE__ */ new Map();
1791
+ await this.action.handle(args, options);
1792
+ });
1793
+ }
1794
+ };
1795
+
1796
+ // src/command/commands/dev.command.ts
1797
+ var DevCommand = class extends AbstractCommand {
1798
+ static {
1799
+ __name(this, "DevCommand");
1800
+ }
1801
+ load(program2) {
1802
+ program2.command("dev").description("run your game in dev mode").option("-d, --directory [directory]", "specify the directory of your project").option("--generate", "generate app from config", false).action(async (rawOptions) => {
1803
+ const options = /* @__PURE__ */ new Map();
1804
+ options.set("directory", { value: rawOptions.directory });
1805
+ options.set("config", { value: rawOptions.config });
1806
+ options.set("generate", { value: rawOptions.generate });
1470
1807
  const args = /* @__PURE__ */ new Map();
1471
1808
  await this.action.handle(args, options);
1472
1809
  });
@@ -1479,10 +1816,11 @@ var GenerateCommand = class extends AbstractCommand {
1479
1816
  __name(this, "GenerateCommand");
1480
1817
  }
1481
1818
  load(program2) {
1482
- program2.command("generate").description("generate nanoforge files from config").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").action(async (rawOptions) => {
1819
+ program2.command("generate").description("generate nanoforge files from config").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--watch", "generate app in watching mode", false).action(async (rawOptions) => {
1483
1820
  const options = /* @__PURE__ */ new Map();
1484
1821
  options.set("directory", { value: rawOptions.directory });
1485
1822
  options.set("config", { value: rawOptions.config });
1823
+ options.set("watch", { value: rawOptions.watch });
1486
1824
  const args = /* @__PURE__ */ new Map();
1487
1825
  await this.action.handle(args, options);
1488
1826
  });
@@ -1537,7 +1875,7 @@ var StartCommand = class extends AbstractCommand {
1537
1875
  program2.command("start").description("start your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option(
1538
1876
  "-p, --client-port [clientPort]",
1539
1877
  "specify the port of the loader (the website to load the game)"
1540
- ).option("--game-exposure-port [gameExposurePort]", "specify the port of the game exposure").option("--server-port [serverPort]", "specify the port of the server").action(async (rawOptions) => {
1878
+ ).option("--game-exposure-port [gameExposurePort]", "specify the port of the game exposure").option("--server-port [serverPort]", "specify the port of the server").option("--watch", "run app in watching mode", false).action(async (rawOptions) => {
1541
1879
  const options = /* @__PURE__ */ new Map();
1542
1880
  options.set("directory", { value: rawOptions.directory });
1543
1881
  options.set("config", { value: rawOptions.config });
@@ -1546,6 +1884,7 @@ var StartCommand = class extends AbstractCommand {
1546
1884
  value: rawOptions.gameExposurePort
1547
1885
  });
1548
1886
  options.set("serverPort", { value: rawOptions.serverPort });
1887
+ options.set("watch", { value: rawOptions.watch });
1549
1888
  const args = /* @__PURE__ */ new Map();
1550
1889
  await this.action.handle(args, options);
1551
1890
  });
@@ -1559,6 +1898,7 @@ var CommandLoader = class {
1559
1898
  }
1560
1899
  static async load(program2) {
1561
1900
  new BuildCommand(new BuildAction()).load(program2);
1901
+ new DevCommand(new DevAction()).load(program2);
1562
1902
  new GenerateCommand(new GenerateAction()).load(program2);
1563
1903
  new InstallCommand(new InstallAction()).load(program2);
1564
1904
  new NewCommand(new NewAction()).load(program2);
@@ -1568,8 +1908,8 @@ var CommandLoader = class {
1568
1908
  static handleInvalidCommand(program2) {
1569
1909
  program2.on("command:*", () => {
1570
1910
  console.error(`
1571
- ${Prefixes.ERROR} Invalid command: ${red6`%s`}`, program2.args.join(" "));
1572
- console.log(`See ${red6`--help`} for a list of available commands.
1911
+ ${Prefixes.ERROR} Invalid command: ${red8`%s`}`, program2.args.join(" "));
1912
+ console.log(`See ${red8`--help`} for a list of available commands.
1573
1913
  `);
1574
1914
  process.exit(1);
1575
1915
  });