@nanoforge-dev/cli 1.3.0 → 1.4.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.
@@ -77,6 +77,11 @@ Try running manually: ${command}`), "BUILD_PART_FAILED"),
77
77
  NEW_SERVER_QUESTION: "Do you want to generate a server for multiplayer?",
78
78
  NEW_SKIP_INSTALL_QUESTION: "Do you want to skip dependency installation?",
79
79
  NEW_DOCKER_QUESTION: "Do you want to add a Dockerfile for containerization?",
80
+ // --- Create ---
81
+ CREATE_START: "NanoForge Component/System Creation",
82
+ CREATE_SUCCESS: success("Element successfully created!"),
83
+ CREATE_FAILED: failure("Creation failed!"),
84
+ CREATE_NAME_QUESTION: "What is the name of your component/system?",
80
85
  // --- Generate ---
81
86
  GENERATE_START: "NanoForge Generate",
82
87
  GENERATE_SUCCESS: success("Generation succeeded!"),
@@ -133,7 +138,7 @@ var getSpinner = /* @__PURE__ */ __name((message) => ora({ text: message }), "ge
133
138
 
134
139
  // src/action/actions/build.action.ts
135
140
  import { watch } from "chokidar";
136
- import { dirname, join as join3 } from "path";
141
+ import { dirname, join as join4 } from "path";
137
142
 
138
143
  // src/lib/input/base-inputs.ts
139
144
  var getStringInput = /* @__PURE__ */ __name((input2, field) => {
@@ -182,21 +187,10 @@ var getConfigInput = /* @__PURE__ */ __name((inputs) => {
182
187
  return getStringInputWithDefault(inputs, "config", ".");
183
188
  }, "getConfigInput");
184
189
 
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");
190
+ // src/lib/input/inputs/editor.input.ts
191
+ var getEditorInput = /* @__PURE__ */ __name((inputs) => {
192
+ return getBooleanInputWithDefault(inputs, "editor", false);
193
+ }, "getEditorInput");
200
194
 
201
195
  // src/lib/question/questions/confirm.question.ts
202
196
  import { confirm } from "@inquirer/prompts";
@@ -286,6 +280,66 @@ var askSelect = /* @__PURE__ */ __name(async (question, choices, baseOptions) =>
286
280
  }).catch(promptError);
287
281
  }, "askSelect");
288
282
 
283
+ // src/lib/input/inputs/name.input.ts
284
+ var getNameInput = /* @__PURE__ */ __name((inputs) => {
285
+ return getStringInput(inputs, "name");
286
+ }, "getNameInput");
287
+ var getNewNameInputOrAsk = /* @__PURE__ */ __name((inputs) => {
288
+ return getInputOrAsk(
289
+ getNameInput(inputs),
290
+ () => askInput(Messages.NEW_NAME_QUESTION, {
291
+ required: true,
292
+ default: "nanoforge-app"
293
+ })
294
+ );
295
+ }, "getNewNameInputOrAsk");
296
+ var getCreateNameInputOrAsk = /* @__PURE__ */ __name((inputs) => {
297
+ return getInputOrAsk(
298
+ getNameInput(inputs),
299
+ () => askInput(Messages.CREATE_NAME_QUESTION, {
300
+ required: true,
301
+ default: "example"
302
+ })
303
+ );
304
+ }, "getCreateNameInputOrAsk");
305
+
306
+ // src/lib/input/inputs/path.input.ts
307
+ var getPathInput = /* @__PURE__ */ __name((inputs) => {
308
+ return getStringInput(inputs, "path");
309
+ }, "getPathInput");
310
+ var getPathInputWithDefault = /* @__PURE__ */ __name((inputs, defaultValue) => {
311
+ return getStringInputWithDefault(inputs, "path", defaultValue);
312
+ }, "getPathInputWithDefault");
313
+
314
+ // src/lib/input/inputs/server.input.ts
315
+ function getServerInput(inputs) {
316
+ return getBooleanInputWithDefault(inputs, "server", false);
317
+ }
318
+ __name(getServerInput, "getServerInput");
319
+
320
+ // src/lib/input/inputs/watch.input.ts
321
+ var getWatchInput = /* @__PURE__ */ __name((inputs) => {
322
+ return getBooleanInputWithDefault(inputs, "watch", false);
323
+ }, "getWatchInput");
324
+
325
+ // src/lib/input/inputs/create/type.input.ts
326
+ var getCreateTypeInput = /* @__PURE__ */ __name((inputs) => {
327
+ const res = getStringInput(inputs, "type");
328
+ if (res && ["component", "system"].includes(res)) return res;
329
+ throw new Error("Invalid type. Please enter 'component' or 'system'.");
330
+ }, "getCreateTypeInput");
331
+
332
+ // src/lib/input/inputs/dev/generate.input.ts
333
+ var getDevGenerateInput = /* @__PURE__ */ __name((inputs) => {
334
+ return getBooleanInputWithDefault(inputs, "generate", false);
335
+ }, "getDevGenerateInput");
336
+
337
+ // src/lib/input/inputs/install/lib.input.ts
338
+ function getInstallLibInput(inputs) {
339
+ return getBooleanInputWithDefault(inputs, "lib", false);
340
+ }
341
+ __name(getInstallLibInput, "getInstallLibInput");
342
+
289
343
  // src/lib/input/inputs/install/names.input.ts
290
344
  var getNamesInput = /* @__PURE__ */ __name((inputs) => {
291
345
  return getArrayInput(inputs, "names");
@@ -297,12 +351,6 @@ var getInstallNamesInputOrAsk = /* @__PURE__ */ __name((inputs) => {
297
351
  );
298
352
  }, "getInstallNamesInputOrAsk");
299
353
 
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
354
  // src/lib/input/inputs/login-out/api-key.input.ts
307
355
  var getApiKeyInput = /* @__PURE__ */ __name((inputs) => {
308
356
  return getStringInput(inputs, "apiKey");
@@ -356,20 +404,6 @@ var getNewLintInput = /* @__PURE__ */ __name((inputs) => {
356
404
  return getBooleanInputWithDefault(inputs, "lint", true);
357
405
  }, "getNewLintInput");
358
406
 
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
407
  // src/lib/input/inputs/new/package-manager.input.ts
374
408
  var getPackageManagerInput = /* @__PURE__ */ __name((inputs) => {
375
409
  return getStringInput(inputs, "packageManager");
@@ -387,11 +421,6 @@ var getNewPackageManagerInputOrAsk = /* @__PURE__ */ __name((inputs) => {
387
421
  );
388
422
  }, "getNewPackageManagerInputOrAsk");
389
423
 
390
- // src/lib/input/inputs/new/path.input.ts
391
- var getNewPathInput = /* @__PURE__ */ __name((inputs) => {
392
- return getStringInput(inputs, "path");
393
- }, "getNewPathInput");
394
-
395
424
  // src/lib/input/inputs/new/server.input.ts
396
425
  var getNewServerInput = /* @__PURE__ */ __name((inputs) => {
397
426
  return getBooleanInput(inputs, "server");
@@ -494,6 +523,9 @@ var PackageManager = class {
494
523
  this.commands = commands;
495
524
  this.runner = runner;
496
525
  }
526
+ name;
527
+ commands;
528
+ runner;
497
529
  static {
498
530
  __name(this, "PackageManager");
499
531
  }
@@ -637,6 +669,8 @@ var Runner = class {
637
669
  this.binary = binary;
638
670
  this.baseArgs = baseArgs;
639
671
  }
672
+ binary;
673
+ baseArgs;
640
674
  static {
641
675
  __name(this, "Runner");
642
676
  }
@@ -841,6 +875,21 @@ var PackageManagerFactory = class {
841
875
  }
842
876
  };
843
877
 
878
+ // src/lib/utils/files.ts
879
+ import fs3 from "fs";
880
+ import { join as join2 } from "path";
881
+ var copyFiles = /* @__PURE__ */ __name((from, to) => {
882
+ if (!fs3.existsSync(from)) return;
883
+ if (!fs3.existsSync(to)) throw new Error(`Directory ${to} does not exist`);
884
+ fs3.readdirSync(from, { recursive: true }).forEach((file) => {
885
+ fs3.copyFileSync(join2(from, file.toString()), join2(to, file.toString()));
886
+ });
887
+ }, "copyFiles");
888
+ var resetFolder = /* @__PURE__ */ __name((folder) => {
889
+ if (fs3.existsSync(folder)) fs3.rmSync(folder, { recursive: true, force: true });
890
+ fs3.mkdirSync(folder);
891
+ }, "resetFolder");
892
+
844
893
  // src/lib/utils/run-safe.ts
845
894
  import { red as red5 } from "ansis";
846
895
  var runSafe = /* @__PURE__ */ __name(async (fn, fallback) => {
@@ -860,42 +909,77 @@ var BuildConfig = class {
860
909
  static {
861
910
  __name(this, "BuildConfig");
862
911
  }
863
- entryFile;
864
- outDir;
912
+ entry;
913
+ staticDir;
914
+ };
915
+ __decorateClass([
916
+ Expose(),
917
+ IsString(),
918
+ IsNotEmpty()
919
+ ], BuildConfig.prototype, "entry", 2);
920
+ __decorateClass([
921
+ Expose(),
922
+ IsString(),
923
+ IsNotEmpty()
924
+ ], BuildConfig.prototype, "staticDir", 2);
925
+ var EditorConfig = class {
926
+ static {
927
+ __name(this, "EditorConfig");
928
+ }
929
+ entry;
930
+ save;
865
931
  };
866
932
  __decorateClass([
867
933
  Expose(),
868
934
  IsString(),
869
935
  IsNotEmpty()
870
- ], BuildConfig.prototype, "entryFile", 2);
936
+ ], EditorConfig.prototype, "entry", 2);
871
937
  __decorateClass([
872
938
  Expose(),
873
939
  IsString(),
874
940
  IsNotEmpty()
875
- ], BuildConfig.prototype, "outDir", 2);
876
- var RunConfig = class {
941
+ ], EditorConfig.prototype, "save", 2);
942
+ var DirsConfig = class {
877
943
  static {
878
- __name(this, "RunConfig");
944
+ __name(this, "DirsConfig");
879
945
  }
880
- dir;
946
+ components;
947
+ systems;
881
948
  };
882
949
  __decorateClass([
883
950
  Expose(),
884
951
  IsString(),
885
952
  IsNotEmpty()
886
- ], RunConfig.prototype, "dir", 2);
953
+ ], DirsConfig.prototype, "components", 2);
954
+ __decorateClass([
955
+ Expose(),
956
+ IsString(),
957
+ IsNotEmpty()
958
+ ], DirsConfig.prototype, "systems", 2);
887
959
  var ClientConfig = class {
888
960
  static {
889
961
  __name(this, "ClientConfig");
890
962
  }
963
+ enable;
891
964
  port;
965
+ outDir;
892
966
  build;
893
- runtime;
967
+ editor;
968
+ dirs;
894
969
  };
970
+ __decorateClass([
971
+ Expose(),
972
+ IsBoolean()
973
+ ], ClientConfig.prototype, "enable", 2);
895
974
  __decorateClass([
896
975
  Expose(),
897
976
  IsPort()
898
977
  ], ClientConfig.prototype, "port", 2);
978
+ __decorateClass([
979
+ Expose(),
980
+ IsString(),
981
+ IsNotEmpty()
982
+ ], ClientConfig.prototype, "outDir", 2);
899
983
  __decorateClass([
900
984
  Expose(),
901
985
  Type(() => BuildConfig),
@@ -903,21 +987,33 @@ __decorateClass([
903
987
  ], ClientConfig.prototype, "build", 2);
904
988
  __decorateClass([
905
989
  Expose(),
906
- Type(() => RunConfig),
990
+ Type(() => EditorConfig),
907
991
  ValidateNested()
908
- ], ClientConfig.prototype, "runtime", 2);
992
+ ], ClientConfig.prototype, "editor", 2);
993
+ __decorateClass([
994
+ Expose(),
995
+ Type(() => DirsConfig),
996
+ ValidateNested()
997
+ ], ClientConfig.prototype, "dirs", 2);
909
998
  var ServerConfig = class {
910
999
  static {
911
1000
  __name(this, "ServerConfig");
912
1001
  }
913
1002
  enable;
1003
+ outDir;
914
1004
  build;
915
- runtime;
1005
+ editor;
1006
+ dirs;
916
1007
  };
917
1008
  __decorateClass([
918
1009
  Expose(),
919
1010
  IsBoolean()
920
1011
  ], ServerConfig.prototype, "enable", 2);
1012
+ __decorateClass([
1013
+ Expose(),
1014
+ IsString(),
1015
+ IsNotEmpty()
1016
+ ], ServerConfig.prototype, "outDir", 2);
921
1017
  __decorateClass([
922
1018
  Expose(),
923
1019
  Type(() => BuildConfig),
@@ -925,9 +1021,14 @@ __decorateClass([
925
1021
  ], ServerConfig.prototype, "build", 2);
926
1022
  __decorateClass([
927
1023
  Expose(),
928
- Type(() => RunConfig),
1024
+ Type(() => EditorConfig),
929
1025
  ValidateNested()
930
- ], ServerConfig.prototype, "runtime", 2);
1026
+ ], ServerConfig.prototype, "editor", 2);
1027
+ __decorateClass([
1028
+ Expose(),
1029
+ Type(() => DirsConfig),
1030
+ ValidateNested()
1031
+ ], ServerConfig.prototype, "dirs", 2);
931
1032
  var Config = class {
932
1033
  static {
933
1034
  __name(this, "Config");
@@ -966,13 +1067,12 @@ __decorateClass([
966
1067
  import { plainToInstance } from "class-transformer";
967
1068
  import { validate } from "class-validator";
968
1069
  import { existsSync, readFileSync } from "fs";
969
- import { join as join2 } from "path";
1070
+ import { join as join3 } from "path";
970
1071
 
971
1072
  // src/lib/constants.ts
972
1073
  var CONFIG_FILE_NAME = "nanoforge.config.json";
973
1074
  var MANIFEST_FILE_NAME = "nanoforge.manifest.json";
974
1075
  var GLOBAL_CONFIG_FILE_NAME = ".nanoforgerc";
975
- var NANOFORGE_DIR = ".nanoforge";
976
1076
  var REGISTRY_URL = "https://api.nanoforge.dev";
977
1077
 
978
1078
  // src/lib/utils/object.ts
@@ -1002,23 +1102,36 @@ var CONFIG_DEFAULTS = {
1002
1102
  language: "ts",
1003
1103
  initFunctions: true,
1004
1104
  client: {
1105
+ enable: true,
1005
1106
  port: "3000",
1107
+ outDir: ".nanoforge/client",
1006
1108
  build: {
1007
- entryFile: "client/main.ts",
1008
- outDir: ".nanoforge/client"
1109
+ entry: "client/main.ts",
1110
+ staticDir: "client/static"
1009
1111
  },
1010
- runtime: {
1011
- dir: ".nanoforge/client"
1112
+ editor: {
1113
+ entry: ".nanoforge/editor/client/main.ts",
1114
+ save: ".nanoforge/client.save.json"
1115
+ },
1116
+ dirs: {
1117
+ components: "client/components",
1118
+ systems: "client/systems"
1012
1119
  }
1013
1120
  },
1014
1121
  server: {
1015
1122
  enable: false,
1123
+ outDir: ".nanoforge/server",
1016
1124
  build: {
1017
- entryFile: "server/main.ts",
1018
- outDir: ".nanoforge/server"
1125
+ entry: "server/main.ts",
1126
+ staticDir: "server/static"
1127
+ },
1128
+ editor: {
1129
+ entry: ".nanoforge/editor/server/main.ts",
1130
+ save: ".nanoforge/server.save.json"
1019
1131
  },
1020
- runtime: {
1021
- dir: ".nanoforge/server"
1132
+ dirs: {
1133
+ components: "server/components",
1134
+ systems: "server/systems"
1022
1135
  }
1023
1136
  }
1024
1137
  };
@@ -1027,23 +1140,23 @@ var CONFIG_DEFAULTS = {
1027
1140
  var config;
1028
1141
  var getConfigPath = /* @__PURE__ */ __name((directory, name) => {
1029
1142
  if (name) {
1030
- return join2(directory, name);
1143
+ return join3(directory, name);
1031
1144
  } else {
1032
1145
  for (const n of [CONFIG_FILE_NAME]) {
1033
- const path = join2(directory, n);
1146
+ const path = join3(directory, n);
1034
1147
  if (existsSync(path)) return path;
1035
1148
  }
1036
1149
  throw new Error(`No config file found in directory: ${directory}`);
1037
1150
  }
1038
1151
  }, "getConfigPath");
1039
- var loadConfig = /* @__PURE__ */ __name(async (directory, name) => {
1152
+ var loadConfig = /* @__PURE__ */ __name(async (directory, name, noThrow = false) => {
1040
1153
  if (config) return config;
1041
1154
  let rawData;
1042
1155
  const path = getConfigPath(directory, name);
1043
1156
  try {
1044
1157
  rawData = deepMerge(CONFIG_DEFAULTS, JSON.parse(readFileSync(path, "utf-8")));
1045
1158
  } catch {
1046
- rawData = null;
1159
+ rawData = noThrow ? CONFIG_DEFAULTS : null;
1047
1160
  }
1048
1161
  if (!rawData) throw new Error(`Not able to read config file : ${path}`);
1049
1162
  const data = plainToInstance(Config, rawData, {
@@ -1058,8 +1171,8 @@ ${errors.toString().replace(/,/g, "\n")}`);
1058
1171
  }, "loadConfig");
1059
1172
 
1060
1173
  // src/action/common/config.ts
1061
- var getConfig = /* @__PURE__ */ __name((inputs, dir) => {
1062
- return loadConfig(dir, getConfigInput(inputs));
1174
+ var getConfig = /* @__PURE__ */ __name((inputs, dir, noThrow) => {
1175
+ return loadConfig(dir, getConfigInput(inputs), noThrow);
1063
1176
  }, "getConfig");
1064
1177
 
1065
1178
  // src/action/abstract.action.ts
@@ -1106,40 +1219,53 @@ var BuildAction = class extends AbstractAction {
1106
1219
  async handle(_args, options) {
1107
1220
  const directory = getDirectoryInput(options);
1108
1221
  const config2 = await getConfig(options, directory);
1222
+ const isEditor = getEditorInput(options);
1109
1223
  const isWatch = getWatchInput(options);
1110
- const targets = this.resolveTargets(config2, options);
1224
+ const targets = this.resolveTargets(config2, options, isEditor);
1111
1225
  const results = await this.buildAll(targets, directory, isWatch);
1112
1226
  if (isWatch) {
1113
1227
  return this.enterWatchMode();
1114
1228
  }
1115
1229
  return { success: results.every(Boolean) };
1116
1230
  }
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) {
1231
+ resolveTargets(config2, options, isEditor) {
1232
+ const targets = [];
1233
+ if (config2.client.enable)
1234
+ targets.push(
1235
+ this.createTarget(
1236
+ "Client",
1237
+ "browser",
1238
+ getStringInputWithDefault(
1239
+ options,
1240
+ "clientEntry",
1241
+ !isEditor ? config2.client.build.entry : config2.client.editor.entry
1242
+ ),
1243
+ getStringInputWithDefault(options, "clientStaticDir", config2.client.build.staticDir),
1244
+ getStringInputWithDefault(options, "clientOutDir", config2.client.outDir)
1245
+ )
1246
+ );
1247
+ if (config2.server.enable)
1127
1248
  targets.push(
1128
1249
  this.createTarget(
1129
1250
  "Server",
1130
- config2.server.build,
1131
1251
  "node",
1132
- getStringInput(options, "serverDirectory")
1252
+ getStringInputWithDefault(
1253
+ options,
1254
+ "serverEntry",
1255
+ !isEditor ? config2.server.build.entry : config2.server.editor.entry
1256
+ ),
1257
+ getStringInputWithDefault(options, "serverStaticDir", config2.server.build.staticDir),
1258
+ getStringInputWithDefault(options, "serverOutDir", config2.server.outDir)
1133
1259
  )
1134
1260
  );
1135
- }
1136
1261
  return targets;
1137
1262
  }
1138
- createTarget(name, config2, platform, outDirOverride) {
1263
+ createTarget(name, platform, entryFile, staticDir, outDir) {
1139
1264
  return {
1140
1265
  name,
1141
- entry: config2.entryFile,
1142
- output: outDirOverride || config2.outDir,
1266
+ entry: entryFile,
1267
+ static: staticDir,
1268
+ output: outDir,
1143
1269
  platform
1144
1270
  };
1145
1271
  }
@@ -1153,17 +1279,18 @@ var BuildAction = class extends AbstractAction {
1153
1279
  }
1154
1280
  async buildTarget(target, directory, isWatch) {
1155
1281
  const packageManager = PackageManagerFactory.create("local_bun" /* LOCAL_BUN */);
1156
- const executeBuild = /* @__PURE__ */ __name((rebuild = false) => runSafe(
1157
- () => packageManager.build(
1282
+ const executeBuild = /* @__PURE__ */ __name((rebuild = false) => runSafe(() => {
1283
+ this.resetOut(target.output, directory);
1284
+ this.copyFiles(target, directory);
1285
+ return packageManager.build(
1158
1286
  target.name,
1159
1287
  directory,
1160
1288
  target.entry,
1161
1289
  target.output,
1162
1290
  ["--asset-naming", "[name].[ext]", "--target", target.platform],
1163
1291
  rebuild
1164
- ),
1165
- false
1166
- ), "executeBuild");
1292
+ );
1293
+ }, false), "executeBuild");
1167
1294
  if (isWatch) {
1168
1295
  this.watchDirectory(directory, target.entry, () => executeBuild(true));
1169
1296
  }
@@ -1171,7 +1298,7 @@ var BuildAction = class extends AbstractAction {
1171
1298
  return result !== false;
1172
1299
  }
1173
1300
  watchDirectory(directory, entry, onChange) {
1174
- const watchPath = dirname(join3(getCwd(directory), entry));
1301
+ const watchPath = dirname(join4(getCwd(directory), entry));
1175
1302
  watch(watchPath).on("change", onChange);
1176
1303
  }
1177
1304
  enterWatchMode() {
@@ -1180,43 +1307,16 @@ var BuildAction = class extends AbstractAction {
1180
1307
  console.info();
1181
1308
  return { keepAlive: true };
1182
1309
  }
1183
- };
1184
-
1185
- // src/action/actions/dev.action.ts
1186
- var DevAction = class extends AbstractAction {
1187
- static {
1188
- __name(this, "DevAction");
1189
- }
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;
1310
+ resetOut(outDir, directory) {
1311
+ resetFolder(getCwd(join4(directory, outDir)));
1208
1312
  }
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
- });
1313
+ copyFiles(target, directory) {
1314
+ const from = getCwd(join4(directory, target.static));
1315
+ const to = getCwd(join4(directory, target.output));
1316
+ copyFiles(from, to);
1214
1317
  }
1215
1318
  };
1216
1319
 
1217
- // src/action/actions/generate.action.ts
1218
- import { join as join4 } from "path";
1219
-
1220
1320
  // src/lib/schematics/abstract.collection.ts
1221
1321
  var AbstractCollection = class {
1222
1322
  constructor(collection, runner, cwd2) {
@@ -1224,6 +1324,9 @@ var AbstractCollection = class {
1224
1324
  this.runner = runner;
1225
1325
  this.cwd = cwd2;
1226
1326
  }
1327
+ collection;
1328
+ runner;
1329
+ cwd;
1227
1330
  static {
1228
1331
  __name(this, "AbstractCollection");
1229
1332
  }
@@ -1273,6 +1376,16 @@ var NanoforgeCollection = class _NanoforgeCollection extends AbstractCollection
1273
1376
  name: "docker",
1274
1377
  alias: "docker",
1275
1378
  description: "Generate a Dockerfile for the application"
1379
+ },
1380
+ {
1381
+ name: "component",
1382
+ alias: "component",
1383
+ description: "Generate a Component for an application"
1384
+ },
1385
+ {
1386
+ name: "system",
1387
+ alias: "system",
1388
+ description: "Generate a System for an application"
1276
1389
  }
1277
1390
  ];
1278
1391
  constructor(runner, cwd2) {
@@ -1316,6 +1429,7 @@ var CollectionFactory = class {
1316
1429
  var toKebabCase = /* @__PURE__ */ __name((str) => {
1317
1430
  return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
1318
1431
  }, "toKebabCase");
1432
+ var capitalize = /* @__PURE__ */ __name((str) => str.charAt(0).toUpperCase() + str.slice(1), "capitalize");
1319
1433
 
1320
1434
  // src/lib/schematics/schematic.option.ts
1321
1435
  var SchematicOption = class {
@@ -1323,6 +1437,8 @@ var SchematicOption = class {
1323
1437
  this.name = name;
1324
1438
  this.value = value;
1325
1439
  }
1440
+ name;
1441
+ value;
1326
1442
  static {
1327
1443
  __name(this, "SchematicOption");
1328
1444
  }
@@ -1393,7 +1509,72 @@ var mapSchematicOptions = /* @__PURE__ */ __name((inputs) => {
1393
1509
  }, []);
1394
1510
  }, "mapSchematicOptions");
1395
1511
 
1512
+ // src/action/actions/create.action.ts
1513
+ var CreateAction = class extends AbstractAction {
1514
+ static {
1515
+ __name(this, "CreateAction");
1516
+ }
1517
+ startMessage = Messages.CREATE_START;
1518
+ successMessage = Messages.CREATE_SUCCESS;
1519
+ failureMessage = Messages.CREATE_FAILED;
1520
+ async handle(args, options) {
1521
+ const directory = getDirectoryInput(options);
1522
+ const config2 = await getConfig(options, directory, true);
1523
+ const type = getCreateTypeInput(args);
1524
+ const name = await getCreateNameInputOrAsk(options);
1525
+ const isServer = getServerInput(options);
1526
+ const path = getPathInputWithDefault(
1527
+ options,
1528
+ config2[isServer ? "server" : "client"].dirs[type === "component" ? "components" : "systems"]
1529
+ );
1530
+ await this.generateElement(directory, type, {
1531
+ name,
1532
+ directory: path,
1533
+ part: isServer ? "server" : "client",
1534
+ language: config2.language
1535
+ });
1536
+ return {};
1537
+ }
1538
+ async generateElement(directory, type, values) {
1539
+ const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1540
+ await executeSchematic(capitalize(type), collection, type, values);
1541
+ }
1542
+ };
1543
+
1544
+ // src/action/actions/dev.action.ts
1545
+ var DevAction = class extends AbstractAction {
1546
+ static {
1547
+ __name(this, "DevAction");
1548
+ }
1549
+ startMessage = Messages.DEV_START;
1550
+ successMessage = Messages.DEV_SUCCESS;
1551
+ failureMessage = Messages.DEV_FAILED;
1552
+ async handle(_args, options) {
1553
+ const directory = getDirectoryInput(options);
1554
+ const generate = getDevGenerateInput(options);
1555
+ const tasks = this.buildTaskList(directory, generate);
1556
+ await Promise.all(tasks);
1557
+ return { keepAlive: true };
1558
+ }
1559
+ buildTaskList(directory, generate) {
1560
+ const tasks = [];
1561
+ if (generate) {
1562
+ tasks.push(this.runSubCommand("generate", directory, { silent: true }));
1563
+ }
1564
+ tasks.push(this.runSubCommand("build", directory, { silent: true }));
1565
+ tasks.push(this.runSubCommand("start", directory, { silent: false }));
1566
+ return tasks;
1567
+ }
1568
+ async runSubCommand(command, directory, options) {
1569
+ await runSafe(async () => {
1570
+ const packageManager = await PackageManagerFactory.find(directory);
1571
+ await packageManager.runDev(directory, "nf", {}, [command, "--watch"], options.silent);
1572
+ });
1573
+ }
1574
+ };
1575
+
1396
1576
  // src/action/actions/generate.action.ts
1577
+ import { join as join5 } from "path";
1397
1578
  var GenerateAction = class extends AbstractAction {
1398
1579
  static {
1399
1580
  __name(this, "GenerateAction");
@@ -1404,9 +1585,9 @@ var GenerateAction = class extends AbstractAction {
1404
1585
  async handle(_args, options) {
1405
1586
  const directory = getDirectoryInput(options);
1406
1587
  const config2 = await getConfig(options, directory);
1588
+ const isEditor = getEditorInput(options);
1407
1589
  const isWatch = getWatchInput(options);
1408
- const values = this.extractValues(config2);
1409
- await this.generateParts(values, directory, isWatch);
1590
+ await this.generateParts(config2, directory, isEditor, isWatch);
1410
1591
  if (isWatch) {
1411
1592
  return this.enterWatchMode();
1412
1593
  }
@@ -1414,43 +1595,45 @@ var GenerateAction = class extends AbstractAction {
1414
1595
  }
1415
1596
  extractValues(config2) {
1416
1597
  return {
1417
- name: config2.name,
1418
1598
  directory: ".",
1419
1599
  language: config2.language,
1420
- server: config2.server.enable,
1421
1600
  initFunctions: config2.initFunctions
1422
1601
  };
1423
1602
  }
1424
- async generateParts(values, directory, watch3) {
1603
+ async generateParts(config2, directory, isEditor, watch3) {
1425
1604
  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) {
1605
+ const values = this.extractValues(config2);
1606
+ if (config2.client.enable)
1607
+ await executeSchematic(
1608
+ "Client main file",
1609
+ collection,
1610
+ "part-main",
1611
+ {
1612
+ ...values,
1613
+ part: "client",
1614
+ outFile: !isEditor ? config2.client.build.entry : config2.client.editor.entry,
1615
+ saveFile: config2.client.editor.save,
1616
+ editor: isEditor
1617
+ },
1618
+ watch3 ? this.watchPath(directory, values.directory, config2.client.editor.save) : void 0
1619
+ );
1620
+ if (config2.server.enable)
1435
1621
  await executeSchematic(
1436
1622
  "Server main file",
1437
1623
  collection,
1438
1624
  "part-main",
1439
- { ...baseOptions, part: "server" },
1440
- this.watchPath(directory, values.directory, "server")
1625
+ {
1626
+ ...values,
1627
+ part: "server",
1628
+ outFile: !isEditor ? config2.server.build.entry : config2.server.editor.entry,
1629
+ saveFile: config2.server.editor.save,
1630
+ editor: isEditor
1631
+ },
1632
+ this.watchPath(directory, values.directory, config2.server.editor.save)
1441
1633
  );
1442
- }
1443
- }
1444
- baseSchematicOptions(values) {
1445
- return {
1446
- name: values.name,
1447
- directory: values.directory,
1448
- language: values.language,
1449
- initFunctions: values.initFunctions
1450
- };
1451
1634
  }
1452
- watchPath(directory, subDir, part) {
1453
- return join4(getCwd(directory), subDir, NANOFORGE_DIR, `${part}.save.json`);
1635
+ watchPath(directory, subDir, saveFile) {
1636
+ return join5(getCwd(directory), subDir, saveFile);
1454
1637
  }
1455
1638
  enterWatchMode() {
1456
1639
  console.info();
@@ -1461,7 +1644,7 @@ var GenerateAction = class extends AbstractAction {
1461
1644
  };
1462
1645
 
1463
1646
  // src/action/actions/install.action.ts
1464
- import { join as join6 } from "path";
1647
+ import { join as join7 } from "path";
1465
1648
 
1466
1649
  // src/lib/global-config/global-config-handler.ts
1467
1650
  import { read, readUser, write, writeUser } from "rc9";
@@ -1704,8 +1887,8 @@ var concatDeps = /* @__PURE__ */ __name((deps) => {
1704
1887
  }, "concatDeps");
1705
1888
 
1706
1889
  // src/lib/registry/registry.ts
1707
- import fs3 from "fs";
1708
- import { join as join5 } from "path";
1890
+ import fs4 from "fs";
1891
+ import { join as join6 } from "path";
1709
1892
  var Registry = class {
1710
1893
  static {
1711
1894
  __name(this, "Registry");
@@ -1736,9 +1919,9 @@ var Registry = class {
1736
1919
  }
1737
1920
  static async installPackage(client2, manifest, dir) {
1738
1921
  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());
1922
+ const path = join6(dir, this.getTypeSubFolder(manifest.type));
1923
+ fs4.mkdirSync(path, { recursive: true });
1924
+ fs4.writeFileSync(join6(path, manifest._file), await file.bytes());
1742
1925
  }
1743
1926
  static getTypeSubFolder(type) {
1744
1927
  if (type === "component") return "components";
@@ -1750,14 +1933,14 @@ var Registry = class {
1750
1933
  return withAuth(config2.apiKey, force, !headers ? {} : void 0);
1751
1934
  }
1752
1935
  static _getPackageFile(filename, dir) {
1753
- const path = join5(getCwd(dir ?? "."), filename);
1754
- if (!fs3.existsSync(path))
1936
+ const path = join6(getCwd(dir ?? "."), filename);
1937
+ if (!fs4.existsSync(path))
1755
1938
  throw new Error(
1756
- "Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.components`!"
1939
+ "Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.package`!"
1757
1940
  );
1758
1941
  try {
1759
- fs3.accessSync(path, fs3.constants.R_OK);
1760
- return fs3.openAsBlob(path);
1942
+ fs4.accessSync(path, fs4.constants.R_OK);
1943
+ return fs4.openAsBlob(path);
1761
1944
  } catch {
1762
1945
  throw new Error("Cannot read package file, please verify your file permissions!");
1763
1946
  }
@@ -1776,7 +1959,7 @@ var InstallAction = class extends AbstractAction {
1776
1959
  const names = await getInstallNamesInputOrAsk(args);
1777
1960
  const directory = getDirectoryInput(options);
1778
1961
  const isLib = getInstallLibInput(options);
1779
- const isServer = getInstallServerInput(options);
1962
+ const isServer = getServerInput(options);
1780
1963
  return isLib ? this._installLibs(directory, names) : this._installNfPackages(directory, names, isServer);
1781
1964
  }
1782
1965
  async _installLibs(directory, names) {
@@ -1793,7 +1976,7 @@ var InstallAction = class extends AbstractAction {
1793
1976
  return withSpinner(Messages.INSTALL_PACKAGES_IN_PROGRESS, async () => {
1794
1977
  await Registry.install(
1795
1978
  Object.values(deps.nf),
1796
- join6(directory, isServer ? "server" : "client")
1979
+ join7(directory, isServer ? "server" : "client")
1797
1980
  );
1798
1981
  });
1799
1982
  }
@@ -1846,7 +2029,7 @@ var LogoutAction = class extends AbstractAction {
1846
2029
  };
1847
2030
 
1848
2031
  // src/action/actions/new.action.ts
1849
- import { join as join7 } from "path";
2032
+ import { join as join8 } from "path";
1850
2033
  var NewAction = class extends AbstractAction {
1851
2034
  static {
1852
2035
  __name(this, "NewAction");
@@ -1862,7 +2045,7 @@ var NewAction = class extends AbstractAction {
1862
2045
  if (!values.skipInstall) {
1863
2046
  res = await this.installDependencies(
1864
2047
  values.packageManager,
1865
- join7(cwdDirectory, values.directory ?? values.name)
2048
+ join8(cwdDirectory, values.directory ?? values.name)
1866
2049
  );
1867
2050
  }
1868
2051
  return { success: res };
@@ -1870,7 +2053,7 @@ var NewAction = class extends AbstractAction {
1870
2053
  async collectValues(inputs) {
1871
2054
  return {
1872
2055
  name: await getNewNameInputOrAsk(inputs),
1873
- directory: getNewPathInput(inputs),
2056
+ directory: getPathInput(inputs),
1874
2057
  packageManager: await getNewPackageManagerInputOrAsk(inputs),
1875
2058
  language: await getNewLanguageInputOrAsk(inputs),
1876
2059
  strict: await getNewStrictOrAsk(inputs),
@@ -1878,7 +2061,8 @@ var NewAction = class extends AbstractAction {
1878
2061
  initFunctions: getNewInitFunctionsWithDefault(inputs),
1879
2062
  skipInstall: await getNewSkipInstallOrAsk(inputs),
1880
2063
  docker: await getNewDockerOrAsk(inputs),
1881
- lint: getNewLintInput(inputs)
2064
+ lint: getNewLintInput(inputs),
2065
+ editor: getEditorInput(inputs)
1882
2066
  };
1883
2067
  }
1884
2068
  async scaffold(values, directory) {
@@ -1901,14 +2085,17 @@ var NewAction = class extends AbstractAction {
1901
2085
  language: values.language,
1902
2086
  strict: values.strict,
1903
2087
  server: values.server,
1904
- lint: values.lint
2088
+ lint: values.lint,
2089
+ editor: values.editor
1905
2090
  });
1906
2091
  }
1907
2092
  generateConfiguration(collection, values) {
1908
2093
  return executeSchematic("Configuration", collection, "configuration", {
1909
2094
  name: values.name,
1910
- directory: values.directory,
1911
- server: values.server
2095
+ directory: values.directory ?? values.name,
2096
+ server: values.server,
2097
+ language: values.language,
2098
+ initFunctions: values.initFunctions
1912
2099
  });
1913
2100
  }
1914
2101
  async generateClientParts(collection, values) {
@@ -1917,7 +2104,9 @@ var NewAction = class extends AbstractAction {
1917
2104
  ...partOptions,
1918
2105
  server: values.server
1919
2106
  });
1920
- await executeSchematic("Client main file", collection, "part-main", partOptions);
2107
+ await executeSchematic("Client main file", collection, "part-main", {
2108
+ ...partOptions
2109
+ });
1921
2110
  }
1922
2111
  async generateServerParts(collection, values) {
1923
2112
  const partOptions = this.partOptions(values, "server");
@@ -1925,20 +2114,20 @@ var NewAction = class extends AbstractAction {
1925
2114
  ...partOptions,
1926
2115
  server: values.server
1927
2116
  });
1928
- await executeSchematic("Server main file", collection, "part-main", partOptions);
2117
+ await executeSchematic("Server main file", collection, "part-main", {
2118
+ ...partOptions
2119
+ });
1929
2120
  }
1930
2121
  async generateDocker(collection, values) {
1931
2122
  await executeSchematic("Docker", collection, "docker", {
1932
- name: values.name,
1933
- directory: values.directory,
2123
+ directory: values.directory ?? values.name,
1934
2124
  packageManager: values.packageManager
1935
2125
  });
1936
2126
  }
1937
2127
  partOptions(values, part) {
1938
2128
  return {
1939
- name: values.name,
1940
2129
  part,
1941
- directory: values.directory,
2130
+ directory: values.directory ?? values.name,
1942
2131
  language: values.language,
1943
2132
  initFunctions: values.initFunctions
1944
2133
  };
@@ -1996,6 +2185,7 @@ var Manifest = class {
1996
2185
  name;
1997
2186
  type;
1998
2187
  description;
2188
+ tags;
1999
2189
  dependencies;
2000
2190
  publish;
2001
2191
  npmDependencies;
@@ -2017,6 +2207,11 @@ __decorateClass([
2017
2207
  IsString2(),
2018
2208
  IsOptional()
2019
2209
  ], Manifest.prototype, "description", 2);
2210
+ __decorateClass([
2211
+ Expose2(),
2212
+ IsString2({ each: true }),
2213
+ IsOptional()
2214
+ ], Manifest.prototype, "tags", 2);
2020
2215
  __decorateClass([
2021
2216
  Expose2(),
2022
2217
  IsString2({ each: true }),
@@ -2039,10 +2234,10 @@ __decorateClass([
2039
2234
  import { plainToInstance as plainToInstance2 } from "class-transformer";
2040
2235
  import { validate as validate2 } from "class-validator";
2041
2236
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
2042
- import { join as join8 } from "path";
2237
+ import { join as join9 } from "path";
2043
2238
  var getManifestPath = /* @__PURE__ */ __name((directory) => {
2044
2239
  for (const n of [MANIFEST_FILE_NAME]) {
2045
- const path = join8(directory, n);
2240
+ const path = join9(directory, n);
2046
2241
  if (existsSync2(path)) return path;
2047
2242
  }
2048
2243
  throw new Error(`No manifest file found in directory: ${directory}`);
@@ -2085,7 +2280,7 @@ var PublishAction = class extends AbstractAction {
2085
2280
 
2086
2281
  // src/action/actions/start.action.ts
2087
2282
  import dotenv from "dotenv";
2088
- import { join as join9, resolve as resolve3 } from "path";
2283
+ import { join as join10, resolve as resolve3 } from "path";
2089
2284
  var StartAction = class extends AbstractAction {
2090
2285
  static {
2091
2286
  __name(this, "StartAction");
@@ -2096,10 +2291,18 @@ var StartAction = class extends AbstractAction {
2096
2291
  async handle(_args, options) {
2097
2292
  const directory = getDirectoryInput(options);
2098
2293
  const config2 = await getConfig(options, directory);
2294
+ const clientDir = getStringInputWithDefault(options, "clientDir", config2.client.outDir);
2295
+ const serverDir = getStringInputWithDefault(options, "serverDir", config2.server.outDir);
2099
2296
  const watch3 = getWatchInput(options);
2100
2297
  const port = getStringInputWithDefault(options, "port", config2.client.port);
2101
2298
  const ssl = this.resolveSSL(options);
2102
- const tasks = this.buildStartTasks(config2, directory, watch3, port, ssl);
2299
+ const tasks = this.buildStartTasks(config2, directory, {
2300
+ clientDir,
2301
+ serverDir,
2302
+ watch: watch3,
2303
+ port,
2304
+ ssl
2305
+ });
2103
2306
  await Promise.all(tasks);
2104
2307
  return { keepAlive: true };
2105
2308
  }
@@ -2114,13 +2317,16 @@ var StartAction = class extends AbstractAction {
2114
2317
  key
2115
2318
  };
2116
2319
  }
2117
- buildStartTasks(config2, directory, watch3, port, ssl) {
2320
+ buildStartTasks(config2, directory, options) {
2118
2321
  const env2 = this.parseEnv(directory);
2119
2322
  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));
2323
+ const { clientDir, serverDir, watch: watch3, port, ssl } = options;
2324
+ if (config2.server.enable)
2325
+ tasks.push(this.startServer(directory, config2, { serverDir, watch: watch3 }, env2));
2326
+ if (config2.client.enable)
2327
+ tasks.push(
2328
+ this.startClient(directory, config2, { clientDir, serverDir, watch: watch3, port, ssl }, env2)
2329
+ );
2124
2330
  return tasks;
2125
2331
  }
2126
2332
  async startClient(directory, config2, options, env2) {
@@ -2135,14 +2341,14 @@ var StartAction = class extends AbstractAction {
2135
2341
  }
2136
2342
  buildClientParams(directory, config2, options) {
2137
2343
  const params = {
2138
- "-d": getCwd(join9(directory, config2.client.runtime.dir)),
2344
+ "-d": getCwd(join10(directory, options.clientDir)),
2139
2345
  "-p": options.port
2140
2346
  };
2141
2347
  if (options.watch) params["--watch"] = true;
2142
2348
  if (options.watch) {
2143
2349
  params["--watch"] = true;
2144
2350
  if (config2.server.enable) {
2145
- params["--watch-server-dir"] = getCwd(join9(directory, config2.server.runtime.dir));
2351
+ params["--watch-server-dir"] = getCwd(join10(directory, options.serverDir));
2146
2352
  }
2147
2353
  }
2148
2354
  if (options.ssl) {
@@ -2151,9 +2357,9 @@ var StartAction = class extends AbstractAction {
2151
2357
  }
2152
2358
  return this.buildParams(params);
2153
2359
  }
2154
- buildServerParams(directory, config2, options) {
2360
+ buildServerParams(directory, _config, options) {
2155
2361
  const params = {
2156
- "-d": getCwd(join9(directory, config2.server.runtime.dir))
2362
+ "-d": getCwd(join10(directory, options.serverDir))
2157
2363
  };
2158
2364
  if (options.watch) params["--watch"] = true;
2159
2365
  return this.buildParams(params);
@@ -2169,7 +2375,7 @@ var StartAction = class extends AbstractAction {
2169
2375
  ...process.env
2170
2376
  };
2171
2377
  dotenv.config({
2172
- path: resolve3(getCwd(join9(dir, ".env"))),
2378
+ path: resolve3(getCwd(join10(dir, ".env"))),
2173
2379
  processEnv: rawEnv
2174
2380
  });
2175
2381
  const baseEnv = Object.entries(rawEnv).filter(
@@ -2214,6 +2420,7 @@ var AbstractCommand = class {
2214
2420
  constructor(action) {
2215
2421
  this.action = action;
2216
2422
  }
2423
+ action;
2217
2424
  static {
2218
2425
  __name(this, "AbstractCommand");
2219
2426
  }
@@ -2232,12 +2439,17 @@ var BuildCommand = class extends AbstractCommand {
2232
2439
  __name(this, "BuildCommand");
2233
2440
  }
2234
2441
  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) => {
2442
+ 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
2443
  const options = AbstractCommand.mapToInput({
2237
2444
  directory: rawOptions.directory,
2238
2445
  config: rawOptions.config,
2239
- clientDirectory: rawOptions.clientOutDir,
2240
- serverDirectory: rawOptions.serverOutDir,
2446
+ clientEntry: rawOptions.clientEntry,
2447
+ serverEntry: rawOptions.serverEntry,
2448
+ clientStaticDir: rawOptions.clientStaticDir,
2449
+ serverStaticDir: rawOptions.serverStaticDir,
2450
+ clientOutDir: rawOptions.clientOutDir,
2451
+ serverOutDir: rawOptions.serverOutDir,
2452
+ editor: rawOptions.editor,
2241
2453
  watch: rawOptions.watch
2242
2454
  });
2243
2455
  await this.action.run(/* @__PURE__ */ new Map(), options);
@@ -2245,6 +2457,35 @@ var BuildCommand = class extends AbstractCommand {
2245
2457
  }
2246
2458
  };
2247
2459
 
2460
+ // src/command/commands/create.command.ts
2461
+ var CreateCommand = class extends AbstractCommand {
2462
+ static {
2463
+ __name(this, "CreateCommand");
2464
+ }
2465
+ load(program) {
2466
+ 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(
2467
+ "-s, --server",
2468
+ "install components/systems on server (default install on client)",
2469
+ false
2470
+ ).option(
2471
+ "-p, --path [path]",
2472
+ "path to the component/system folder (default: [part]/<components|systems>)"
2473
+ ).action(async (type, rawOptions) => {
2474
+ const args = AbstractCommand.mapToInput({
2475
+ type
2476
+ });
2477
+ const options = AbstractCommand.mapToInput({
2478
+ directory: rawOptions.directory,
2479
+ config: rawOptions.config,
2480
+ name: rawOptions.name,
2481
+ server: rawOptions.server,
2482
+ path: rawOptions.path
2483
+ });
2484
+ await this.action.run(args, options);
2485
+ });
2486
+ }
2487
+ };
2488
+
2248
2489
  // src/command/commands/dev.command.ts
2249
2490
  var DevCommand = class extends AbstractCommand {
2250
2491
  static {
@@ -2268,10 +2509,11 @@ var GenerateCommand = class extends AbstractCommand {
2268
2509
  __name(this, "GenerateCommand");
2269
2510
  }
2270
2511
  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) => {
2512
+ 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
2513
  const options = AbstractCommand.mapToInput({
2273
2514
  directory: rawOptions.directory,
2274
2515
  config: rawOptions.config,
2516
+ editor: rawOptions.editor,
2275
2517
  watch: rawOptions.watch
2276
2518
  });
2277
2519
  await this.action.run(/* @__PURE__ */ new Map(), options);
@@ -2345,7 +2587,7 @@ var NewCommand = class extends AbstractCommand {
2345
2587
  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
2588
  "--path [path]",
2347
2589
  "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) => {
2590
+ ).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").action(async (rawOptions) => {
2349
2591
  const options = AbstractCommand.mapToInput({
2350
2592
  directory: rawOptions.directory,
2351
2593
  name: rawOptions.name,
@@ -2357,7 +2599,8 @@ var NewCommand = class extends AbstractCommand {
2357
2599
  initFunctions: rawOptions.initFunctions,
2358
2600
  skipInstall: rawOptions.skipInstall,
2359
2601
  docker: rawOptions.docker,
2360
- lint: rawOptions.lint
2602
+ lint: rawOptions.lint,
2603
+ editor: rawOptions.editor
2361
2604
  });
2362
2605
  await this.action.run(/* @__PURE__ */ new Map(), options);
2363
2606
  });
@@ -2385,11 +2628,13 @@ var StartCommand = class extends AbstractCommand {
2385
2628
  __name(this, "StartCommand");
2386
2629
  }
2387
2630
  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) => {
2631
+ 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
2632
  const options = AbstractCommand.mapToInput({
2390
2633
  directory: rawOptions.directory,
2391
2634
  config: rawOptions.config,
2392
2635
  port: rawOptions.port,
2636
+ clientDir: rawOptions.clientDir,
2637
+ serverDir: rawOptions.serverDir,
2393
2638
  watch: rawOptions.watch,
2394
2639
  cert: rawOptions.cert,
2395
2640
  key: rawOptions.key
@@ -2426,6 +2671,7 @@ var CommandLoader = class {
2426
2671
  new StartCommand(new StartAction()).load(program);
2427
2672
  new DevCommand(new DevAction()).load(program);
2428
2673
  new GenerateCommand(new GenerateAction()).load(program);
2674
+ new CreateCommand(new CreateAction()).load(program);
2429
2675
  new LoginCommand(new LoginAction()).load(program);
2430
2676
  new LogoutCommand(new LogoutAction()).load(program);
2431
2677
  new PublishCommand(new PublishAction()).load(program);