@nanoforge-dev/cli 1.3.0 → 1.4.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.
@@ -11,10 +11,10 @@ var __decorateClass = (decorators, target, key, kind) => {
11
11
  };
12
12
 
13
13
  // src/command/command.loader.ts
14
- import { red as red6 } from "ansis";
14
+ import { red as red7 } from "ansis";
15
15
 
16
16
  // src/lib/ui/messages.ts
17
- import { green } from "ansis";
17
+ import { bold, green } from "ansis";
18
18
 
19
19
  // src/lib/ui/emojis.ts
20
20
  import { get } from "node-emoji";
@@ -49,8 +49,9 @@ var Messages = {
49
49
  BUILD_WATCH_START: "Watching for changes...",
50
50
  BUILD_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Building ${part}`, "BUILD_PART_IN_PROGRESS"),
51
51
  BUILD_PART_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((part) => `${part} updated, rebuilding`, "BUILD_PART_WATCH_IN_PROGRESS"),
52
+ BUILD_PART_SUCCESS: /* @__PURE__ */ __name((name) => success(`Build of ${name} succeeded!`), "BUILD_PART_SUCCESS"),
52
53
  BUILD_PART_FAILED: /* @__PURE__ */ __name((part, command) => failure(`Build of ${part} failed!
53
- Try running manually: ${command}`), "BUILD_PART_FAILED"),
54
+ Try running manually: ${bold(command)}`), "BUILD_PART_FAILED"),
54
55
  // --- Install ---
55
56
  INSTALL_START: "NanoForge Installation",
56
57
  INSTALL_SUCCESS: success("Installation completed!"),
@@ -70,6 +71,7 @@ Try running manually: ${command}`), "BUILD_PART_FAILED"),
70
71
  NEW_START: "NanoForge Project Creation",
71
72
  NEW_SUCCESS: success("Project successfully created!"),
72
73
  NEW_FAILED: failure("Project creation failed!"),
74
+ NEW_GENERATION_START: "Creating project...",
73
75
  NEW_NAME_QUESTION: "What is the name of your project?",
74
76
  NEW_PACKAGE_MANAGER_QUESTION: "Which package manager do you want to use?",
75
77
  NEW_LANGUAGE_QUESTION: "Which language do you want to use?",
@@ -77,6 +79,13 @@ Try running manually: ${command}`), "BUILD_PART_FAILED"),
77
79
  NEW_SERVER_QUESTION: "Do you want to generate a server for multiplayer?",
78
80
  NEW_SKIP_INSTALL_QUESTION: "Do you want to skip dependency installation?",
79
81
  NEW_DOCKER_QUESTION: "Do you want to add a Dockerfile for containerization?",
82
+ NEW_GIT_QUESTION: "Do you want to create a git repository?",
83
+ NEW_GIT_REMOTE_QUESTION: "Do you want to setup a git remote? (leave empty if you don't want to)",
84
+ // --- Create ---
85
+ CREATE_START: "NanoForge Component/System Creation",
86
+ CREATE_SUCCESS: success("Element successfully created!"),
87
+ CREATE_FAILED: failure("Creation failed!"),
88
+ CREATE_NAME_QUESTION: "What is the name of your component/system?",
80
89
  // --- Generate ---
81
90
  GENERATE_START: "NanoForge Generate",
82
91
  GENERATE_SUCCESS: success("Generation succeeded!"),
@@ -93,6 +102,9 @@ Try running manually: ${command}`), "BUILD_PART_FAILED"),
93
102
  START_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Starting ${part}...`, "START_PART_IN_PROGRESS"),
94
103
  START_PART_SUCCESS: /* @__PURE__ */ __name((part) => success(`${part} terminated.`), "START_PART_SUCCESS"),
95
104
  START_PART_FAILED: /* @__PURE__ */ __name((part) => failure(`${part} failed!`), "START_PART_FAILED"),
105
+ EDITOR_START: "NanoForge Editor",
106
+ EDITOR_SUCCESS: "Editor ended",
107
+ EDITOR_FAILED: failure("Editor failed!"),
96
108
  // --- Publish ---
97
109
  PUBLISH_START: "NanoForge Publish",
98
110
  PUBLISH_SUCCESS: success("Publish completed!"),
@@ -104,7 +116,6 @@ Try running manually: ${command}`), "BUILD_PART_FAILED"),
104
116
  UNPUBLISH_FAILED: failure("Unpublish failed!"),
105
117
  UNPUBLISH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Unpublishing ${name}...`, "UNPUBLISH_IN_PROGRESS"),
106
118
  // --- Schematics ---
107
- SCHEMATICS_START: "Running schematics",
108
119
  SCHEMATIC_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Generating ${name}...`, "SCHEMATIC_IN_PROGRESS"),
109
120
  SCHEMATIC_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Change detected, regenerating ${name}...`, "SCHEMATIC_WATCH_IN_PROGRESS"),
110
121
  SCHEMATIC_SUCCESS: /* @__PURE__ */ __name((name) => success(`${name} generated successfully!`), "SCHEMATIC_SUCCESS"),
@@ -114,10 +125,20 @@ Try running manually: ${command}`), "BUILD_PART_FAILED"),
114
125
  PACKAGE_MANAGER_INSTALLATION_NOTHING: "Nothing to install.",
115
126
  PACKAGE_MANAGER_INSTALLATION_SUCCEED: /* @__PURE__ */ __name((names) => names ? success(`Packages installed: ${names.map((n) => green(n)).join(", ")}`) : success("Packages installed!"), "PACKAGE_MANAGER_INSTALLATION_SUCCEED"),
116
127
  PACKAGE_MANAGER_INSTALLATION_FAILED: /* @__PURE__ */ __name((command) => failure(`Package installation failed!
117
- Try running manually: ${command}`), "PACKAGE_MANAGER_INSTALLATION_FAILED"),
128
+ Try running manually: ${bold(command)}`), "PACKAGE_MANAGER_INSTALLATION_FAILED"),
129
+ // --- Git init ---
130
+ GIT_INIT_IN_PROGRESS: `Initializing git repository... ${Emojis.COFFEE}`,
131
+ GIT_INIT_SUCCEED: success("Git repository initialized!"),
132
+ GIT_INIT_FAILED: /* @__PURE__ */ __name((command) => failure(`Git repository initialization failed!
133
+ Try running manually: ${bold(command)}`), "GIT_INIT_FAILED"),
134
+ // --- Git remote ---
135
+ GIT_REMOTE_IN_PROGRESS: `Adding git remote... ${Emojis.COFFEE}`,
136
+ GIT_REMOTE_SUCCEED: success("Git remote added!"),
137
+ GIT_REMOTE_FAILED: /* @__PURE__ */ __name((command) => failure(`Git remote addition failed!
138
+ Try running manually: ${bold(command)}`), "GIT_REMOTE_FAILED"),
118
139
  // --- Runner ---
119
140
  RUNNER_EXECUTION_ERROR: /* @__PURE__ */ __name((command) => `
120
- Failed to execute command: ${command}`, "RUNNER_EXECUTION_ERROR")
141
+ Failed to execute command: ${bold(command)}`, "RUNNER_EXECUTION_ERROR")
121
142
  };
122
143
 
123
144
  // src/lib/ui/prefixes.ts
@@ -133,7 +154,7 @@ var getSpinner = /* @__PURE__ */ __name((message) => ora({ text: message }), "ge
133
154
 
134
155
  // src/action/actions/build.action.ts
135
156
  import { watch } from "chokidar";
136
- import { dirname, join as join3 } from "path";
157
+ import { dirname, join as join4 } from "path";
137
158
 
138
159
  // src/lib/input/base-inputs.ts
139
160
  var getStringInput = /* @__PURE__ */ __name((input2, field) => {
@@ -182,21 +203,10 @@ var getConfigInput = /* @__PURE__ */ __name((inputs) => {
182
203
  return getStringInputWithDefault(inputs, "config", ".");
183
204
  }, "getConfigInput");
184
205
 
185
- // src/lib/input/inputs/watch.input.ts
186
- var getWatchInput = /* @__PURE__ */ __name((inputs) => {
187
- return getBooleanInputWithDefault(inputs, "watch", false);
188
- }, "getWatchInput");
189
-
190
- // src/lib/input/inputs/dev/generate.input.ts
191
- var getDevGenerateInput = /* @__PURE__ */ __name((inputs) => {
192
- return getBooleanInputWithDefault(inputs, "generate", false);
193
- }, "getDevGenerateInput");
194
-
195
- // src/lib/input/inputs/install/lib.input.ts
196
- function getInstallLibInput(inputs) {
197
- return getBooleanInputWithDefault(inputs, "lib", false);
198
- }
199
- __name(getInstallLibInput, "getInstallLibInput");
206
+ // src/lib/input/inputs/editor.input.ts
207
+ var getEditorInput = /* @__PURE__ */ __name((inputs) => {
208
+ return getBooleanInputWithDefault(inputs, "editor", false);
209
+ }, "getEditorInput");
200
210
 
201
211
  // src/lib/question/questions/confirm.question.ts
202
212
  import { confirm } from "@inquirer/prompts";
@@ -286,6 +296,71 @@ var askSelect = /* @__PURE__ */ __name(async (question, choices, baseOptions) =>
286
296
  }).catch(promptError);
287
297
  }, "askSelect");
288
298
 
299
+ // src/lib/input/inputs/name.input.ts
300
+ var getNameInput = /* @__PURE__ */ __name((inputs) => {
301
+ return getStringInput(inputs, "name");
302
+ }, "getNameInput");
303
+ var getNewNameInputOrAsk = /* @__PURE__ */ __name((inputs) => {
304
+ return getInputOrAsk(
305
+ getNameInput(inputs),
306
+ () => askInput(Messages.NEW_NAME_QUESTION, {
307
+ required: true,
308
+ default: "nanoforge-app"
309
+ })
310
+ );
311
+ }, "getNewNameInputOrAsk");
312
+ var getCreateNameInputOrAsk = /* @__PURE__ */ __name((inputs) => {
313
+ return getInputOrAsk(
314
+ getNameInput(inputs),
315
+ () => askInput(Messages.CREATE_NAME_QUESTION, {
316
+ required: true,
317
+ default: "example"
318
+ })
319
+ );
320
+ }, "getCreateNameInputOrAsk");
321
+
322
+ // src/lib/input/inputs/path.input.ts
323
+ var getPathInput = /* @__PURE__ */ __name((inputs) => {
324
+ return getStringInput(inputs, "path");
325
+ }, "getPathInput");
326
+ var getPathInputWithDefault = /* @__PURE__ */ __name((inputs, defaultValue) => {
327
+ return getStringInputWithDefault(inputs, "path", defaultValue);
328
+ }, "getPathInputWithDefault");
329
+
330
+ // src/lib/input/inputs/server.input.ts
331
+ function getServerInput(inputs) {
332
+ return getBooleanInputWithDefault(inputs, "server", false);
333
+ }
334
+ __name(getServerInput, "getServerInput");
335
+
336
+ // src/lib/input/inputs/watch.input.ts
337
+ var getWatchInput = /* @__PURE__ */ __name((inputs) => {
338
+ return getBooleanInputWithDefault(inputs, "watch", false);
339
+ }, "getWatchInput");
340
+
341
+ // src/lib/input/inputs/create/type.input.ts
342
+ var getCreateTypeInput = /* @__PURE__ */ __name((inputs) => {
343
+ const res = getStringInput(inputs, "type");
344
+ if (res && ["component", "system"].includes(res)) return res;
345
+ throw new Error("Invalid type. Please enter 'component' or 'system'.");
346
+ }, "getCreateTypeInput");
347
+
348
+ // src/lib/input/inputs/dev/generate.input.ts
349
+ var getDevGenerateInput = /* @__PURE__ */ __name((inputs) => {
350
+ return getBooleanInputWithDefault(inputs, "generate", false);
351
+ }, "getDevGenerateInput");
352
+
353
+ // src/lib/input/inputs/editor/open.input.ts
354
+ var getEditorOpenInput = /* @__PURE__ */ __name((inputs, defaultValue) => {
355
+ return getBooleanInputWithDefault(inputs, "open", defaultValue);
356
+ }, "getEditorOpenInput");
357
+
358
+ // src/lib/input/inputs/install/lib.input.ts
359
+ function getInstallLibInput(inputs) {
360
+ return getBooleanInputWithDefault(inputs, "lib", false);
361
+ }
362
+ __name(getInstallLibInput, "getInstallLibInput");
363
+
289
364
  // src/lib/input/inputs/install/names.input.ts
290
365
  var getNamesInput = /* @__PURE__ */ __name((inputs) => {
291
366
  return getArrayInput(inputs, "names");
@@ -297,12 +372,6 @@ var getInstallNamesInputOrAsk = /* @__PURE__ */ __name((inputs) => {
297
372
  );
298
373
  }, "getInstallNamesInputOrAsk");
299
374
 
300
- // src/lib/input/inputs/install/server.input.ts
301
- function getInstallServerInput(inputs) {
302
- return getBooleanInputWithDefault(inputs, "server", false);
303
- }
304
- __name(getInstallServerInput, "getInstallServerInput");
305
-
306
375
  // src/lib/input/inputs/login-out/api-key.input.ts
307
376
  var getApiKeyInput = /* @__PURE__ */ __name((inputs) => {
308
377
  return getStringInput(inputs, "apiKey");
@@ -356,20 +425,6 @@ var getNewLintInput = /* @__PURE__ */ __name((inputs) => {
356
425
  return getBooleanInputWithDefault(inputs, "lint", true);
357
426
  }, "getNewLintInput");
358
427
 
359
- // src/lib/input/inputs/new/name.input.ts
360
- var getNameInput = /* @__PURE__ */ __name((inputs) => {
361
- return getStringInput(inputs, "name");
362
- }, "getNameInput");
363
- var getNewNameInputOrAsk = /* @__PURE__ */ __name((inputs) => {
364
- return getInputOrAsk(
365
- getNameInput(inputs),
366
- () => askInput(Messages.NEW_NAME_QUESTION, {
367
- required: true,
368
- default: "nanoforge-app"
369
- })
370
- );
371
- }, "getNewNameInputOrAsk");
372
-
373
428
  // src/lib/input/inputs/new/package-manager.input.ts
374
429
  var getPackageManagerInput = /* @__PURE__ */ __name((inputs) => {
375
430
  return getStringInput(inputs, "packageManager");
@@ -387,11 +442,6 @@ var getNewPackageManagerInputOrAsk = /* @__PURE__ */ __name((inputs) => {
387
442
  );
388
443
  }, "getNewPackageManagerInputOrAsk");
389
444
 
390
- // src/lib/input/inputs/new/path.input.ts
391
- var getNewPathInput = /* @__PURE__ */ __name((inputs) => {
392
- return getStringInput(inputs, "path");
393
- }, "getNewPathInput");
394
-
395
445
  // src/lib/input/inputs/new/server.input.ts
396
446
  var getNewServerInput = /* @__PURE__ */ __name((inputs) => {
397
447
  return getBooleanInput(inputs, "server");
@@ -426,7 +476,7 @@ var getNewStrictOrAsk = /* @__PURE__ */ __name((inputs) => {
426
476
  }, "getNewStrictOrAsk");
427
477
 
428
478
  // src/lib/package-manager/package-manager.ts
429
- import { bold, red as red3 } from "ansis";
479
+ import { red as red4 } from "ansis";
430
480
 
431
481
  // src/lib/runner/process-logger.ts
432
482
  import { green as green2, red as red2, yellow } from "ansis";
@@ -473,15 +523,16 @@ var resolveCLINodeBinaryPath = /* @__PURE__ */ __name((name) => {
473
523
  }, "resolveCLINodeBinaryPath");
474
524
 
475
525
  // src/lib/utils/spinner.ts
476
- var withSpinner = /* @__PURE__ */ __name(async (message, task, onError) => {
477
- const spinner = getSpinner(message);
526
+ import { red as red3 } from "ansis";
527
+ var withSpinner = /* @__PURE__ */ __name(async (task, loadingMessage, successMessage, failureMessage, onError) => {
528
+ const spinner = getSpinner(loadingMessage);
478
529
  spinner.start();
479
530
  try {
480
531
  const value = await task(spinner);
481
- spinner.succeed();
532
+ spinner.succeed(successMessage);
482
533
  return { success: true, value };
483
534
  } catch (error) {
484
- spinner.fail();
535
+ spinner.fail(red3(failureMessage));
485
536
  if (onError) onError();
486
537
  return { success: false, error };
487
538
  }
@@ -494,18 +545,19 @@ var PackageManager = class {
494
545
  this.commands = commands;
495
546
  this.runner = runner;
496
547
  }
548
+ name;
549
+ commands;
550
+ runner;
497
551
  static {
498
552
  __name(this, "PackageManager");
499
553
  }
500
554
  async install(directory) {
501
555
  const args = [this.commands.install, this.commands.silentFlag];
502
556
  const result = await withSpinner(
557
+ () => this.exec(args, directory),
503
558
  Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS,
504
- async (spinner) => {
505
- await this.exec(args, directory, { onFail: /* @__PURE__ */ __name(() => spinner.fail(), "onFail") });
506
- this.logSuccess(Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED());
507
- },
508
- () => this.logFailure(this.formatFailCommand([this.commands.install]))
559
+ Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED(),
560
+ Messages.PACKAGE_MANAGER_INSTALLATION_FAILED(this.formatFailCommand([this.commands.install]))
509
561
  );
510
562
  return result.success;
511
563
  }
@@ -528,11 +580,10 @@ var PackageManager = class {
528
580
  ...flags
529
581
  ];
530
582
  const result = await withSpinner(
583
+ () => this.exec(args, directory),
531
584
  message,
532
- async (spinner) => {
533
- await this.exec(args, directory, { onFail: /* @__PURE__ */ __name(() => spinner.fail(), "onFail") });
534
- },
535
- () => this.logBuildFailure(name)
585
+ Messages.BUILD_PART_SUCCESS(name),
586
+ Messages.BUILD_PART_FAILED(name, this.formatFailCommand(args))
536
587
  );
537
588
  return result.success;
538
589
  }
@@ -550,7 +601,25 @@ var PackageManager = class {
550
601
  console.info(Messages.START_PART_SUCCESS(name));
551
602
  return true;
552
603
  } catch {
553
- console.error(red3(Messages.START_PART_FAILED(name)));
604
+ console.error(red4(Messages.START_PART_FAILED(name)));
605
+ return false;
606
+ }
607
+ }
608
+ async runFile(name, directory, script, params, env2 = {}, flags = [], silent = false) {
609
+ console.info(Messages.START_PART_IN_PROGRESS(name));
610
+ try {
611
+ const args = this.buildRunFileArgs(script, params, flags, silent);
612
+ await this.exec(args, directory, {
613
+ env: env2,
614
+ listeners: {
615
+ onStdout: createStdoutLogger(name),
616
+ onStderr: createStderrLogger(name)
617
+ }
618
+ });
619
+ console.info(Messages.START_PART_SUCCESS(name));
620
+ return true;
621
+ } catch {
622
+ console.error(red4(Messages.START_PART_FAILED(name)));
554
623
  return false;
555
624
  }
556
625
  }
@@ -571,12 +640,10 @@ var PackageManager = class {
571
640
  }
572
641
  const args = [this.commands.add, saveFlag, ...dependencies];
573
642
  const result = await withSpinner(
643
+ () => this.exec(args, directory),
574
644
  Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS,
575
- async (spinner) => {
576
- await this.exec(args, directory, { onFail: /* @__PURE__ */ __name(() => spinner.fail(), "onFail") });
577
- this.logSuccess(Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED(dependencies));
578
- },
579
- () => this.logFailure(this.formatFailCommand(args))
645
+ Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED(),
646
+ Messages.PACKAGE_MANAGER_INSTALLATION_FAILED(this.formatFailCommand(args))
580
647
  );
581
648
  return result.success;
582
649
  }
@@ -593,6 +660,15 @@ var PackageManager = class {
593
660
  if (this.commands.runArgsFlag) args.push(this.commands.runArgsFlag);
594
661
  return args.concat(params);
595
662
  }
663
+ buildRunFileArgs(script, params, flags, silent) {
664
+ if (!this.commands.runFile) throw new Error("Package manager does not support runFile");
665
+ const args = [...flags, this.commands.runFile];
666
+ if (silent) args.push(this.commands.silentFlag);
667
+ args.push(script);
668
+ if (params.length === 0) return args;
669
+ if (this.commands.runArgsFlag) args.push(this.commands.runArgsFlag);
670
+ return args.concat(params);
671
+ }
596
672
  exec(args, directory, options = {}) {
597
673
  return this.runner.run(args, {
598
674
  collect: options.collect ?? true,
@@ -605,18 +681,6 @@ var PackageManager = class {
605
681
  formatFailCommand(args) {
606
682
  return this.runner.fullCommand(args);
607
683
  }
608
- logSuccess(message) {
609
- console.info();
610
- console.info(message);
611
- console.info();
612
- }
613
- logFailure(command) {
614
- console.error(red3(Messages.PACKAGE_MANAGER_INSTALLATION_FAILED(bold(command))));
615
- }
616
- logBuildFailure(name) {
617
- const command = this.formatFailCommand([this.commands.install]);
618
- console.error(red3(Messages.BUILD_PART_FAILED(name, bold(command))));
619
- }
620
684
  logEmpty(message) {
621
685
  console.info();
622
686
  console.info(message);
@@ -629,7 +693,7 @@ import fs2 from "fs";
629
693
  import { resolve as resolve2 } from "path";
630
694
 
631
695
  // src/lib/runner/runner.ts
632
- import { red as red4 } from "ansis";
696
+ import { red as red5 } from "ansis";
633
697
  import { spawn } from "child_process";
634
698
  import * as process2 from "process";
635
699
  var Runner = class {
@@ -637,6 +701,8 @@ var Runner = class {
637
701
  this.binary = binary;
638
702
  this.baseArgs = baseArgs;
639
703
  }
704
+ binary;
705
+ baseArgs;
640
706
  static {
641
707
  __name(this, "Runner");
642
708
  }
@@ -684,7 +750,7 @@ var Runner = class {
684
750
  this.logCapturedOutput(output);
685
751
  }
686
752
  logFailedCommand(args) {
687
- console.error(red4(`
753
+ console.error(red5(`
688
754
  Failed to execute command: ${this.binary} ${args.join(" ")}`));
689
755
  }
690
756
  logCapturedOutput(output) {
@@ -841,14 +907,29 @@ var PackageManagerFactory = class {
841
907
  }
842
908
  };
843
909
 
910
+ // src/lib/utils/files.ts
911
+ import fs3 from "fs";
912
+ import { join as join2 } from "path";
913
+ var copyFiles = /* @__PURE__ */ __name((from, to) => {
914
+ if (!fs3.existsSync(from)) return;
915
+ if (!fs3.existsSync(to)) throw new Error(`Directory ${to} does not exist`);
916
+ fs3.readdirSync(from, { recursive: true }).forEach((file) => {
917
+ fs3.copyFileSync(join2(from, file.toString()), join2(to, file.toString()));
918
+ });
919
+ }, "copyFiles");
920
+ var resetFolder = /* @__PURE__ */ __name((folder) => {
921
+ if (fs3.existsSync(folder)) fs3.rmSync(folder, { recursive: true, force: true });
922
+ fs3.mkdirSync(folder, { recursive: true });
923
+ }, "resetFolder");
924
+
844
925
  // src/lib/utils/run-safe.ts
845
- import { red as red5 } from "ansis";
926
+ import { red as red6 } from "ansis";
846
927
  var runSafe = /* @__PURE__ */ __name(async (fn, fallback) => {
847
928
  try {
848
929
  return await fn();
849
930
  } catch (error) {
850
931
  const msg = getErrorMessage(error);
851
- if (msg) console.error(red5(msg));
932
+ if (msg) console.error(red6(msg));
852
933
  return fallback;
853
934
  }
854
935
  }, "runSafe");
@@ -860,42 +941,77 @@ var BuildConfig = class {
860
941
  static {
861
942
  __name(this, "BuildConfig");
862
943
  }
863
- entryFile;
864
- outDir;
944
+ entry;
945
+ staticDir;
946
+ };
947
+ __decorateClass([
948
+ Expose(),
949
+ IsString(),
950
+ IsNotEmpty()
951
+ ], BuildConfig.prototype, "entry", 2);
952
+ __decorateClass([
953
+ Expose(),
954
+ IsString(),
955
+ IsNotEmpty()
956
+ ], BuildConfig.prototype, "staticDir", 2);
957
+ var EditorConfig = class {
958
+ static {
959
+ __name(this, "EditorConfig");
960
+ }
961
+ entry;
962
+ save;
865
963
  };
866
964
  __decorateClass([
867
965
  Expose(),
868
966
  IsString(),
869
967
  IsNotEmpty()
870
- ], BuildConfig.prototype, "entryFile", 2);
968
+ ], EditorConfig.prototype, "entry", 2);
871
969
  __decorateClass([
872
970
  Expose(),
873
971
  IsString(),
874
972
  IsNotEmpty()
875
- ], BuildConfig.prototype, "outDir", 2);
876
- var RunConfig = class {
973
+ ], EditorConfig.prototype, "save", 2);
974
+ var DirsConfig = class {
877
975
  static {
878
- __name(this, "RunConfig");
976
+ __name(this, "DirsConfig");
879
977
  }
880
- dir;
978
+ components;
979
+ systems;
881
980
  };
882
981
  __decorateClass([
883
982
  Expose(),
884
983
  IsString(),
885
984
  IsNotEmpty()
886
- ], RunConfig.prototype, "dir", 2);
985
+ ], DirsConfig.prototype, "components", 2);
986
+ __decorateClass([
987
+ Expose(),
988
+ IsString(),
989
+ IsNotEmpty()
990
+ ], DirsConfig.prototype, "systems", 2);
887
991
  var ClientConfig = class {
888
992
  static {
889
993
  __name(this, "ClientConfig");
890
994
  }
995
+ enable;
891
996
  port;
997
+ outDir;
892
998
  build;
893
- runtime;
999
+ editor;
1000
+ dirs;
894
1001
  };
1002
+ __decorateClass([
1003
+ Expose(),
1004
+ IsBoolean()
1005
+ ], ClientConfig.prototype, "enable", 2);
895
1006
  __decorateClass([
896
1007
  Expose(),
897
1008
  IsPort()
898
1009
  ], ClientConfig.prototype, "port", 2);
1010
+ __decorateClass([
1011
+ Expose(),
1012
+ IsString(),
1013
+ IsNotEmpty()
1014
+ ], ClientConfig.prototype, "outDir", 2);
899
1015
  __decorateClass([
900
1016
  Expose(),
901
1017
  Type(() => BuildConfig),
@@ -903,21 +1019,33 @@ __decorateClass([
903
1019
  ], ClientConfig.prototype, "build", 2);
904
1020
  __decorateClass([
905
1021
  Expose(),
906
- Type(() => RunConfig),
1022
+ Type(() => EditorConfig),
1023
+ ValidateNested()
1024
+ ], ClientConfig.prototype, "editor", 2);
1025
+ __decorateClass([
1026
+ Expose(),
1027
+ Type(() => DirsConfig),
907
1028
  ValidateNested()
908
- ], ClientConfig.prototype, "runtime", 2);
1029
+ ], ClientConfig.prototype, "dirs", 2);
909
1030
  var ServerConfig = class {
910
1031
  static {
911
1032
  __name(this, "ServerConfig");
912
1033
  }
913
1034
  enable;
1035
+ outDir;
914
1036
  build;
915
- runtime;
1037
+ editor;
1038
+ dirs;
916
1039
  };
917
1040
  __decorateClass([
918
1041
  Expose(),
919
1042
  IsBoolean()
920
1043
  ], ServerConfig.prototype, "enable", 2);
1044
+ __decorateClass([
1045
+ Expose(),
1046
+ IsString(),
1047
+ IsNotEmpty()
1048
+ ], ServerConfig.prototype, "outDir", 2);
921
1049
  __decorateClass([
922
1050
  Expose(),
923
1051
  Type(() => BuildConfig),
@@ -925,9 +1053,14 @@ __decorateClass([
925
1053
  ], ServerConfig.prototype, "build", 2);
926
1054
  __decorateClass([
927
1055
  Expose(),
928
- Type(() => RunConfig),
1056
+ Type(() => EditorConfig),
1057
+ ValidateNested()
1058
+ ], ServerConfig.prototype, "editor", 2);
1059
+ __decorateClass([
1060
+ Expose(),
1061
+ Type(() => DirsConfig),
929
1062
  ValidateNested()
930
- ], ServerConfig.prototype, "runtime", 2);
1063
+ ], ServerConfig.prototype, "dirs", 2);
931
1064
  var Config = class {
932
1065
  static {
933
1066
  __name(this, "Config");
@@ -966,13 +1099,12 @@ __decorateClass([
966
1099
  import { plainToInstance } from "class-transformer";
967
1100
  import { validate } from "class-validator";
968
1101
  import { existsSync, readFileSync } from "fs";
969
- import { join as join2 } from "path";
1102
+ import { join as join3 } from "path";
970
1103
 
971
1104
  // src/lib/constants.ts
972
1105
  var CONFIG_FILE_NAME = "nanoforge.config.json";
973
1106
  var MANIFEST_FILE_NAME = "nanoforge.manifest.json";
974
1107
  var GLOBAL_CONFIG_FILE_NAME = ".nanoforgerc";
975
- var NANOFORGE_DIR = ".nanoforge";
976
1108
  var REGISTRY_URL = "https://api.nanoforge.dev";
977
1109
 
978
1110
  // src/lib/utils/object.ts
@@ -1002,23 +1134,36 @@ var CONFIG_DEFAULTS = {
1002
1134
  language: "ts",
1003
1135
  initFunctions: true,
1004
1136
  client: {
1137
+ enable: true,
1005
1138
  port: "3000",
1139
+ outDir: ".nanoforge/client",
1006
1140
  build: {
1007
- entryFile: "client/main.ts",
1008
- outDir: ".nanoforge/client"
1141
+ entry: "client/main.ts",
1142
+ staticDir: "client/static"
1143
+ },
1144
+ editor: {
1145
+ entry: ".nanoforge/editor/client/main.ts",
1146
+ save: ".nanoforge/client.save.json"
1009
1147
  },
1010
- runtime: {
1011
- dir: ".nanoforge/client"
1148
+ dirs: {
1149
+ components: "client/components",
1150
+ systems: "client/systems"
1012
1151
  }
1013
1152
  },
1014
1153
  server: {
1015
1154
  enable: false,
1155
+ outDir: ".nanoforge/server",
1016
1156
  build: {
1017
- entryFile: "server/main.ts",
1018
- outDir: ".nanoforge/server"
1157
+ entry: "server/main.ts",
1158
+ staticDir: "server/static"
1019
1159
  },
1020
- runtime: {
1021
- dir: ".nanoforge/server"
1160
+ editor: {
1161
+ entry: ".nanoforge/editor/server/main.ts",
1162
+ save: ".nanoforge/server.save.json"
1163
+ },
1164
+ dirs: {
1165
+ components: "server/components",
1166
+ systems: "server/systems"
1022
1167
  }
1023
1168
  }
1024
1169
  };
@@ -1027,23 +1172,23 @@ var CONFIG_DEFAULTS = {
1027
1172
  var config;
1028
1173
  var getConfigPath = /* @__PURE__ */ __name((directory, name) => {
1029
1174
  if (name) {
1030
- return join2(directory, name);
1175
+ return join3(directory, name);
1031
1176
  } else {
1032
1177
  for (const n of [CONFIG_FILE_NAME]) {
1033
- const path = join2(directory, n);
1178
+ const path = join3(directory, n);
1034
1179
  if (existsSync(path)) return path;
1035
1180
  }
1036
1181
  throw new Error(`No config file found in directory: ${directory}`);
1037
1182
  }
1038
1183
  }, "getConfigPath");
1039
- var loadConfig = /* @__PURE__ */ __name(async (directory, name) => {
1184
+ var loadConfig = /* @__PURE__ */ __name(async (directory, name, noThrow = false) => {
1040
1185
  if (config) return config;
1041
1186
  let rawData;
1042
1187
  const path = getConfigPath(directory, name);
1043
1188
  try {
1044
1189
  rawData = deepMerge(CONFIG_DEFAULTS, JSON.parse(readFileSync(path, "utf-8")));
1045
1190
  } catch {
1046
- rawData = null;
1191
+ rawData = noThrow ? CONFIG_DEFAULTS : null;
1047
1192
  }
1048
1193
  if (!rawData) throw new Error(`Not able to read config file : ${path}`);
1049
1194
  const data = plainToInstance(Config, rawData, {
@@ -1058,8 +1203,8 @@ ${errors.toString().replace(/,/g, "\n")}`);
1058
1203
  }, "loadConfig");
1059
1204
 
1060
1205
  // src/action/common/config.ts
1061
- var getConfig = /* @__PURE__ */ __name((inputs, dir) => {
1062
- return loadConfig(dir, getConfigInput(inputs));
1206
+ var getConfig = /* @__PURE__ */ __name((inputs, dir, noThrow) => {
1207
+ return loadConfig(dir, getConfigInput(inputs), noThrow);
1063
1208
  }, "getConfig");
1064
1209
 
1065
1210
  // src/action/abstract.action.ts
@@ -1106,40 +1251,53 @@ var BuildAction = class extends AbstractAction {
1106
1251
  async handle(_args, options) {
1107
1252
  const directory = getDirectoryInput(options);
1108
1253
  const config2 = await getConfig(options, directory);
1254
+ const isEditor = getEditorInput(options);
1109
1255
  const isWatch = getWatchInput(options);
1110
- const targets = this.resolveTargets(config2, options);
1256
+ const targets = this.resolveTargets(config2, options, isEditor);
1111
1257
  const results = await this.buildAll(targets, directory, isWatch);
1112
1258
  if (isWatch) {
1113
1259
  return this.enterWatchMode();
1114
1260
  }
1115
1261
  return { success: results.every(Boolean) };
1116
1262
  }
1117
- resolveTargets(config2, options) {
1118
- const targets = [
1119
- this.createTarget(
1120
- "Client",
1121
- config2.client.build,
1122
- "browser",
1123
- getStringInput(options, "clientDirectory")
1124
- )
1125
- ];
1126
- if (config2.server.enable) {
1263
+ resolveTargets(config2, options, isEditor) {
1264
+ const targets = [];
1265
+ if (config2.client.enable)
1266
+ targets.push(
1267
+ this.createTarget(
1268
+ "Client",
1269
+ "browser",
1270
+ getStringInputWithDefault(
1271
+ options,
1272
+ "clientEntry",
1273
+ !isEditor ? config2.client.build.entry : config2.client.editor.entry
1274
+ ),
1275
+ getStringInputWithDefault(options, "clientStaticDir", config2.client.build.staticDir),
1276
+ getStringInputWithDefault(options, "clientOutDir", config2.client.outDir)
1277
+ )
1278
+ );
1279
+ if (config2.server.enable)
1127
1280
  targets.push(
1128
1281
  this.createTarget(
1129
1282
  "Server",
1130
- config2.server.build,
1131
1283
  "node",
1132
- getStringInput(options, "serverDirectory")
1284
+ getStringInputWithDefault(
1285
+ options,
1286
+ "serverEntry",
1287
+ !isEditor ? config2.server.build.entry : config2.server.editor.entry
1288
+ ),
1289
+ getStringInputWithDefault(options, "serverStaticDir", config2.server.build.staticDir),
1290
+ getStringInputWithDefault(options, "serverOutDir", config2.server.outDir)
1133
1291
  )
1134
1292
  );
1135
- }
1136
1293
  return targets;
1137
1294
  }
1138
- createTarget(name, config2, platform, outDirOverride) {
1295
+ createTarget(name, platform, entryFile, staticDir, outDir) {
1139
1296
  return {
1140
1297
  name,
1141
- entry: config2.entryFile,
1142
- output: outDirOverride || config2.outDir,
1298
+ entry: entryFile,
1299
+ static: staticDir,
1300
+ output: outDir,
1143
1301
  platform
1144
1302
  };
1145
1303
  }
@@ -1153,17 +1311,18 @@ var BuildAction = class extends AbstractAction {
1153
1311
  }
1154
1312
  async buildTarget(target, directory, isWatch) {
1155
1313
  const packageManager = PackageManagerFactory.create("local_bun" /* LOCAL_BUN */);
1156
- const executeBuild = /* @__PURE__ */ __name((rebuild = false) => runSafe(
1157
- () => packageManager.build(
1314
+ const executeBuild = /* @__PURE__ */ __name((rebuild = false) => runSafe(() => {
1315
+ this.resetOut(target.output, directory);
1316
+ this.copyFiles(target, directory);
1317
+ return packageManager.build(
1158
1318
  target.name,
1159
1319
  directory,
1160
1320
  target.entry,
1161
1321
  target.output,
1162
1322
  ["--asset-naming", "[name].[ext]", "--target", target.platform],
1163
1323
  rebuild
1164
- ),
1165
- false
1166
- ), "executeBuild");
1324
+ );
1325
+ }, false), "executeBuild");
1167
1326
  if (isWatch) {
1168
1327
  this.watchDirectory(directory, target.entry, () => executeBuild(true));
1169
1328
  }
@@ -1171,7 +1330,7 @@ var BuildAction = class extends AbstractAction {
1171
1330
  return result !== false;
1172
1331
  }
1173
1332
  watchDirectory(directory, entry, onChange) {
1174
- const watchPath = dirname(join3(getCwd(directory), entry));
1333
+ const watchPath = dirname(join4(getCwd(directory), entry));
1175
1334
  watch(watchPath).on("change", onChange);
1176
1335
  }
1177
1336
  enterWatchMode() {
@@ -1180,43 +1339,16 @@ var BuildAction = class extends AbstractAction {
1180
1339
  console.info();
1181
1340
  return { keepAlive: true };
1182
1341
  }
1183
- };
1184
-
1185
- // src/action/actions/dev.action.ts
1186
- var DevAction = class extends AbstractAction {
1187
- static {
1188
- __name(this, "DevAction");
1342
+ resetOut(outDir, directory) {
1343
+ resetFolder(getCwd(join4(directory, outDir)));
1189
1344
  }
1190
- startMessage = Messages.DEV_START;
1191
- successMessage = Messages.DEV_SUCCESS;
1192
- failureMessage = Messages.DEV_FAILED;
1193
- async handle(_args, options) {
1194
- const directory = getDirectoryInput(options);
1195
- const generate = getDevGenerateInput(options);
1196
- const tasks = this.buildTaskList(directory, generate);
1197
- await Promise.all(tasks);
1198
- return { keepAlive: true };
1199
- }
1200
- buildTaskList(directory, generate) {
1201
- const tasks = [];
1202
- if (generate) {
1203
- tasks.push(this.runSubCommand("generate", directory, { silent: true }));
1204
- }
1205
- tasks.push(this.runSubCommand("build", directory, { silent: true }));
1206
- tasks.push(this.runSubCommand("start", directory, { silent: false }));
1207
- return tasks;
1208
- }
1209
- async runSubCommand(command, directory, options) {
1210
- await runSafe(async () => {
1211
- const packageManager = await PackageManagerFactory.find(directory);
1212
- await packageManager.runDev(directory, "nf", {}, [command, "--watch"], options.silent);
1213
- });
1345
+ copyFiles(target, directory) {
1346
+ const from = getCwd(join4(directory, target.static));
1347
+ const to = getCwd(join4(directory, target.output));
1348
+ copyFiles(from, to);
1214
1349
  }
1215
1350
  };
1216
1351
 
1217
- // src/action/actions/generate.action.ts
1218
- import { join as join4 } from "path";
1219
-
1220
1352
  // src/lib/schematics/abstract.collection.ts
1221
1353
  var AbstractCollection = class {
1222
1354
  constructor(collection, runner, cwd2) {
@@ -1224,6 +1356,9 @@ var AbstractCollection = class {
1224
1356
  this.runner = runner;
1225
1357
  this.cwd = cwd2;
1226
1358
  }
1359
+ collection;
1360
+ runner;
1361
+ cwd;
1227
1362
  static {
1228
1363
  __name(this, "AbstractCollection");
1229
1364
  }
@@ -1273,6 +1408,16 @@ var NanoforgeCollection = class _NanoforgeCollection extends AbstractCollection
1273
1408
  name: "docker",
1274
1409
  alias: "docker",
1275
1410
  description: "Generate a Dockerfile for the application"
1411
+ },
1412
+ {
1413
+ name: "component",
1414
+ alias: "component",
1415
+ description: "Generate a Component for an application"
1416
+ },
1417
+ {
1418
+ name: "system",
1419
+ alias: "system",
1420
+ description: "Generate a System for an application"
1276
1421
  }
1277
1422
  ];
1278
1423
  constructor(runner, cwd2) {
@@ -1316,6 +1461,7 @@ var CollectionFactory = class {
1316
1461
  var toKebabCase = /* @__PURE__ */ __name((str) => {
1317
1462
  return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
1318
1463
  }, "toKebabCase");
1464
+ var capitalize = /* @__PURE__ */ __name((str) => str.charAt(0).toUpperCase() + str.slice(1), "capitalize");
1319
1465
 
1320
1466
  // src/lib/schematics/schematic.option.ts
1321
1467
  var SchematicOption = class {
@@ -1323,6 +1469,8 @@ var SchematicOption = class {
1323
1469
  this.name = name;
1324
1470
  this.value = value;
1325
1471
  }
1472
+ name;
1473
+ value;
1326
1474
  static {
1327
1475
  __name(this, "SchematicOption");
1328
1476
  }
@@ -1393,7 +1541,108 @@ var mapSchematicOptions = /* @__PURE__ */ __name((inputs) => {
1393
1541
  }, []);
1394
1542
  }, "mapSchematicOptions");
1395
1543
 
1544
+ // src/action/actions/create.action.ts
1545
+ var CreateAction = class extends AbstractAction {
1546
+ static {
1547
+ __name(this, "CreateAction");
1548
+ }
1549
+ startMessage = Messages.CREATE_START;
1550
+ successMessage = Messages.CREATE_SUCCESS;
1551
+ failureMessage = Messages.CREATE_FAILED;
1552
+ async handle(args, options) {
1553
+ const directory = getDirectoryInput(options);
1554
+ const config2 = await getConfig(options, directory, true);
1555
+ const type = getCreateTypeInput(args);
1556
+ const name = await getCreateNameInputOrAsk(options);
1557
+ const isServer = getServerInput(options);
1558
+ const path = getPathInputWithDefault(
1559
+ options,
1560
+ config2[isServer ? "server" : "client"].dirs[type === "component" ? "components" : "systems"]
1561
+ );
1562
+ await this.generateElement(directory, type, {
1563
+ name,
1564
+ directory: path,
1565
+ part: isServer ? "server" : "client",
1566
+ language: config2.language
1567
+ });
1568
+ return {};
1569
+ }
1570
+ async generateElement(directory, type, values) {
1571
+ const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1572
+ await executeSchematic(capitalize(type), collection, type, values);
1573
+ }
1574
+ };
1575
+
1576
+ // src/action/actions/dev.action.ts
1577
+ var DevAction = class extends AbstractAction {
1578
+ static {
1579
+ __name(this, "DevAction");
1580
+ }
1581
+ startMessage = Messages.DEV_START;
1582
+ successMessage = Messages.DEV_SUCCESS;
1583
+ failureMessage = Messages.DEV_FAILED;
1584
+ async handle(_args, options) {
1585
+ const directory = getDirectoryInput(options);
1586
+ const generate = getDevGenerateInput(options);
1587
+ const tasks = this.buildTaskList(directory, generate);
1588
+ await Promise.all(tasks);
1589
+ return { keepAlive: true };
1590
+ }
1591
+ buildTaskList(directory, generate) {
1592
+ const tasks = [];
1593
+ if (generate) {
1594
+ tasks.push(this.runSubCommand("generate", directory, { silent: true }));
1595
+ }
1596
+ tasks.push(this.runSubCommand("build", directory, { silent: true }));
1597
+ tasks.push(this.runSubCommand("start", directory, { silent: false }));
1598
+ return tasks;
1599
+ }
1600
+ async runSubCommand(command, directory, options) {
1601
+ await runSafe(async () => {
1602
+ const packageManager = await PackageManagerFactory.find(directory);
1603
+ await packageManager.runDev(directory, "nf", {}, [command, "--watch"], options.silent);
1604
+ });
1605
+ }
1606
+ };
1607
+
1608
+ // src/action/actions/editor.action.ts
1609
+ import open from "open";
1610
+ import { join as join5 } from "path";
1611
+ var EditorAction = class extends AbstractAction {
1612
+ static {
1613
+ __name(this, "EditorAction");
1614
+ }
1615
+ startMessage = Messages.EDITOR_START;
1616
+ successMessage = Messages.EDITOR_SUCCESS;
1617
+ failureMessage = Messages.EDITOR_FAILED;
1618
+ async handle(args, options) {
1619
+ const directory = getDirectoryInput(options);
1620
+ const path = getPathInput(args);
1621
+ const open2 = getEditorOpenInput(options, !!path);
1622
+ void this.startEditor(directory);
1623
+ if (open2) await this.openEditor(path);
1624
+ return { keepAlive: true };
1625
+ }
1626
+ async startEditor(directory) {
1627
+ const editorPath = join5(
1628
+ getModulePath("@nanoforge-dev/editor/package.json", true),
1629
+ "dist",
1630
+ "index.js"
1631
+ );
1632
+ await runSafe(async () => {
1633
+ const packageManager = PackageManagerFactory.create("local_bun" /* LOCAL_BUN */);
1634
+ await packageManager.run("Editor", directory, editorPath, [], {}, [], true);
1635
+ });
1636
+ }
1637
+ async openEditor(path) {
1638
+ const query = path ? `?projectPath=${encodeURIComponent(path)}` : "";
1639
+ const url = `http://localhost:3000/load-project${query}`;
1640
+ await open(url);
1641
+ }
1642
+ };
1643
+
1396
1644
  // src/action/actions/generate.action.ts
1645
+ import { join as join6 } from "path";
1397
1646
  var GenerateAction = class extends AbstractAction {
1398
1647
  static {
1399
1648
  __name(this, "GenerateAction");
@@ -1404,9 +1653,9 @@ var GenerateAction = class extends AbstractAction {
1404
1653
  async handle(_args, options) {
1405
1654
  const directory = getDirectoryInput(options);
1406
1655
  const config2 = await getConfig(options, directory);
1656
+ const isEditor = getEditorInput(options);
1407
1657
  const isWatch = getWatchInput(options);
1408
- const values = this.extractValues(config2);
1409
- await this.generateParts(values, directory, isWatch);
1658
+ await this.generateParts(config2, directory, isEditor, isWatch);
1410
1659
  if (isWatch) {
1411
1660
  return this.enterWatchMode();
1412
1661
  }
@@ -1414,43 +1663,45 @@ var GenerateAction = class extends AbstractAction {
1414
1663
  }
1415
1664
  extractValues(config2) {
1416
1665
  return {
1417
- name: config2.name,
1418
1666
  directory: ".",
1419
1667
  language: config2.language,
1420
- server: config2.server.enable,
1421
1668
  initFunctions: config2.initFunctions
1422
1669
  };
1423
1670
  }
1424
- async generateParts(values, directory, watch3) {
1671
+ async generateParts(config2, directory, isEditor, watch3) {
1425
1672
  const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1426
- const baseOptions = this.baseSchematicOptions(values);
1427
- await executeSchematic(
1428
- "Client main file",
1429
- collection,
1430
- "part-main",
1431
- { ...baseOptions, part: "client" },
1432
- watch3 ? this.watchPath(directory, values.directory, "client") : void 0
1433
- );
1434
- if (values.server) {
1673
+ const values = this.extractValues(config2);
1674
+ if (config2.client.enable)
1675
+ await executeSchematic(
1676
+ "Client main file",
1677
+ collection,
1678
+ "part-main",
1679
+ {
1680
+ ...values,
1681
+ part: "client",
1682
+ outFile: !isEditor ? config2.client.build.entry : config2.client.editor.entry,
1683
+ saveFile: config2.client.editor.save,
1684
+ editor: isEditor
1685
+ },
1686
+ watch3 ? this.watchPath(directory, values.directory, config2.client.editor.save) : void 0
1687
+ );
1688
+ if (config2.server.enable)
1435
1689
  await executeSchematic(
1436
1690
  "Server main file",
1437
1691
  collection,
1438
1692
  "part-main",
1439
- { ...baseOptions, part: "server" },
1440
- this.watchPath(directory, values.directory, "server")
1693
+ {
1694
+ ...values,
1695
+ part: "server",
1696
+ outFile: !isEditor ? config2.server.build.entry : config2.server.editor.entry,
1697
+ saveFile: config2.server.editor.save,
1698
+ editor: isEditor
1699
+ },
1700
+ this.watchPath(directory, values.directory, config2.server.editor.save)
1441
1701
  );
1442
- }
1443
1702
  }
1444
- baseSchematicOptions(values) {
1445
- return {
1446
- name: values.name,
1447
- directory: values.directory,
1448
- language: values.language,
1449
- initFunctions: values.initFunctions
1450
- };
1451
- }
1452
- watchPath(directory, subDir, part) {
1453
- return join4(getCwd(directory), subDir, NANOFORGE_DIR, `${part}.save.json`);
1703
+ watchPath(directory, subDir, saveFile) {
1704
+ return join6(getCwd(directory), subDir, saveFile);
1454
1705
  }
1455
1706
  enterWatchMode() {
1456
1707
  console.info();
@@ -1461,7 +1712,7 @@ var GenerateAction = class extends AbstractAction {
1461
1712
  };
1462
1713
 
1463
1714
  // src/action/actions/install.action.ts
1464
- import { join as join6 } from "path";
1715
+ import { join as join8 } from "path";
1465
1716
 
1466
1717
  // src/lib/global-config/global-config-handler.ts
1467
1718
  import { read, readUser, write, writeUser } from "rc9";
@@ -1704,8 +1955,8 @@ var concatDeps = /* @__PURE__ */ __name((deps) => {
1704
1955
  }, "concatDeps");
1705
1956
 
1706
1957
  // src/lib/registry/registry.ts
1707
- import fs3 from "fs";
1708
- import { join as join5 } from "path";
1958
+ import fs4 from "fs";
1959
+ import { join as join7 } from "path";
1709
1960
  var Registry = class {
1710
1961
  static {
1711
1962
  __name(this, "Registry");
@@ -1736,9 +1987,9 @@ var Registry = class {
1736
1987
  }
1737
1988
  static async installPackage(client2, manifest, dir) {
1738
1989
  const file = await client2.getFile(`/registry/${manifest.name}/-/${manifest._file}`);
1739
- const path = join5(dir, this.getTypeSubFolder(manifest.type));
1740
- fs3.mkdirSync(path, { recursive: true });
1741
- fs3.writeFileSync(join5(path, manifest._file), await file.bytes());
1990
+ const path = join7(dir, this.getTypeSubFolder(manifest.type));
1991
+ fs4.mkdirSync(path, { recursive: true });
1992
+ fs4.writeFileSync(join7(path, manifest._file), await file.bytes());
1742
1993
  }
1743
1994
  static getTypeSubFolder(type) {
1744
1995
  if (type === "component") return "components";
@@ -1750,14 +2001,14 @@ var Registry = class {
1750
2001
  return withAuth(config2.apiKey, force, !headers ? {} : void 0);
1751
2002
  }
1752
2003
  static _getPackageFile(filename, dir) {
1753
- const path = join5(getCwd(dir ?? "."), filename);
1754
- if (!fs3.existsSync(path))
2004
+ const path = join7(getCwd(dir ?? "."), filename);
2005
+ if (!fs4.existsSync(path))
1755
2006
  throw new Error(
1756
- "Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.components`!"
2007
+ "Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.package`!"
1757
2008
  );
1758
2009
  try {
1759
- fs3.accessSync(path, fs3.constants.R_OK);
1760
- return fs3.openAsBlob(path);
2010
+ fs4.accessSync(path, fs4.constants.R_OK);
2011
+ return fs4.openAsBlob(path);
1761
2012
  } catch {
1762
2013
  throw new Error("Cannot read package file, please verify your file permissions!");
1763
2014
  }
@@ -1776,7 +2027,7 @@ var InstallAction = class extends AbstractAction {
1776
2027
  const names = await getInstallNamesInputOrAsk(args);
1777
2028
  const directory = getDirectoryInput(options);
1778
2029
  const isLib = getInstallLibInput(options);
1779
- const isServer = getInstallServerInput(options);
2030
+ const isServer = getServerInput(options);
1780
2031
  return isLib ? this._installLibs(directory, names) : this._installNfPackages(directory, names, isServer);
1781
2032
  }
1782
2033
  async _installLibs(directory, names) {
@@ -1785,17 +2036,16 @@ var InstallAction = class extends AbstractAction {
1785
2036
  }
1786
2037
  async _installNfPackages(directory, names, isServer) {
1787
2038
  const deps = await resolveManifestDependencies(names, directory);
2039
+ const part = isServer ? "server" : "client";
1788
2040
  const libSuccess = await this._installLibs(
1789
2041
  directory,
1790
2042
  deps.npm.map(([name, version]) => `${name}@${version}`)
1791
2043
  );
1792
2044
  if (!libSuccess) return { success: false };
1793
- return withSpinner(Messages.INSTALL_PACKAGES_IN_PROGRESS, async () => {
1794
- await Registry.install(
1795
- Object.values(deps.nf),
1796
- join6(directory, isServer ? "server" : "client")
1797
- );
1798
- });
2045
+ return withSpinner(
2046
+ () => Registry.install(Object.values(deps.nf), join8(directory, part)),
2047
+ Messages.INSTALL_PACKAGES_IN_PROGRESS
2048
+ );
1799
2049
  }
1800
2050
  };
1801
2051
 
@@ -1846,7 +2096,82 @@ var LogoutAction = class extends AbstractAction {
1846
2096
  };
1847
2097
 
1848
2098
  // src/action/actions/new.action.ts
1849
- import { join as join7 } from "path";
2099
+ import { join as join9 } from "path";
2100
+
2101
+ // src/lib/git/git-runner.ts
2102
+ var GIT = "git";
2103
+ var GIT_COMMANDS = {
2104
+ init: "init",
2105
+ remote: "remote"
2106
+ };
2107
+ var GitRunner = class {
2108
+ static {
2109
+ __name(this, "GitRunner");
2110
+ }
2111
+ runner;
2112
+ constructor() {
2113
+ this.runner = new Runner(GIT);
2114
+ }
2115
+ async init(directory) {
2116
+ const args = [GIT_COMMANDS.init];
2117
+ const result = await withSpinner(
2118
+ () => this.exec(args, directory),
2119
+ Messages.GIT_INIT_IN_PROGRESS,
2120
+ Messages.GIT_INIT_SUCCEED,
2121
+ Messages.GIT_INIT_FAILED(this.formatFailCommand(args))
2122
+ );
2123
+ return result.success;
2124
+ }
2125
+ async addRemote(directory, remote) {
2126
+ const args = [GIT_COMMANDS.remote, "add", "origin", remote];
2127
+ const result = await withSpinner(
2128
+ () => this.exec(args, directory),
2129
+ Messages.GIT_REMOTE_IN_PROGRESS,
2130
+ Messages.GIT_REMOTE_SUCCEED,
2131
+ Messages.GIT_REMOTE_FAILED(this.formatFailCommand(args))
2132
+ );
2133
+ return result.success;
2134
+ }
2135
+ exec(args, directory, options = {}) {
2136
+ return this.runner.run(args, {
2137
+ collect: options.collect ?? true,
2138
+ cwd: getCwd(directory),
2139
+ env: options.env,
2140
+ listeners: options.listeners,
2141
+ onFail: options.onFail
2142
+ });
2143
+ }
2144
+ formatFailCommand(args) {
2145
+ return this.runner.fullCommand(args);
2146
+ }
2147
+ };
2148
+
2149
+ // src/lib/input/inputs/new/git-remote.input.ts
2150
+ var getGitRemoteInput = /* @__PURE__ */ __name((inputs) => {
2151
+ return getStringInput(inputs, "gitRemote");
2152
+ }, "getGitRemoteInput");
2153
+ var getNewGitRemoteInputOrAsk = /* @__PURE__ */ __name((inputs) => {
2154
+ return getInputOrAsk(
2155
+ getGitRemoteInput(inputs),
2156
+ () => askInput(Messages.NEW_GIT_REMOTE_QUESTION, {
2157
+ required: false,
2158
+ default: ""
2159
+ })
2160
+ );
2161
+ }, "getNewGitRemoteInputOrAsk");
2162
+
2163
+ // src/lib/input/inputs/new/git.input.ts
2164
+ var getNewGitInput = /* @__PURE__ */ __name((inputs) => {
2165
+ return getBooleanInput(inputs, "git");
2166
+ }, "getNewGitInput");
2167
+ var getNewGitOrAsk = /* @__PURE__ */ __name((inputs) => {
2168
+ return getInputOrAsk(
2169
+ getNewGitInput(inputs),
2170
+ () => askConfirm(Messages.NEW_GIT_QUESTION, { default: true })
2171
+ );
2172
+ }, "getNewGitOrAsk");
2173
+
2174
+ // src/action/actions/new.action.ts
1850
2175
  var NewAction = class extends AbstractAction {
1851
2176
  static {
1852
2177
  __name(this, "NewAction");
@@ -1859,18 +2184,16 @@ var NewAction = class extends AbstractAction {
1859
2184
  const values = await this.collectValues(options);
1860
2185
  await this.scaffold(values, cwdDirectory);
1861
2186
  let res = true;
2187
+ const distDir = join9(cwdDirectory, values.directory);
1862
2188
  if (!values.skipInstall) {
1863
- res = await this.installDependencies(
1864
- values.packageManager,
1865
- join7(cwdDirectory, values.directory ?? values.name)
1866
- );
2189
+ res = await this.installDependencies(values.packageManager, distDir);
1867
2190
  }
2191
+ if (values.git) await this.setupGitRepository(values.gitRemote, distDir);
1868
2192
  return { success: res };
1869
2193
  }
1870
2194
  async collectValues(inputs) {
1871
- return {
2195
+ const values = {
1872
2196
  name: await getNewNameInputOrAsk(inputs),
1873
- directory: getNewPathInput(inputs),
1874
2197
  packageManager: await getNewPackageManagerInputOrAsk(inputs),
1875
2198
  language: await getNewLanguageInputOrAsk(inputs),
1876
2199
  strict: await getNewStrictOrAsk(inputs),
@@ -1878,12 +2201,20 @@ var NewAction = class extends AbstractAction {
1878
2201
  initFunctions: getNewInitFunctionsWithDefault(inputs),
1879
2202
  skipInstall: await getNewSkipInstallOrAsk(inputs),
1880
2203
  docker: await getNewDockerOrAsk(inputs),
1881
- lint: getNewLintInput(inputs)
2204
+ lint: getNewLintInput(inputs),
2205
+ editor: getEditorInput(inputs),
2206
+ git: await getNewGitOrAsk(inputs)
2207
+ };
2208
+ return {
2209
+ ...values,
2210
+ directory: getPathInput(inputs) ?? values.name,
2211
+ gitRemote: values.git ? await getNewGitRemoteInputOrAsk(inputs) || null : null
1882
2212
  };
1883
2213
  }
1884
2214
  async scaffold(values, directory) {
1885
2215
  const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1886
- console.info(Messages.SCHEMATICS_START);
2216
+ console.info();
2217
+ console.info(Messages.NEW_GENERATION_START);
1887
2218
  console.info();
1888
2219
  await this.generateApplication(collection, values);
1889
2220
  await this.generateConfiguration(collection, values);
@@ -1901,14 +2232,17 @@ var NewAction = class extends AbstractAction {
1901
2232
  language: values.language,
1902
2233
  strict: values.strict,
1903
2234
  server: values.server,
1904
- lint: values.lint
2235
+ lint: values.lint,
2236
+ editor: values.editor
1905
2237
  });
1906
2238
  }
1907
2239
  generateConfiguration(collection, values) {
1908
2240
  return executeSchematic("Configuration", collection, "configuration", {
1909
2241
  name: values.name,
1910
2242
  directory: values.directory,
1911
- server: values.server
2243
+ server: values.server,
2244
+ language: values.language,
2245
+ initFunctions: values.initFunctions
1912
2246
  });
1913
2247
  }
1914
2248
  async generateClientParts(collection, values) {
@@ -1917,7 +2251,9 @@ var NewAction = class extends AbstractAction {
1917
2251
  ...partOptions,
1918
2252
  server: values.server
1919
2253
  });
1920
- await executeSchematic("Client main file", collection, "part-main", partOptions);
2254
+ await executeSchematic("Client main file", collection, "part-main", {
2255
+ ...partOptions
2256
+ });
1921
2257
  }
1922
2258
  async generateServerParts(collection, values) {
1923
2259
  const partOptions = this.partOptions(values, "server");
@@ -1925,18 +2261,18 @@ var NewAction = class extends AbstractAction {
1925
2261
  ...partOptions,
1926
2262
  server: values.server
1927
2263
  });
1928
- await executeSchematic("Server main file", collection, "part-main", partOptions);
2264
+ await executeSchematic("Server main file", collection, "part-main", {
2265
+ ...partOptions
2266
+ });
1929
2267
  }
1930
2268
  async generateDocker(collection, values) {
1931
2269
  await executeSchematic("Docker", collection, "docker", {
1932
- name: values.name,
1933
2270
  directory: values.directory,
1934
2271
  packageManager: values.packageManager
1935
2272
  });
1936
2273
  }
1937
2274
  partOptions(values, part) {
1938
2275
  return {
1939
- name: values.name,
1940
2276
  part,
1941
2277
  directory: values.directory,
1942
2278
  language: values.language,
@@ -1947,6 +2283,13 @@ var NewAction = class extends AbstractAction {
1947
2283
  const packageManager = PackageManagerFactory.create(packageManagerName);
1948
2284
  return await packageManager.install(directory);
1949
2285
  }
2286
+ async setupGitRepository(gitRemote, dir) {
2287
+ const runner = new GitRunner();
2288
+ let res;
2289
+ res = await runner.init(dir);
2290
+ if (res && gitRemote) res = await runner.addRemote(dir, gitRemote);
2291
+ return res;
2292
+ }
1950
2293
  };
1951
2294
 
1952
2295
  // src/lib/manifest/manifest.type.ts
@@ -1996,6 +2339,7 @@ var Manifest = class {
1996
2339
  name;
1997
2340
  type;
1998
2341
  description;
2342
+ tags;
1999
2343
  dependencies;
2000
2344
  publish;
2001
2345
  npmDependencies;
@@ -2017,6 +2361,11 @@ __decorateClass([
2017
2361
  IsString2(),
2018
2362
  IsOptional()
2019
2363
  ], Manifest.prototype, "description", 2);
2364
+ __decorateClass([
2365
+ Expose2(),
2366
+ IsString2({ each: true }),
2367
+ IsOptional()
2368
+ ], Manifest.prototype, "tags", 2);
2020
2369
  __decorateClass([
2021
2370
  Expose2(),
2022
2371
  IsString2({ each: true }),
@@ -2039,10 +2388,10 @@ __decorateClass([
2039
2388
  import { plainToInstance as plainToInstance2 } from "class-transformer";
2040
2389
  import { validate as validate2 } from "class-validator";
2041
2390
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
2042
- import { join as join8 } from "path";
2391
+ import { join as join10 } from "path";
2043
2392
  var getManifestPath = /* @__PURE__ */ __name((directory) => {
2044
2393
  for (const n of [MANIFEST_FILE_NAME]) {
2045
- const path = join8(directory, n);
2394
+ const path = join10(directory, n);
2046
2395
  if (existsSync2(path)) return path;
2047
2396
  }
2048
2397
  throw new Error(`No manifest file found in directory: ${directory}`);
@@ -2077,15 +2426,16 @@ var PublishAction = class extends AbstractAction {
2077
2426
  async handle(_args, options) {
2078
2427
  const directory = getDirectoryInput(options);
2079
2428
  const manifest = await loadManifest(directory);
2080
- return withSpinner(Messages.PUBLISH_IN_PROGRESS(manifest.name), async () => {
2081
- await Registry.publish(manifest, directory);
2082
- });
2429
+ return withSpinner(
2430
+ () => Registry.publish(manifest, directory),
2431
+ Messages.PUBLISH_IN_PROGRESS(manifest.name)
2432
+ );
2083
2433
  }
2084
2434
  };
2085
2435
 
2086
2436
  // src/action/actions/start.action.ts
2087
2437
  import dotenv from "dotenv";
2088
- import { join as join9, resolve as resolve3 } from "path";
2438
+ import { join as join11, resolve as resolve3 } from "path";
2089
2439
  var StartAction = class extends AbstractAction {
2090
2440
  static {
2091
2441
  __name(this, "StartAction");
@@ -2096,10 +2446,18 @@ var StartAction = class extends AbstractAction {
2096
2446
  async handle(_args, options) {
2097
2447
  const directory = getDirectoryInput(options);
2098
2448
  const config2 = await getConfig(options, directory);
2449
+ const clientDir = getStringInputWithDefault(options, "clientDir", config2.client.outDir);
2450
+ const serverDir = getStringInputWithDefault(options, "serverDir", config2.server.outDir);
2099
2451
  const watch3 = getWatchInput(options);
2100
2452
  const port = getStringInputWithDefault(options, "port", config2.client.port);
2101
2453
  const ssl = this.resolveSSL(options);
2102
- const tasks = this.buildStartTasks(config2, directory, watch3, port, ssl);
2454
+ const tasks = this.buildStartTasks(config2, directory, {
2455
+ clientDir,
2456
+ serverDir,
2457
+ watch: watch3,
2458
+ port,
2459
+ ssl
2460
+ });
2103
2461
  await Promise.all(tasks);
2104
2462
  return { keepAlive: true };
2105
2463
  }
@@ -2114,13 +2472,16 @@ var StartAction = class extends AbstractAction {
2114
2472
  key
2115
2473
  };
2116
2474
  }
2117
- buildStartTasks(config2, directory, watch3, port, ssl) {
2475
+ buildStartTasks(config2, directory, options) {
2118
2476
  const env2 = this.parseEnv(directory);
2119
2477
  const tasks = [];
2120
- if (config2.server.enable) {
2121
- tasks.push(this.startServer(directory, config2, { watch: watch3 }, env2));
2122
- }
2123
- tasks.push(this.startClient(directory, config2, { watch: watch3, port, ssl }, env2));
2478
+ const { clientDir, serverDir, watch: watch3, port, ssl } = options;
2479
+ if (config2.server.enable)
2480
+ tasks.push(this.startServer(directory, config2, { serverDir, watch: watch3 }, env2));
2481
+ if (config2.client.enable)
2482
+ tasks.push(
2483
+ this.startClient(directory, config2, { clientDir, serverDir, watch: watch3, port, ssl }, env2)
2484
+ );
2124
2485
  return tasks;
2125
2486
  }
2126
2487
  async startClient(directory, config2, options, env2) {
@@ -2135,14 +2496,14 @@ var StartAction = class extends AbstractAction {
2135
2496
  }
2136
2497
  buildClientParams(directory, config2, options) {
2137
2498
  const params = {
2138
- "-d": getCwd(join9(directory, config2.client.runtime.dir)),
2499
+ "-d": getCwd(join11(directory, options.clientDir)),
2139
2500
  "-p": options.port
2140
2501
  };
2141
2502
  if (options.watch) params["--watch"] = true;
2142
2503
  if (options.watch) {
2143
2504
  params["--watch"] = true;
2144
2505
  if (config2.server.enable) {
2145
- params["--watch-server-dir"] = getCwd(join9(directory, config2.server.runtime.dir));
2506
+ params["--watch-server-dir"] = getCwd(join11(directory, options.serverDir));
2146
2507
  }
2147
2508
  }
2148
2509
  if (options.ssl) {
@@ -2151,9 +2512,9 @@ var StartAction = class extends AbstractAction {
2151
2512
  }
2152
2513
  return this.buildParams(params);
2153
2514
  }
2154
- buildServerParams(directory, config2, options) {
2515
+ buildServerParams(directory, _config, options) {
2155
2516
  const params = {
2156
- "-d": getCwd(join9(directory, config2.server.runtime.dir))
2517
+ "-d": getCwd(join11(directory, options.serverDir))
2157
2518
  };
2158
2519
  if (options.watch) params["--watch"] = true;
2159
2520
  return this.buildParams(params);
@@ -2169,7 +2530,7 @@ var StartAction = class extends AbstractAction {
2169
2530
  ...process.env
2170
2531
  };
2171
2532
  dotenv.config({
2172
- path: resolve3(getCwd(join9(dir, ".env"))),
2533
+ path: resolve3(getCwd(join11(dir, ".env"))),
2173
2534
  processEnv: rawEnv
2174
2535
  });
2175
2536
  const baseEnv = Object.entries(rawEnv).filter(
@@ -2203,9 +2564,10 @@ var UnpublishAction = class extends AbstractAction {
2203
2564
  async handle(_args, options) {
2204
2565
  const directory = getDirectoryInput(options);
2205
2566
  const manifest = await loadManifest(directory);
2206
- return withSpinner(Messages.UNPUBLISH_IN_PROGRESS(manifest.name), async () => {
2207
- await Registry.unpublish(manifest, directory);
2208
- });
2567
+ return withSpinner(
2568
+ () => Registry.unpublish(manifest, directory),
2569
+ Messages.UNPUBLISH_IN_PROGRESS(manifest.name)
2570
+ );
2209
2571
  }
2210
2572
  };
2211
2573
 
@@ -2214,6 +2576,7 @@ var AbstractCommand = class {
2214
2576
  constructor(action) {
2215
2577
  this.action = action;
2216
2578
  }
2579
+ action;
2217
2580
  static {
2218
2581
  __name(this, "AbstractCommand");
2219
2582
  }
@@ -2232,12 +2595,17 @@ var BuildCommand = class extends AbstractCommand {
2232
2595
  __name(this, "BuildCommand");
2233
2596
  }
2234
2597
  load(program) {
2235
- program.command("build").description("build your game").option("-d, --directory [directory]", "specify the working directory of the command").option("-c, --config [config]", "path to the config file", CONFIG_FILE_NAME).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) => {
2598
+ program.command("build").description("build your game").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("--client-entry <clientEntry>", "specify the entry file of the client").option("--server-entry <serverEntry>", "specify the entry file of the server").option("--client-static-dir <clientStaticDir>", "specify the static directory of the client").option("--server-static-dir <serverStaticDir>", "specify the static directory of the server").option("--client-out-dir <clientOutDir>", "specify the output directory of the client").option("--server-out-dir <serverOutDir>", "specify the output directory of the server").option("--editor", "specify if the project must build with editor config").option("--watch", "build app in watching mode", false).action(async (rawOptions) => {
2236
2599
  const options = AbstractCommand.mapToInput({
2237
2600
  directory: rawOptions.directory,
2238
2601
  config: rawOptions.config,
2239
- clientDirectory: rawOptions.clientOutDir,
2240
- serverDirectory: rawOptions.serverOutDir,
2602
+ clientEntry: rawOptions.clientEntry,
2603
+ serverEntry: rawOptions.serverEntry,
2604
+ clientStaticDir: rawOptions.clientStaticDir,
2605
+ serverStaticDir: rawOptions.serverStaticDir,
2606
+ clientOutDir: rawOptions.clientOutDir,
2607
+ serverOutDir: rawOptions.serverOutDir,
2608
+ editor: rawOptions.editor,
2241
2609
  watch: rawOptions.watch
2242
2610
  });
2243
2611
  await this.action.run(/* @__PURE__ */ new Map(), options);
@@ -2245,13 +2613,42 @@ var BuildCommand = class extends AbstractCommand {
2245
2613
  }
2246
2614
  };
2247
2615
 
2616
+ // src/command/commands/create.command.ts
2617
+ var CreateCommand = class extends AbstractCommand {
2618
+ static {
2619
+ __name(this, "CreateCommand");
2620
+ }
2621
+ load(program) {
2622
+ program.command("create <type>").description("create nanoforge components or systems").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("-n, --name <name>", "name of the component/system").option(
2623
+ "-s, --server",
2624
+ "install components/systems on server (default install on client)",
2625
+ false
2626
+ ).option(
2627
+ "-p, --path <path>",
2628
+ "path to the component/system folder (default: <part>/<components|systems>)"
2629
+ ).action(async (type, rawOptions) => {
2630
+ const args = AbstractCommand.mapToInput({
2631
+ type
2632
+ });
2633
+ const options = AbstractCommand.mapToInput({
2634
+ directory: rawOptions.directory,
2635
+ config: rawOptions.config,
2636
+ name: rawOptions.name,
2637
+ server: rawOptions.server,
2638
+ path: rawOptions.path
2639
+ });
2640
+ await this.action.run(args, options);
2641
+ });
2642
+ }
2643
+ };
2644
+
2248
2645
  // src/command/commands/dev.command.ts
2249
2646
  var DevCommand = class extends AbstractCommand {
2250
2647
  static {
2251
2648
  __name(this, "DevCommand");
2252
2649
  }
2253
2650
  load(program) {
2254
- program.command("dev").description("run your game in dev mode").option("-d, --directory [directory]", "specify the working directory of the command").option("-c, --config [config]", "path to the config file", CONFIG_FILE_NAME).option("--generate", "generate app from config", false).action(async (rawOptions) => {
2651
+ program.command("dev").description("run your game in dev mode").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("--generate", "generate app from config", false).action(async (rawOptions) => {
2255
2652
  const options = AbstractCommand.mapToInput({
2256
2653
  directory: rawOptions.directory,
2257
2654
  config: rawOptions.config,
@@ -2262,16 +2659,39 @@ var DevCommand = class extends AbstractCommand {
2262
2659
  }
2263
2660
  };
2264
2661
 
2662
+ // src/command/commands/editor.command.ts
2663
+ var EditorCommand = class extends AbstractCommand {
2664
+ static {
2665
+ __name(this, "EditorCommand");
2666
+ }
2667
+ load(program) {
2668
+ program.command("editor [path]").description("start the editor").option("-d, --directory <directory>", "specify the working directory of the command").option(
2669
+ "--open",
2670
+ "open the editor on the default web browser (default: true if path is specified, false otherwise)"
2671
+ ).option("--no-open", "do not open the editor on the default web browser").action(async (path, rawOptions) => {
2672
+ const args = AbstractCommand.mapToInput({
2673
+ path
2674
+ });
2675
+ const options = AbstractCommand.mapToInput({
2676
+ directory: rawOptions.directory,
2677
+ open: rawOptions.open
2678
+ });
2679
+ await this.action.run(args, options);
2680
+ });
2681
+ }
2682
+ };
2683
+
2265
2684
  // src/command/commands/generate.command.ts
2266
2685
  var GenerateCommand = class extends AbstractCommand {
2267
2686
  static {
2268
2687
  __name(this, "GenerateCommand");
2269
2688
  }
2270
2689
  load(program) {
2271
- program.command("generate").description("generate nanoforge files from config").option("-d, --directory [directory]", "specify the working directory of the command").option("-c, --config [config]", "path to the config file", CONFIG_FILE_NAME).option("--watch", "generate app in watching mode", false).action(async (rawOptions) => {
2690
+ program.command("generate").description("generate nanoforge files from config").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("--editor", "specify if the project must generate editor main file").option("--watch", "generate app in watching mode", false).action(async (rawOptions) => {
2272
2691
  const options = AbstractCommand.mapToInput({
2273
2692
  directory: rawOptions.directory,
2274
2693
  config: rawOptions.config,
2694
+ editor: rawOptions.editor,
2275
2695
  watch: rawOptions.watch
2276
2696
  });
2277
2697
  await this.action.run(/* @__PURE__ */ new Map(), options);
@@ -2285,7 +2705,7 @@ var InstallCommand = class extends AbstractCommand {
2285
2705
  __name(this, "InstallCommand");
2286
2706
  }
2287
2707
  load(program) {
2288
- program.command("install [names...]").alias("add").description("add Nanoforge components and systems to your project").option("-d, --directory [directory]", "specify the working directory of the command").option("-l, --lib", "install library instead of component/system", false).option(
2708
+ program.command("install [names...]").alias("add").description("add Nanoforge components and systems to your project").option("-d, --directory <directory>", "specify the working directory of the command").option("-l, --lib", "install library instead of component/system", false).option(
2289
2709
  "-s, --server",
2290
2710
  "install components/systems on server (default install on client)",
2291
2711
  false
@@ -2309,7 +2729,7 @@ var LoginCommand = class extends AbstractCommand {
2309
2729
  __name(this, "LoginCommand");
2310
2730
  }
2311
2731
  load(program) {
2312
- program.command("login").description("login to Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").option("-l, --local", "login only for the project", false).option("-k, --api-key <key>", "api key for Nanoforge registry").action(async (rawOptions) => {
2732
+ program.command("login").description("login to Nanoforge registry").option("-d, --directory <directory>", "specify the working directory of the command").option("-l, --local", "login only for the project", false).option("-k, --api-key <key>", "api key for Nanoforge registry").action(async (rawOptions) => {
2313
2733
  const options = AbstractCommand.mapToInput({
2314
2734
  directory: rawOptions.directory,
2315
2735
  local: rawOptions.local,
@@ -2326,7 +2746,7 @@ var LogoutCommand = class extends AbstractCommand {
2326
2746
  __name(this, "LogoutCommand");
2327
2747
  }
2328
2748
  load(program) {
2329
- program.command("logout").description("logout from Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").option("-l, --local", "logout only for the project").action(async (rawOptions) => {
2749
+ program.command("logout").description("logout from Nanoforge registry").option("-d, --directory <directory>", "specify the working directory of the command").option("-l, --local", "logout only for the project").action(async (rawOptions) => {
2330
2750
  const options = AbstractCommand.mapToInput({
2331
2751
  directory: rawOptions.directory,
2332
2752
  local: rawOptions.local
@@ -2342,10 +2762,13 @@ var NewCommand = class extends AbstractCommand {
2342
2762
  __name(this, "NewCommand");
2343
2763
  }
2344
2764
  load(program) {
2345
- program.command("new").description("create a new nanoforge project").option("-d, --directory [directory]", "specify the working directory of the command").option("--name [name]", "specify the name of your project").option(
2346
- "--path [path]",
2765
+ program.command("new").description("create a new nanoforge project").option("-d, --directory <directory>", "specify the working directory of the command").option("--name <name>", "specify the name of your project").option(
2766
+ "--path <path>",
2347
2767
  "specify the relative path where your project will be created (default: name of the project)"
2348
- ).option("--package-manager [packageManager]", "specify the package manager of your project").option("--language [language]", "specify the language of your project").option("--strict", "use strict mode").option("--no-strict", "do not use strict mode").option("--server", "create a server").option("--no-server", "do not create a server").option("--init-functions", "initialize functions").option("--no-init-functions", "do not initialize functions").option("--skip-install", "skip installing dependencies").option("--no-skip-install", "do not skip installing dependencies").option("--docker", "generate docker files").option("--no-docker", "do not generate docker files").option("--no-lint", "do not generate lint files").action(async (rawOptions) => {
2768
+ ).option("--package-manager <packageManager>", "specify the package manager of your project").option("--language <language>", "specify the language of your project").option("--strict", "use strict mode").option("--no-strict", "do not use strict mode").option("--server", "create a server").option("--no-server", "do not create a server").option("--init-functions", "initialize functions").option("--no-init-functions", "do not initialize functions").option("--skip-install", "skip installing dependencies").option("--no-skip-install", "do not skip installing dependencies").option("--docker", "generate docker files").option("--no-docker", "do not generate docker files").option("--no-lint", "do not generate lint files").option("--editor", "do add editor dependencies").option("--git", "generate git repository").option("--no-git", "do not generate git repository").option(
2769
+ "--git-remote <gitRemote>",
2770
+ "setup git remote to git repository (required if --git is used)"
2771
+ ).option("--no-git-remote", "do not setup git remote to git repository").action(async (rawOptions) => {
2349
2772
  const options = AbstractCommand.mapToInput({
2350
2773
  directory: rawOptions.directory,
2351
2774
  name: rawOptions.name,
@@ -2357,7 +2780,10 @@ var NewCommand = class extends AbstractCommand {
2357
2780
  initFunctions: rawOptions.initFunctions,
2358
2781
  skipInstall: rawOptions.skipInstall,
2359
2782
  docker: rawOptions.docker,
2360
- lint: rawOptions.lint
2783
+ lint: rawOptions.lint,
2784
+ editor: rawOptions.editor,
2785
+ git: rawOptions.git,
2786
+ gitRemote: rawOptions.gitRemote || void 0
2361
2787
  });
2362
2788
  await this.action.run(/* @__PURE__ */ new Map(), options);
2363
2789
  });
@@ -2370,7 +2796,7 @@ var PublishCommand = class extends AbstractCommand {
2370
2796
  __name(this, "PublishCommand");
2371
2797
  }
2372
2798
  load(program) {
2373
- program.command("publish").description("publish package to Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").action(async (rawOptions) => {
2799
+ program.command("publish").description("publish package to Nanoforge registry").option("-d, --directory <directory>", "specify the working directory of the command").action(async (rawOptions) => {
2374
2800
  const options = AbstractCommand.mapToInput({
2375
2801
  directory: rawOptions.directory
2376
2802
  });
@@ -2385,11 +2811,13 @@ var StartCommand = class extends AbstractCommand {
2385
2811
  __name(this, "StartCommand");
2386
2812
  }
2387
2813
  load(program) {
2388
- program.command("start").description("start your game").option("-d, --directory [directory]", "specify the working directory of the command").option("-c, --config [config]", "path to the config file", CONFIG_FILE_NAME).option("-p, --port [port]", "specify the port of the loader (the website to load the game)").option("--watch", "run app in watching mode", false).option("--cert [cert]", "path to the SSL certificate for HTTPS").option("--key [key]", "path to the SSL key for HTTPS").action(async (rawOptions) => {
2814
+ program.command("start").description("start your game").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("-p, --port <port>", "specify the port of the loader (the website to load the game)").option("--client-dir <clientDirectory>", "specify the directory of the client").option("--server-dir <serverDirectory>", "specify the directory of the server").option("--watch", "run app in watching mode", false).option("--cert <cert>", "path to the SSL certificate for HTTPS").option("--key <key>", "path to the SSL key for HTTPS").action(async (rawOptions) => {
2389
2815
  const options = AbstractCommand.mapToInput({
2390
2816
  directory: rawOptions.directory,
2391
2817
  config: rawOptions.config,
2392
2818
  port: rawOptions.port,
2819
+ clientDir: rawOptions.clientDir,
2820
+ serverDir: rawOptions.serverDir,
2393
2821
  watch: rawOptions.watch,
2394
2822
  cert: rawOptions.cert,
2395
2823
  key: rawOptions.key
@@ -2405,7 +2833,7 @@ var UnpublishCommand = class extends AbstractCommand {
2405
2833
  __name(this, "UnpublishCommand");
2406
2834
  }
2407
2835
  load(program) {
2408
- program.command("unpublish").description("unpublish package to Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").action(async (rawOptions) => {
2836
+ program.command("unpublish").description("unpublish package to Nanoforge registry").option("-d, --directory <directory>", "specify the working directory of the command").action(async (rawOptions) => {
2409
2837
  const options = AbstractCommand.mapToInput({
2410
2838
  directory: rawOptions.directory
2411
2839
  });
@@ -2425,7 +2853,9 @@ var CommandLoader = class {
2425
2853
  new BuildCommand(new BuildAction()).load(program);
2426
2854
  new StartCommand(new StartAction()).load(program);
2427
2855
  new DevCommand(new DevAction()).load(program);
2856
+ new EditorCommand(new EditorAction()).load(program);
2428
2857
  new GenerateCommand(new GenerateAction()).load(program);
2858
+ new CreateCommand(new CreateAction()).load(program);
2429
2859
  new LoginCommand(new LoginAction()).load(program);
2430
2860
  new LogoutCommand(new LogoutAction()).load(program);
2431
2861
  new PublishCommand(new PublishAction()).load(program);
@@ -2435,8 +2865,8 @@ var CommandLoader = class {
2435
2865
  static handleInvalidCommand(program) {
2436
2866
  program.on("command:*", () => {
2437
2867
  console.error(`
2438
- ${Prefixes.ERROR} Invalid command: ${red6`%s`}`, program.args.join(" "));
2439
- console.log(`See ${red6`--help`} for a list of available commands.
2868
+ ${Prefixes.ERROR} Invalid command: ${red7`%s`}`, program.args.join(" "));
2869
+ console.log(`See ${red7`--help`} for a list of available commands.
2440
2870
  `);
2441
2871
  process.exit(1);
2442
2872
  });