@evitcastudio/kit 3.1.1 → 3.2.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.
Files changed (40) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +224 -123
  3. package/lib/bundle/cli/cli.js +905 -154
  4. package/lib/bundle/cli/kit-game-templates/multi/_gitignore +180 -180
  5. package/lib/bundle/cli/kit-game-templates/multi/package.json +3 -3
  6. package/lib/bundle/cli/kit-game-templates/multi/resource.json +1 -0
  7. package/lib/bundle/cli/kit-game-templates/multi/src/client/packets/s-packets.ts +4 -4
  8. package/lib/bundle/cli/kit-game-templates/multi/src/server/packets/c-packets.ts +4 -4
  9. package/lib/bundle/cli/kit-game-templates/single/_gitignore +180 -180
  10. package/lib/bundle/cli/kit-game-templates/single/package.json +3 -3
  11. package/lib/bundle/cli/kit-game-templates/single/resource.json +1 -0
  12. package/lib/cli/app-bundler.d.ts +29 -0
  13. package/lib/cli/app-bundler.d.ts.map +1 -0
  14. package/lib/cli/app-bundler.js +230 -0
  15. package/lib/cli/create.d.ts +11 -0
  16. package/lib/cli/create.d.ts.map +1 -0
  17. package/lib/cli/create.js +88 -0
  18. package/lib/cli/doctor.d.ts +9 -0
  19. package/lib/cli/doctor.d.ts.map +1 -0
  20. package/lib/cli/doctor.js +179 -0
  21. package/lib/cli/host.d.ts +49 -0
  22. package/lib/cli/host.d.ts.map +1 -0
  23. package/lib/cli/host.js +127 -0
  24. package/lib/cli/init.d.ts +2 -0
  25. package/lib/cli/init.d.ts.map +1 -1
  26. package/lib/cli/init.js +42 -15
  27. package/lib/cli/main.d.ts +22 -1
  28. package/lib/cli/main.d.ts.map +1 -1
  29. package/lib/cli/main.js +28 -1
  30. package/lib/cli/resource-builder.d.ts +1 -1
  31. package/lib/cli/resource-builder.d.ts.map +1 -1
  32. package/lib/cli/resource-builder.js +139 -19
  33. package/lib/cli/types.d.ts +12 -6
  34. package/lib/cli/types.d.ts.map +1 -1
  35. package/lib/types/vylo.d.ts +3848 -3848
  36. package/lib/vendor/vyi/index.js +26 -26
  37. package/package.json +73 -73
  38. package/lib/bundle/cli/kit-game-templates/multi/bun-build.ts +0 -109
  39. package/lib/bundle/cli/kit-game-templates/single/bun-build.ts +0 -33
  40. package/lib/bundle/cli/kit-game-templates/single/bun-serve.ts +0 -28
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
+ // @bun
2
3
 
3
4
  /*!
4
- * @evitcastudio/kit@3.1.1 git+https://github.com/EvitcaStudio/Kit.git
5
- * Compiled Fri, 26 Jun 2026 23:30:10 UTC
5
+ * @evitcastudio/kit@3.2.1 git+https://github.com/EvitcaStudio/Kit.git
6
+ * Compiled Wed, 09 Sep 2026 08:34:23 UTC
6
7
  * Copyright (c) 2026 Jared Bates, Evitca Studio, "doubleactii"
7
8
  *
8
9
  * @evitcastudio/kit is licensed under the MIT License.
9
10
  * http://www.opensource.org/licenses/mit-license
10
11
  */
11
- import { createRequire } from "node:module";
12
12
  var __create = Object.create;
13
13
  var __getProtoOf = Object.getPrototypeOf;
14
14
  var __defProp = Object.defineProperty;
@@ -26,7 +26,6 @@ var __toESM = (mod, isNodeMode, target) => {
26
26
  return to;
27
27
  };
28
28
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
29
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
30
29
 
31
30
  // node_modules/commander/lib/error.js
32
31
  var require_error = __commonJS((exports) => {
@@ -351,7 +350,7 @@ var require_help = __commonJS((exports) => {
351
350
  return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
352
351
  }
353
352
  wrap(str, width, indent, minColumnWidth = 40) {
354
- const indents = " \\f\\t\\v   -    \uFEFF";
353
+ const indents = " \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF";
355
354
  const manualIndent = new RegExp(`[\\n][${indents}]+`);
356
355
  if (str.match(manualIndent))
357
356
  return str;
@@ -363,7 +362,7 @@ var require_help = __commonJS((exports) => {
363
362
  `, `
364
363
  `);
365
364
  const indentString = " ".repeat(indent);
366
- const zeroWidthSpace = "";
365
+ const zeroWidthSpace = "\u200B";
367
366
  const breaks = `\\s${zeroWidthSpace}`;
368
367
  const regex = new RegExp(`
369
368
  |.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`, "g");
@@ -606,11 +605,11 @@ var require_suggestSimilar = __commonJS((exports) => {
606
605
 
607
606
  // node_modules/commander/lib/command.js
608
607
  var require_command = __commonJS((exports) => {
609
- var EventEmitter = __require("node:events").EventEmitter;
610
- var childProcess = __require("node:child_process");
611
- var path = __require("node:path");
612
- var fs = __require("node:fs");
613
- var process2 = __require("node:process");
608
+ var EventEmitter = import.meta.require("events").EventEmitter;
609
+ var childProcess = import.meta.require("child_process");
610
+ var path = import.meta.require("path");
611
+ var fs = import.meta.require("fs");
612
+ var process2 = import.meta.require("process");
614
613
  var { Argument, humanReadableArgName } = require_argument();
615
614
  var { CommanderError } = require_error();
616
615
  var { Help } = require_help();
@@ -1943,8 +1942,8 @@ var {
1943
1942
  } = import__.default;
1944
1943
 
1945
1944
  // src/cli/resource-builder.ts
1946
- import { promises as fs } from "fs";
1947
- import { join, extname, basename } from "path";
1945
+ import { promises as fs2, watch as fsWatch, existsSync as existsSync2 } from "fs";
1946
+ import { join as join2, extname as extname2, basename, resolve } from "path";
1948
1947
 
1949
1948
  // node_modules/chalk/source/vendor/ansi-styles/index.js
1950
1949
  var ANSI_BACKGROUND_OFFSET = 10;
@@ -2124,9 +2123,9 @@ var ansiStyles = assembleStyles();
2124
2123
  var ansi_styles_default = ansiStyles;
2125
2124
 
2126
2125
  // node_modules/chalk/source/vendor/supports-color/index.js
2127
- import process2 from "node:process";
2128
- import os from "node:os";
2129
- import tty from "node:tty";
2126
+ import process2 from "process";
2127
+ import os from "os";
2128
+ import tty from "tty";
2130
2129
  function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
2131
2130
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
2132
2131
  const position = argv.indexOf(prefix + flag);
@@ -2475,19 +2474,19 @@ function v4(options, buf, offset) {
2475
2474
  }
2476
2475
  var v4_default = v4;
2477
2476
  // src/vendor/vyi/index.js
2478
- /*!
2479
- * vyi@4.1.0 https://github.com/EvitcaStudio/vyi
2480
- * Compiled Sun, 21 Jun 2026 10:57:24 UTC
2481
- * Copyright (c) 2026 Evitca Studio, "doubleactii"
2482
- *
2483
- * vyi is privately licensed.
2477
+ /*!
2478
+ * vyi@4.1.0 https://github.com/EvitcaStudio/vyi
2479
+ * Compiled Sun, 21 Jun 2026 10:57:24 UTC
2480
+ * Copyright (c) 2026 Evitca Studio, "doubleactii"
2481
+ *
2482
+ * vyi is privately licensed.
2484
2483
  */
2485
- /*!
2486
- * logger@1.0.0 https://github.com/EvitcaStudio/Logger
2487
- * Compiled Mon, 10 Nov 2025 05:36:23 UTC
2488
- * Copyright (c) 2025 Evitca Studio, "doubleactii"
2489
- *
2490
- * logger is privately licensed.
2484
+ /*!
2485
+ * logger@1.0.0 https://github.com/EvitcaStudio/Logger
2486
+ * Compiled Mon, 10 Nov 2025 05:36:23 UTC
2487
+ * Copyright (c) 2025 Evitca Studio, "doubleactii"
2488
+ *
2489
+ * logger is privately licensed.
2491
2490
  */
2492
2491
 
2493
2492
  class Logger {
@@ -2758,19 +2757,19 @@ class Frame {
2758
2757
  return frameData;
2759
2758
  }
2760
2759
  }
2761
- /*!
2762
- * icon-point@2.1.0 https://github.com/EvitcaStudio/IconPoint
2763
- * Compiled Mon, 10 Nov 2025 09:52:21 UTC
2764
- * Copyright (c) 2025 Evitca Studio, "doubleactii"
2765
- *
2766
- * icon-point is privately licensed.
2760
+ /*!
2761
+ * icon-point@2.1.0 https://github.com/EvitcaStudio/IconPoint
2762
+ * Compiled Mon, 10 Nov 2025 09:52:21 UTC
2763
+ * Copyright (c) 2025 Evitca Studio, "doubleactii"
2764
+ *
2765
+ * icon-point is privately licensed.
2767
2766
  */
2768
- /*!
2769
- * logger@1.0.0 https://github.com/EvitcaStudio/Logger
2770
- * Compiled Mon, 10 Nov 2025 05:36:23 UTC
2771
- * Copyright (c) 2025 Evitca Studio, "doubleactii"
2772
- *
2773
- * logger is privately licensed.
2767
+ /*!
2768
+ * logger@1.0.0 https://github.com/EvitcaStudio/Logger
2769
+ * Compiled Mon, 10 Nov 2025 05:36:23 UTC
2770
+ * Copyright (c) 2025 Evitca Studio, "doubleactii"
2771
+ *
2772
+ * logger is privately licensed.
2774
2773
  */
2775
2774
 
2776
2775
  class Logger2 {
@@ -7987,6 +7986,209 @@ class WorkerPool {
7987
7986
  }
7988
7987
  }
7989
7988
 
7989
+ // src/cli/app-bundler.ts
7990
+ import { promises as fs, existsSync } from "fs";
7991
+ import { join, dirname, extname } from "path";
7992
+ var Bun2 = globalThis.Bun;
7993
+ function detectArchitecture(pSrcDir) {
7994
+ const hasClientEntry = existsSync(join(pSrcDir, "client", "index.ts"));
7995
+ const hasServerEntry = existsSync(join(pSrcDir, "server", "index.ts"));
7996
+ const hasSingleEntry = existsSync(join(pSrcDir, "index.ts"));
7997
+ if (hasClientEntry || hasServerEntry) {
7998
+ return "multi";
7999
+ }
8000
+ if (hasSingleEntry) {
8001
+ return "single";
8002
+ }
8003
+ return "none";
8004
+ }
8005
+ async function copyDirectoryRecursive(pSourceDir, pDestDir) {
8006
+ if (!existsSync(pSourceDir))
8007
+ return;
8008
+ const entries = await fs.readdir(pSourceDir, { withFileTypes: true });
8009
+ await fs.mkdir(pDestDir, { recursive: true });
8010
+ for (const entry of entries) {
8011
+ const srcPath = join(pSourceDir, entry.name);
8012
+ const destPath = join(pDestDir, entry.name);
8013
+ if (entry.isDirectory()) {
8014
+ await copyDirectoryRecursive(srcPath, destPath);
8015
+ } else {
8016
+ await fs.copyFile(srcPath, destPath);
8017
+ }
8018
+ }
8019
+ }
8020
+ async function copyStaticWebFiles(pSourceDir, pDestDir, pBaseDir) {
8021
+ if (!existsSync(pSourceDir))
8022
+ return;
8023
+ const entries = await fs.readdir(pSourceDir, { withFileTypes: true });
8024
+ for (const entry of entries) {
8025
+ const fullPath = join(pSourceDir, entry.name);
8026
+ if (entry.isDirectory()) {
8027
+ if (entry.name === "vendor" || entry.name === "resources" || entry.name === "node_modules") {
8028
+ continue;
8029
+ }
8030
+ await copyStaticWebFiles(fullPath, pDestDir, pBaseDir);
8031
+ } else {
8032
+ const ext = extname(entry.name).toLowerCase();
8033
+ if ([".html", ".css", ".ico"].includes(ext)) {
8034
+ const relativePath = fullPath.slice(pBaseDir.length).replace(/^[/\\]+/, "");
8035
+ const targetPath = join(pDestDir, relativePath);
8036
+ await fs.mkdir(dirname(targetPath), { recursive: true });
8037
+ await fs.copyFile(fullPath, targetPath);
8038
+ }
8039
+ }
8040
+ }
8041
+ }
8042
+ async function bundleApp(pProjectRoot, pOutDir, pOptions = {}) {
8043
+ const srcDir = join(pProjectRoot, "src");
8044
+ const architecture = detectArchitecture(srcDir);
8045
+ const isVerbose = Boolean(pOptions.verbose);
8046
+ if (architecture === "none") {
8047
+ if (isVerbose) {
8048
+ console.log(source_default.yellow("[Kit CLI] No application entrypoint detected (src/index.ts or src/client/index.ts). Skipping code bundle."));
8049
+ }
8050
+ return { architecture: "none", success: true };
8051
+ }
8052
+ const isProd = Boolean(pOptions.prod);
8053
+ const shouldMinify = isProd || Boolean(pOptions.minify);
8054
+ const shouldObfuscate = isProd || Boolean(pOptions.obfuscate);
8055
+ const sourcemapMode = pOptions.sourcemap ?? (isProd ? "none" : "linked");
8056
+ let banner = "";
8057
+ const pkgPath = join(pProjectRoot, "package.json");
8058
+ if (existsSync(pkgPath)) {
8059
+ try {
8060
+ const pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"));
8061
+ banner = [
8062
+ "/*!",
8063
+ ` * ${pkg.name || "game"}@${pkg.version || "1.0.0"}`,
8064
+ ` * Compiled ${new Date().toUTCString().replace(/GMT/g, "UTC")}`,
8065
+ " *",
8066
+ ` * ${pkg.name || "game"} is privately licensed. All rights reserved.`,
8067
+ ` * Author: ${pkg.author ?? "Unnamed"}`,
8068
+ " */"
8069
+ ].join(`
8070
+ `);
8071
+ } catch {
8072
+ }
8073
+ }
8074
+ try {
8075
+ if (architecture === "single") {
8076
+ const startStamp = Date.now();
8077
+ const clientResult = await Bun2.build({
8078
+ entrypoints: [join(srcDir, "index.ts")],
8079
+ naming: "index.js",
8080
+ outdir: pOutDir,
8081
+ target: "browser",
8082
+ banner,
8083
+ sourcemap: sourcemapMode,
8084
+ minify: shouldMinify ? {
8085
+ identifiers: shouldObfuscate,
8086
+ syntax: true,
8087
+ whitespace: true
8088
+ } : false
8089
+ });
8090
+ if (!clientResult.success) {
8091
+ console.error(clientResult.logs);
8092
+ throw new AggregateError(clientResult.logs, "Client build failed");
8093
+ }
8094
+ await copyStaticWebFiles(srcDir, pOutDir, srcDir);
8095
+ const rootFavicon = join(pProjectRoot, "favicon.ico");
8096
+ if (existsSync(rootFavicon)) {
8097
+ await fs.copyFile(rootFavicon, join(pOutDir, "favicon.ico"));
8098
+ }
8099
+ const vendorDir = join(srcDir, "vendor");
8100
+ if (existsSync(vendorDir)) {
8101
+ await copyDirectoryRecursive(vendorDir, join(pOutDir, "vendor"));
8102
+ }
8103
+ const elapsed = Date.now() - startStamp;
8104
+ if (isVerbose) {
8105
+ console.log(source_default.hex("#ffa552")(`[Kit CLI] Singleplayer Client Build took: ${elapsed}ms`));
8106
+ }
8107
+ return { architecture: "single", clientBuildTime: elapsed, success: true };
8108
+ }
8109
+ if (architecture === "multi") {
8110
+ const clientEntry = join(srcDir, "client", "index.ts");
8111
+ const serverEntry = join(srcDir, "server", "index.ts");
8112
+ let clientElapsed = 0;
8113
+ let serverElapsed = 0;
8114
+ if (existsSync(clientEntry)) {
8115
+ const clientStart = Date.now();
8116
+ const clientResult = await Bun2.build({
8117
+ entrypoints: [clientEntry],
8118
+ naming: "index.js",
8119
+ outdir: pOutDir,
8120
+ target: "browser",
8121
+ banner,
8122
+ sourcemap: sourcemapMode,
8123
+ minify: shouldMinify ? {
8124
+ identifiers: shouldObfuscate,
8125
+ syntax: true,
8126
+ whitespace: true
8127
+ } : false
8128
+ });
8129
+ if (!clientResult.success) {
8130
+ console.error(clientResult.logs);
8131
+ throw new AggregateError(clientResult.logs, "Multiplayer client build failed");
8132
+ }
8133
+ const clientSrc = join(srcDir, "client");
8134
+ await copyStaticWebFiles(clientSrc, pOutDir, clientSrc);
8135
+ const clientVendor = join(clientSrc, "vendor");
8136
+ if (existsSync(clientVendor)) {
8137
+ await copyDirectoryRecursive(clientVendor, join(pOutDir, "vendor"));
8138
+ }
8139
+ clientElapsed = Date.now() - clientStart;
8140
+ }
8141
+ if (existsSync(serverEntry)) {
8142
+ const serverStart = Date.now();
8143
+ const serverResult = await Bun2.build({
8144
+ entrypoints: [serverEntry],
8145
+ naming: "server.js",
8146
+ outdir: pOutDir,
8147
+ target: "node",
8148
+ banner,
8149
+ sourcemap: sourcemapMode,
8150
+ minify: shouldMinify ? {
8151
+ identifiers: shouldObfuscate,
8152
+ syntax: true,
8153
+ whitespace: true
8154
+ } : false
8155
+ });
8156
+ if (!serverResult.success) {
8157
+ console.error(serverResult.logs);
8158
+ throw new AggregateError(serverResult.logs, "Multiplayer server build failed");
8159
+ }
8160
+ const settingsFile = join(srcDir, "server", "settings.json");
8161
+ if (existsSync(settingsFile)) {
8162
+ await fs.copyFile(settingsFile, join(pOutDir, "settings.json"));
8163
+ }
8164
+ serverElapsed = Date.now() - serverStart;
8165
+ }
8166
+ const rootFavicon = join(pProjectRoot, "favicon.ico");
8167
+ if (existsSync(rootFavicon)) {
8168
+ await fs.copyFile(rootFavicon, join(pOutDir, "favicon.ico"));
8169
+ }
8170
+ if (isVerbose) {
8171
+ if (clientElapsed) {
8172
+ console.log(source_default.hex("#ffa552")(`[Kit CLI] Multiplayer Client Build took: ${clientElapsed}ms`));
8173
+ }
8174
+ if (serverElapsed) {
8175
+ console.log(source_default.hex("#ffa552")(`[Kit CLI] Multiplayer Server Build took: ${serverElapsed}ms`));
8176
+ }
8177
+ }
8178
+ return {
8179
+ architecture: "multi",
8180
+ clientBuildTime: clientElapsed,
8181
+ serverBuildTime: serverElapsed,
8182
+ success: true
8183
+ };
8184
+ }
8185
+ return { architecture: "none", success: true };
8186
+ } catch (pError) {
8187
+ console.error(source_default.hex("#c42847")(`[Kit CLI Build Error] ${pError}`));
8188
+ return { architecture, success: false };
8189
+ }
8190
+ }
8191
+
7990
8192
  // src/cli/resource-builder.ts
7991
8193
  var log = console.log;
7992
8194
  var info = source_default.hex("#ffa552");
@@ -7999,7 +8201,9 @@ var isVerbose = false;
7999
8201
  var ignoringSound = false;
8000
8202
  var resourceInDirectory = "";
8001
8203
  var resourceOutDirectory = "";
8204
+ var customManifestPath = undefined;
8002
8205
  var resourcesToProcess = [];
8206
+ var subdirectoriesToMirror = [];
8003
8207
  function initializeResourceJSON() {
8004
8208
  return RESOURCE_TYPES.reduce((acc, type) => {
8005
8209
  acc[type] = [];
@@ -8007,7 +8211,7 @@ function initializeResourceJSON() {
8007
8211
  }, {});
8008
8212
  }
8009
8213
  function prepareFileForProcessing(pFilePath) {
8010
- const extension = extname(pFilePath).slice(1);
8214
+ const extension = extname2(pFilePath).slice(1);
8011
8215
  const fileName = basename(pFilePath);
8012
8216
  const resourceIdentifier = `${v4_default()}.vyr`;
8013
8217
  const type = getResourceType(extension);
@@ -8043,13 +8247,19 @@ function getResourceType(pExtension) {
8043
8247
  }
8044
8248
  async function processDirectory(pDirectoryPath) {
8045
8249
  try {
8046
- const contents = await fs.readdir(pDirectoryPath);
8250
+ const contents = await fs2.readdir(pDirectoryPath);
8047
8251
  for (const item of contents) {
8048
- const itemPath = join(pDirectoryPath, item);
8049
- const stats = await fs.stat(itemPath);
8252
+ const itemPath = join2(pDirectoryPath, item);
8253
+ if (resolve(itemPath) === resourceOutDirectory) {
8254
+ continue;
8255
+ }
8256
+ const stats = await fs2.stat(itemPath);
8050
8257
  if (stats.isDirectory()) {
8258
+ if (pDirectoryPath === resourceInDirectory) {
8259
+ subdirectoriesToMirror.push(item);
8260
+ }
8051
8261
  await processDirectory(itemPath);
8052
- } else if (isValidExtension(extname(itemPath).slice(1))) {
8262
+ } else if (isValidExtension(extname2(itemPath).slice(1))) {
8053
8263
  prepareFileForProcessing(itemPath);
8054
8264
  }
8055
8265
  }
@@ -8060,6 +8270,22 @@ async function processDirectory(pDirectoryPath) {
8060
8270
  function isValidExtension(pExtension) {
8061
8271
  return VALID_EXTENSIONS.includes(pExtension);
8062
8272
  }
8273
+ async function mirrorDirectory(pSourceDir, pDestDir) {
8274
+ const entries = await fs2.readdir(pSourceDir, { withFileTypes: true });
8275
+ await fs2.mkdir(pDestDir, { recursive: true });
8276
+ for (const entry of entries) {
8277
+ const srcPath = join2(pSourceDir, entry.name);
8278
+ const destPath = join2(pDestDir, entry.name);
8279
+ if (entry.isDirectory()) {
8280
+ await mirrorDirectory(srcPath, destPath);
8281
+ } else {
8282
+ const ext = extname2(entry.name).slice(1);
8283
+ if (!isValidExtension(ext)) {
8284
+ await fs2.copyFile(srcPath, destPath);
8285
+ }
8286
+ }
8287
+ }
8288
+ }
8063
8289
  async function processAllFiles() {
8064
8290
  try {
8065
8291
  await clearResourceTypeDirectories(`${resourceOutDirectory}/resources`);
@@ -8069,11 +8295,16 @@ async function processAllFiles() {
8069
8295
  if (!resource) {
8070
8296
  throw new Error(`Resource not found for file: ${fileName}`);
8071
8297
  }
8072
- const destination = join(resourceOutDirectory, "resources");
8298
+ const destination = join2(resourceOutDirectory, "resources");
8073
8299
  const resourceName = resource.resourceIdentifier;
8074
8300
  return copyFile(filePath, destination, resourceName);
8075
8301
  });
8076
8302
  await Promise.all(copyOperations);
8303
+ for (const subDir of subdirectoriesToMirror) {
8304
+ const srcPath = join2(resourceInDirectory, subDir);
8305
+ const destPath = join2(resourceOutDirectory, "resources", subDir);
8306
+ await mirrorDirectory(srcPath, destPath);
8307
+ }
8077
8308
  logVerbose(`[Kit CLI] All resources have been processed.`);
8078
8309
  await saveResourceJSON();
8079
8310
  const boundsData = await buildBoundsJSON();
@@ -8093,7 +8324,7 @@ async function buildBoundsJSON() {
8093
8324
  if (type !== "icon")
8094
8325
  continue;
8095
8326
  try {
8096
- const fileBuffer = await fs.readFile(filePath);
8327
+ const fileBuffer = await fs2.readFile(filePath);
8097
8328
  const vyi = new VYI().parse(fileBuffer);
8098
8329
  const atlasName = basename(filePath, ".vyi");
8099
8330
  const atlasEntry = {};
@@ -8134,7 +8365,7 @@ async function buildBoundsJSON() {
8134
8365
  async function saveBoundsJSON(pBoundsData) {
8135
8366
  const filePath = "bounds.json";
8136
8367
  try {
8137
- await fs.writeFile(filePath, JSON.stringify(pBoundsData));
8368
+ await fs2.writeFile(filePath, JSON.stringify(pBoundsData));
8138
8369
  } catch (pError) {
8139
8370
  logError(`[Error] Saving bounds JSON: ${pError}`);
8140
8371
  }
@@ -8145,7 +8376,7 @@ async function buildIconPointsJSON() {
8145
8376
  if (type !== "icon")
8146
8377
  continue;
8147
8378
  try {
8148
- const fileBuffer = await fs.readFile(filePath);
8379
+ const fileBuffer = await fs2.readFile(filePath);
8149
8380
  const vyi = new VYI().parse(fileBuffer);
8150
8381
  const atlasName = basename(filePath, ".vyi");
8151
8382
  const atlasEntry = {};
@@ -8204,7 +8435,7 @@ async function buildIconPointsJSON() {
8204
8435
  async function saveIconPointsJSON(pPointsData) {
8205
8436
  const filePath = "icon-points.json";
8206
8437
  try {
8207
- await fs.writeFile(filePath, JSON.stringify(pPointsData));
8438
+ await fs2.writeFile(filePath, JSON.stringify(pPointsData));
8208
8439
  } catch (pError) {
8209
8440
  logError(`[Error] Saving icon points JSON: ${pError}`);
8210
8441
  }
@@ -8215,7 +8446,7 @@ async function buildSizesJSON() {
8215
8446
  if (type !== "icon")
8216
8447
  continue;
8217
8448
  try {
8218
- const fileBuffer = await fs.readFile(filePath);
8449
+ const fileBuffer = await fs2.readFile(filePath);
8219
8450
  const vyi = new VYI().parse(fileBuffer);
8220
8451
  const atlasName = basename(filePath, ".vyi");
8221
8452
  const atlasEntry = {};
@@ -8237,16 +8468,16 @@ async function buildSizesJSON() {
8237
8468
  async function saveSizesJSON(pSizesData) {
8238
8469
  const filePath = "sizes.json";
8239
8470
  try {
8240
- await fs.writeFile(filePath, JSON.stringify(pSizesData));
8471
+ await fs2.writeFile(filePath, JSON.stringify(pSizesData));
8241
8472
  } catch (pError) {
8242
8473
  logError(`[Error] Saving sizes JSON: ${pError}`);
8243
8474
  }
8244
8475
  }
8245
8476
  async function clearResourceTypeDirectories(pBaseDirectory) {
8246
8477
  try {
8247
- const directoryExists = await fs.stat(pBaseDirectory).then((stat) => stat.isDirectory()).catch(() => false);
8478
+ const directoryExists = await fs2.stat(pBaseDirectory).then((stat) => stat.isDirectory()).catch(() => false);
8248
8479
  if (directoryExists) {
8249
- await fs.rm(pBaseDirectory, { recursive: true });
8480
+ await fs2.rm(pBaseDirectory, { recursive: true });
8250
8481
  }
8251
8482
  } catch (pError) {
8252
8483
  log(`${error(`[Error]`)} clearing resource directory: ${pError}`);
@@ -8254,33 +8485,32 @@ async function clearResourceTypeDirectories(pBaseDirectory) {
8254
8485
  }
8255
8486
  async function copyFile(pSource, pDestinationDir, pNewName) {
8256
8487
  try {
8257
- await fs.mkdir(pDestinationDir, { recursive: true });
8258
- await fs.copyFile(pSource, join(pDestinationDir, pNewName));
8488
+ await fs2.mkdir(pDestinationDir, { recursive: true });
8489
+ await fs2.copyFile(pSource, join2(pDestinationDir, pNewName));
8259
8490
  } catch (pError) {
8260
8491
  logError(`[Error] Copying file ${pSource}: ${pError}`);
8261
8492
  }
8262
8493
  }
8263
8494
  async function saveResourceJSON() {
8264
- const filePath = "resource.json";
8495
+ const jsonContent = JSON.stringify(resourceJSON, null, 4);
8496
+ const targetPath = customManifestPath || "resource.json";
8265
8497
  try {
8266
- await fs.writeFile(filePath, JSON.stringify(resourceJSON, null, 4));
8498
+ await fs2.writeFile(targetPath, jsonContent, "utf8");
8267
8499
  } catch (pError) {
8268
- logError(`[Error] Saving resource JSON: ${pError}`);
8500
+ logError(`[Error] Saving resource JSON to ${targetPath}: ${pError}`);
8269
8501
  }
8270
8502
  }
8271
- async function processResources({ inDirectory, outDirectory, verbose, ignoreSound }) {
8272
- resourceInDirectory = inDirectory;
8273
- resourceOutDirectory = outDirectory;
8274
- isVerbose = verbose;
8275
- ignoringSound = ignoreSound;
8503
+ var shouldBundleApp = false;
8504
+ var projectRootDirectory = "";
8505
+ var appBundleOptions = {};
8506
+ async function runBuild() {
8276
8507
  resourceJSON = initializeResourceJSON();
8277
8508
  resourcesToProcess.length = 0;
8278
- if (!resourceInDirectory || !resourceOutDirectory) {
8279
- logError("[Error] Input and output directories must be specified");
8280
- return;
8509
+ subdirectoriesToMirror.length = 0;
8510
+ if (existsSync2(resourceInDirectory)) {
8511
+ await processDirectory(resourceInDirectory);
8281
8512
  }
8282
- await processDirectory(resourceInDirectory);
8283
- if (resourcesToProcess.length > 0) {
8513
+ if (resourcesToProcess.length > 0 || subdirectoriesToMirror.length > 0) {
8284
8514
  await processAllFiles();
8285
8515
  } else {
8286
8516
  logAlert("No resources found!");
@@ -8289,6 +8519,79 @@ async function processResources({ inDirectory, outDirectory, verbose, ignoreSoun
8289
8519
  await saveIconPointsJSON({});
8290
8520
  await saveSizesJSON({});
8291
8521
  }
8522
+ if (shouldBundleApp && projectRootDirectory) {
8523
+ await bundleApp(projectRootDirectory, resourceOutDirectory, {
8524
+ ...appBundleOptions,
8525
+ verbose: Boolean(isVerbose)
8526
+ });
8527
+ }
8528
+ logVerbose(`[Kit CLI] Resources built successfully.`);
8529
+ }
8530
+ async function runWatch() {
8531
+ await runBuild();
8532
+ console.log(source_default.cyan(`
8533
+ \uD83D\uDC40 Watching for changes in: ${source_default.bold(resourceInDirectory)}`));
8534
+ let debounceTimer = null;
8535
+ const triggerRebuild = (pFilename) => {
8536
+ if (debounceTimer)
8537
+ clearTimeout(debounceTimer);
8538
+ debounceTimer = setTimeout(async () => {
8539
+ console.log(source_default.dim(`
8540
+ File changed: ${pFilename}, rebuilding...`));
8541
+ await runBuild();
8542
+ }, 150);
8543
+ };
8544
+ const watchers = [];
8545
+ if (existsSync2(resourceInDirectory)) {
8546
+ const resWatcher = fsWatch(resourceInDirectory, { recursive: true }, (_eventType, pFilename) => {
8547
+ if (pFilename)
8548
+ triggerRebuild(pFilename);
8549
+ });
8550
+ watchers.push(resWatcher);
8551
+ }
8552
+ const srcDir = join2(projectRootDirectory, "src");
8553
+ if (shouldBundleApp && existsSync2(srcDir) && srcDir !== resourceInDirectory) {
8554
+ const srcWatcher = fsWatch(srcDir, { recursive: true }, (_eventType, pFilename) => {
8555
+ if (!pFilename)
8556
+ return;
8557
+ if (pFilename.startsWith("resources"))
8558
+ return;
8559
+ triggerRebuild(pFilename);
8560
+ });
8561
+ watchers.push(srcWatcher);
8562
+ }
8563
+ process.on("SIGINT", () => {
8564
+ for (const w of watchers)
8565
+ w.close();
8566
+ process.exit(0);
8567
+ });
8568
+ }
8569
+ async function processResources({ inDirectory, outDirectory, manifestPath, watch, verbose, ignoreSound, app, minify, obfuscate, sourcemap, prod }) {
8570
+ projectRootDirectory = process.cwd();
8571
+ const resolvedIn = inDirectory || (existsSync2(join2(projectRootDirectory, "src", "resources")) ? "src/resources" : "");
8572
+ const resolvedOut = outDirectory || "dist";
8573
+ resourceInDirectory = resolvedIn ? resolve(resolvedIn) : "";
8574
+ resourceOutDirectory = resolvedOut ? resolve(resolvedOut) : "";
8575
+ customManifestPath = manifestPath;
8576
+ isVerbose = verbose;
8577
+ ignoringSound = ignoreSound;
8578
+ appBundleOptions = {
8579
+ minify,
8580
+ obfuscate,
8581
+ sourcemap,
8582
+ prod
8583
+ };
8584
+ const hasAppEntry = existsSync2(join2(projectRootDirectory, "src", "index.ts")) || existsSync2(join2(projectRootDirectory, "src", "client", "index.ts")) || existsSync2(join2(projectRootDirectory, "src", "server", "index.ts"));
8585
+ shouldBundleApp = app !== undefined ? app : hasAppEntry;
8586
+ if (!resourceInDirectory || !resourceOutDirectory) {
8587
+ logError("[Error] Input and output directories must be specified");
8588
+ return;
8589
+ }
8590
+ if (watch) {
8591
+ await runWatch();
8592
+ } else {
8593
+ await runBuild();
8594
+ }
8292
8595
  }
8293
8596
  function logVerbose(pMessage) {
8294
8597
  if (isVerbose)
@@ -8303,11 +8606,11 @@ function logAlert(pMessage) {
8303
8606
 
8304
8607
  // node_modules/@clack/core/dist/index.mjs
8305
8608
  var import_sisteransi = __toESM(require_src(), 1);
8306
- import { styleText as D } from "node:util";
8307
- import { stdout as R, stdin as q } from "node:process";
8308
- import * as k from "node:readline";
8309
- import ot from "node:readline";
8310
- import { ReadStream as J } from "node:tty";
8609
+ import { styleText as D } from "util";
8610
+ import { stdout as R, stdin as q } from "process";
8611
+ import * as k from "readline";
8612
+ import ot from "readline";
8613
+ import { ReadStream as J } from "tty";
8311
8614
  function x(t, e, s) {
8312
8615
  if (!s.some((u) => !u.disabled))
8313
8616
  return t;
@@ -8391,7 +8694,7 @@ var X = (t, e = {}, s = {}) => {
8391
8694
  var pt = { limit: 1 / 0, ellipsis: "", ellipsisWidth: 0 };
8392
8695
  var S = (t, e = {}) => X(t, pt, e).width;
8393
8696
  var T = "\x1B";
8394
- var Z = "›";
8697
+ var Z = "\x9B";
8395
8698
  var Ft = 39;
8396
8699
  var j = "\x07";
8397
8700
  var Q = "[";
@@ -8712,7 +9015,7 @@ class Vt extends B {
8712
9015
  if (!this.userInput)
8713
9016
  return D(["inverse", "hidden"], "_");
8714
9017
  if (this._cursor >= this.userInput.length)
8715
- return `${this.userInput}█`;
9018
+ return `${this.userInput}\u2588`;
8716
9019
  const e = this.userInput.slice(0, this._cursor), [s, ...i] = this.userInput.slice(this._cursor);
8717
9020
  return `${e}${D("inverse", s)}${i.join("")}`;
8718
9021
  }
@@ -8855,7 +9158,7 @@ class $t extends B {
8855
9158
  return this.userInput;
8856
9159
  const e = this.userInput;
8857
9160
  if (this.cursor >= e.length)
8858
- return `${this.userInput}█`;
9161
+ return `${this.userInput}\u2588`;
8859
9162
  const s = e.slice(0, this.cursor), [i, ...r] = e.slice(this.cursor);
8860
9163
  return `${s}${D("inverse", i)}${r.join("")}`;
8861
9164
  }
@@ -8872,8 +9175,8 @@ class $t extends B {
8872
9175
  }
8873
9176
 
8874
9177
  // node_modules/@clack/prompts/dist/index.mjs
8875
- import { styleText as t, stripVTControlCharacters as ue } from "node:util";
8876
- import N2 from "node:process";
9178
+ import { styleText as t, stripVTControlCharacters as ue } from "util";
9179
+ import N2 from "process";
8877
9180
  var import_sisteransi2 = __toESM(require_src(), 1);
8878
9181
  function pt2() {
8879
9182
  return N2.platform !== "win32" ? N2.env.TERM !== "linux" : !!N2.env.CI || !!N2.env.WT_SESSION || !!N2.env.TERMINUS_SUBLIME || N2.env.ConEmuTask === "{cmd::Cmder}" || N2.env.TERM_PROGRAM === "Terminus-Sublime" || N2.env.TERM_PROGRAM === "vscode" || N2.env.TERM === "xterm-256color" || N2.env.TERM === "alacritty" || N2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
@@ -8881,31 +9184,31 @@ function pt2() {
8881
9184
  var ee = pt2();
8882
9185
  var ce = () => process.env.CI === "true";
8883
9186
  var I2 = (e, r) => ee ? e : r;
8884
- var Re = I2("", "*");
8885
- var $e = I2("", "x");
8886
- var de = I2("", "x");
8887
- var V = I2("", "o");
8888
- var he = I2("", "T");
8889
- var h = I2("", "|");
8890
- var x2 = I2("", "");
8891
- var Oe = I2("", "T");
8892
- var Pe = I2("", "");
8893
- var z2 = I2("", ">");
8894
- var H2 = I2("", " ");
8895
- var te = I2("", "[]");
8896
- var U2 = I2("", "[+]");
8897
- var q2 = I2("", "[ ]");
8898
- var Ne = I2("", "");
8899
- var se = I2("", "-");
8900
- var pe = I2("", "+");
8901
- var We = I2("", "+");
8902
- var me = I2("", "+");
8903
- var ge = I2("", "+");
8904
- var Ge = I2("", "+");
8905
- var fe = I2("", "");
8906
- var Fe = I2("", "*");
8907
- var ye = I2("", "!");
8908
- var Ee = I2("", "x");
9187
+ var Re = I2("\u25C6", "*");
9188
+ var $e = I2("\u25A0", "x");
9189
+ var de = I2("\u25B2", "x");
9190
+ var V = I2("\u25C7", "o");
9191
+ var he = I2("\u250C", "T");
9192
+ var h = I2("\u2502", "|");
9193
+ var x2 = I2("\u2514", "\u2014");
9194
+ var Oe = I2("\u2510", "T");
9195
+ var Pe = I2("\u2518", "\u2014");
9196
+ var z2 = I2("\u25CF", ">");
9197
+ var H2 = I2("\u25CB", " ");
9198
+ var te = I2("\u25FB", "[\u2022]");
9199
+ var U2 = I2("\u25FC", "[+]");
9200
+ var q2 = I2("\u25FB", "[ ]");
9201
+ var Ne = I2("\u25AA", "\u2022");
9202
+ var se = I2("\u2500", "-");
9203
+ var pe = I2("\u256E", "+");
9204
+ var We = I2("\u251C", "+");
9205
+ var me = I2("\u256F", "+");
9206
+ var ge = I2("\u2570", "+");
9207
+ var Ge = I2("\u256D", "+");
9208
+ var fe = I2("\u25CF", "\u2022");
9209
+ var Fe = I2("\u25C6", "*");
9210
+ var ye = I2("\u25B2", "!");
9211
+ var Ee = I2("\u25A0", "x");
8909
9212
  var W2 = (e) => {
8910
9213
  switch (e) {
8911
9214
  case "initial":
@@ -9009,7 +9312,7 @@ var Le = (e, r = {}, s = {}) => {
9009
9312
  var Et2 = { limit: 1 / 0, ellipsis: "", ellipsisWidth: 0 };
9010
9313
  var D2 = (e, r = {}) => Le(e, Et2, r).width;
9011
9314
  var ae = "\x1B";
9012
- var je = "›";
9315
+ var je = "\x9B";
9013
9316
  var vt2 = 39;
9014
9317
  var Ce = "\x07";
9015
9318
  var ke = "[";
@@ -9212,7 +9515,7 @@ ${t("gray", f + se.repeat(n + 2) + me)}
9212
9515
  `);
9213
9516
  };
9214
9517
  var Kt = (e) => t("magenta", e);
9215
- var be = ({ indicator: e = "dots", onCancel: r, output: s = process.stdout, cancelMessage: i, errorMessage: a, frames: o = ee ? ["", "", "", ""] : ["", "o", "O", "0"], delay: u = ee ? 80 : 120, signal: l, ...n } = {}) => {
9518
+ var be = ({ indicator: e = "dots", onCancel: r, output: s = process.stdout, cancelMessage: i, errorMessage: a, frames: o = ee ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], delay: u = ee ? 80 : 120, signal: l, ...n } = {}) => {
9216
9519
  const c = ce();
9217
9520
  let p, f, g = false, E = false, $ = "", m, d = performance.now();
9218
9521
  const F = rt(s), y2 = n?.styleFrame ?? Kt, v = (B2) => {
@@ -9269,7 +9572,7 @@ var be = ({ indicator: e = "dots", onCancel: r, output: s = process.stdout, canc
9269
9572
  return E;
9270
9573
  } };
9271
9574
  };
9272
- var ze = { light: I2("", "-"), heavy: I2("", "="), block: I2("", "#") };
9575
+ var ze = { light: I2("\u2500", "-"), heavy: I2("\u2501", "="), block: I2("\u2588", "#") };
9273
9576
  var oe = (e, r) => e.includes(`
9274
9577
  `) ? e.split(`
9275
9578
  `).map((s) => r(s)).join(`
@@ -9347,15 +9650,15 @@ ${l}
9347
9650
  } }).prompt();
9348
9651
 
9349
9652
  // src/cli/init.ts
9350
- import fs2 from "node:fs";
9351
- import path from "node:path";
9352
- import { fileURLToPath } from "node:url";
9353
- import { spawnSync, execSync } from "node:child_process";
9354
- import os2 from "node:os";
9653
+ import fs3 from "fs";
9654
+ import path from "path";
9655
+ import { fileURLToPath } from "url";
9656
+ import { spawnSync, execSync } from "child_process";
9657
+ import os2 from "os";
9355
9658
  // package.json
9356
9659
  var package_default = {
9357
9660
  name: "@evitcastudio/kit",
9358
- version: "3.1.1",
9661
+ version: "3.2.1",
9359
9662
  author: "doubleactii 56242467+doubleactii@users.noreply.github.com (https://evitcastudio.com)",
9360
9663
  main: "./lib/index.js",
9361
9664
  types: "./lib/index.d.ts",
@@ -9455,15 +9758,15 @@ function installBun() {
9455
9758
  }
9456
9759
  }
9457
9760
  function copyTemplate(pSrc, pDest, pProjectName, pVersion, pAuthor) {
9458
- if (!fs2.existsSync(pDest)) {
9459
- fs2.mkdirSync(pDest, { recursive: true });
9761
+ if (!fs3.existsSync(pDest)) {
9762
+ fs3.mkdirSync(pDest, { recursive: true });
9460
9763
  }
9461
- const files = fs2.readdirSync(pSrc);
9764
+ const files = fs3.readdirSync(pSrc);
9462
9765
  for (const file of files) {
9463
9766
  const srcPath = path.join(pSrc, file);
9464
9767
  const destFile = file === "_gitignore" ? ".gitignore" : file;
9465
9768
  const destPath = path.join(pDest, destFile);
9466
- const stats = fs2.statSync(srcPath);
9769
+ const stats = fs3.statSync(srcPath);
9467
9770
  if (stats.isDirectory()) {
9468
9771
  if (file === ".git")
9469
9772
  continue;
@@ -9472,13 +9775,13 @@ function copyTemplate(pSrc, pDest, pProjectName, pVersion, pAuthor) {
9472
9775
  const ext = path.extname(file).toLowerCase();
9473
9776
  const textExtensions = [".ts", ".js", ".json", ".html", ".css", ".md", ".txt"];
9474
9777
  if (textExtensions.includes(ext)) {
9475
- let content = fs2.readFileSync(srcPath, "utf8");
9778
+ let content = fs3.readFileSync(srcPath, "utf8");
9476
9779
  content = content.replace(/{{PROJECT_NAME}}/g, pProjectName);
9477
9780
  content = content.replace(/{{VERSION}}/g, pVersion);
9478
9781
  content = content.replace(/{{PROJECT_AUTHOR}}/g, pAuthor);
9479
- fs2.writeFileSync(destPath, content);
9782
+ fs3.writeFileSync(destPath, content);
9480
9783
  } else {
9481
- fs2.copyFileSync(srcPath, destPath);
9784
+ fs3.copyFileSync(srcPath, destPath);
9482
9785
  }
9483
9786
  }
9484
9787
  }
@@ -9509,7 +9812,9 @@ Note: Kit projects cannot build or run without Bun.`);
9509
9812
  }
9510
9813
  let projectName = pOptions.projectName;
9511
9814
  let gameType = "single";
9512
- if (!pOptions.single && !pOptions.multi && !projectName) {
9815
+ let shouldInstall = Boolean(pOptions.install);
9816
+ const isInteractive = !pOptions.single && !pOptions.multi && !projectName;
9817
+ if (isInteractive) {
9513
9818
  const name = await Zt({
9514
9819
  message: "What is the name of your project?",
9515
9820
  placeholder: "my-amazing-project",
@@ -9538,6 +9843,13 @@ Note: Kit projects cannot build or run without Bun.`);
9538
9843
  process.exit(0);
9539
9844
  }
9540
9845
  gameType = type;
9846
+ const installChoice = await Rt({
9847
+ message: "Install dependencies with Bun now?",
9848
+ initialValue: true
9849
+ });
9850
+ if (!Ct(installChoice)) {
9851
+ shouldInstall = Boolean(installChoice);
9852
+ }
9541
9853
  } else {
9542
9854
  if (pOptions.single)
9543
9855
  gameType = "single";
@@ -9549,32 +9861,38 @@ Note: Kit projects cannot build or run without Bun.`);
9549
9861
  projectName = "kit-project";
9550
9862
  }
9551
9863
  const projectDir = path.join(process.cwd(), projectName);
9552
- if (fs2.existsSync(projectDir)) {
9553
- const overwrite = await Rt({
9554
- message: `Directory ${source_default.cyan(projectName)} already exists. Overwrite?`,
9555
- initialValue: false
9556
- });
9557
- if (Ct(overwrite) || !overwrite) {
9558
- Nt("Installation aborted.");
9559
- process.exit(0);
9864
+ if (fs3.existsSync(projectDir)) {
9865
+ if (isInteractive) {
9866
+ const overwrite = await Rt({
9867
+ message: `Directory ${source_default.cyan(projectName)} already exists. Overwrite?`,
9868
+ initialValue: false
9869
+ });
9870
+ if (Ct(overwrite) || !overwrite) {
9871
+ Nt("Installation aborted.");
9872
+ process.exit(0);
9873
+ }
9874
+ } else if (!pOptions.force) {
9875
+ console.error(source_default.red(`
9876
+ Error: Destination directory '${projectName}' already exists. Use --force (-f) to overwrite.`));
9877
+ process.exit(1);
9560
9878
  }
9561
9879
  }
9562
9880
  const s = be();
9563
9881
  s.start(`Scaffolding ${source_default.cyan(projectName)}...`);
9564
9882
  try {
9565
9883
  const projectPath = path.join(process.cwd(), projectName);
9566
- if (fs2.existsSync(projectPath)) {
9567
- fs2.rmSync(projectPath, { recursive: true, force: true });
9884
+ if (fs3.existsSync(projectPath)) {
9885
+ fs3.rmSync(projectPath, { recursive: true, force: true });
9568
9886
  }
9569
- fs2.mkdirSync(projectPath, { recursive: true });
9887
+ fs3.mkdirSync(projectPath, { recursive: true });
9570
9888
  let templateType = gameType;
9571
9889
  if (gameType === "both")
9572
9890
  templateType = "multi";
9573
9891
  const templatesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "kit-game-templates", templateType);
9574
9892
  const author = getGitUser();
9575
- if (!fs2.existsSync(templatesDir)) {
9893
+ if (!fs3.existsSync(templatesDir)) {
9576
9894
  const localTemplatesDir = path.join(process.cwd(), "kit-game-templates", templateType);
9577
- if (!fs2.existsSync(localTemplatesDir)) {
9895
+ if (!fs3.existsSync(localTemplatesDir)) {
9578
9896
  console.error(source_default.red(`Error: Templates not found at ${templatesDir} or ${localTemplatesDir}`));
9579
9897
  process.exit(1);
9580
9898
  }
@@ -9592,19 +9910,33 @@ Note: Kit projects cannot build or run without Bun.`);
9592
9910
  } catch {
9593
9911
  }
9594
9912
  s.stop(`Project ${source_default.green(projectName)} created!`);
9595
- console.log(`${source_default.cyan("│")}`);
9596
- console.log(`${source_default.cyan("│")} ${source_default.white.bold("Next steps:")}`);
9597
- console.log(`${source_default.cyan("│")} ${source_default.dim("1.")} cd ${source_default.cyan(projectName)}`);
9598
- console.log(`${source_default.cyan("")} ${source_default.dim("2.")} bun install`);
9599
- console.log(`${source_default.cyan("│")} ${source_default.dim("3.")} bun run build`);
9600
- console.log(`${source_default.cyan("")}`);
9913
+ if (shouldInstall) {
9914
+ const installSpinner = be();
9915
+ installSpinner.start("Installing project dependencies with Bun...");
9916
+ const installResult = spawnSync("bun", ["install"], { cwd: projectPath, stdio: "ignore", shell: true });
9917
+ if (installResult.status === 0) {
9918
+ installSpinner.stop(source_default.green("Dependencies installed successfully!"));
9919
+ } else {
9920
+ installSpinner.stop(source_default.yellow("Dependency installation finished with warnings."));
9921
+ }
9922
+ }
9923
+ console.log(`${source_default.cyan("\u2502")}`);
9924
+ console.log(`${source_default.cyan("\u2502")} ${source_default.white.bold("Next steps:")}`);
9925
+ console.log(`${source_default.cyan("\u2502")} ${source_default.dim("1.")} cd ${source_default.cyan(projectName)}`);
9926
+ if (!shouldInstall) {
9927
+ console.log(`${source_default.cyan("\u2502")} ${source_default.dim("2.")} bun install`);
9928
+ console.log(`${source_default.cyan("\u2502")} ${source_default.dim("3.")} bun run build`);
9929
+ } else {
9930
+ console.log(`${source_default.cyan("\u2502")} ${source_default.dim("2.")} bun run build`);
9931
+ }
9932
+ console.log(`${source_default.cyan("\u2502")}`);
9601
9933
  Gt(source_default.green.bold("Happy coding!"));
9602
9934
  } catch (pError) {
9603
9935
  s.stop(source_default.red("Scaffolding failed."));
9604
9936
  if (projectName) {
9605
9937
  const projectPath = path.join(process.cwd(), projectName);
9606
- if (fs2.existsSync(projectPath)) {
9607
- fs2.rmSync(projectPath, { recursive: true, force: true });
9938
+ if (fs3.existsSync(projectPath)) {
9939
+ fs3.rmSync(projectPath, { recursive: true, force: true });
9608
9940
  }
9609
9941
  }
9610
9942
  console.error(pError);
@@ -9612,6 +9944,361 @@ Note: Kit projects cannot build or run without Bun.`);
9612
9944
  }
9613
9945
  }
9614
9946
 
9947
+ // src/cli/doctor.ts
9948
+ import { spawnSync as spawnSync2 } from "child_process";
9949
+ import { existsSync as existsSync3, readFileSync } from "fs";
9950
+ import { join as join3 } from "path";
9951
+ async function processDoctor(pOptions = {}) {
9952
+ const isVerbose2 = Boolean(pOptions.verbose);
9953
+ const results = [];
9954
+ console.log(`
9955
+ ${source_default.cyan.bold("Kit Doctor")} ${source_default.dim("-")} Environment & Project Health Check
9956
+ `);
9957
+ const bunCheck = spawnSync2("bun", ["--version"], { encoding: "utf8", shell: true });
9958
+ if (!bunCheck.error && bunCheck.status === 0) {
9959
+ results.push({
9960
+ category: "Runtime",
9961
+ title: "Bun Runtime",
9962
+ passed: true,
9963
+ details: `Installed version v${bunCheck.stdout.trim()}`
9964
+ });
9965
+ } else {
9966
+ results.push({
9967
+ category: "Runtime",
9968
+ title: "Bun Runtime",
9969
+ passed: false,
9970
+ details: "Bun is not installed or not in PATH. Download at https://bun.sh/"
9971
+ });
9972
+ }
9973
+ const gitCheck = spawnSync2("git", ["--version"], { encoding: "utf8", shell: true });
9974
+ if (!gitCheck.error && gitCheck.status === 0) {
9975
+ results.push({
9976
+ category: "VCS",
9977
+ title: "Git Installation",
9978
+ passed: true,
9979
+ details: gitCheck.stdout.trim()
9980
+ });
9981
+ } else {
9982
+ results.push({
9983
+ category: "VCS",
9984
+ title: "Git Installation",
9985
+ passed: false,
9986
+ details: "Git was not found in your PATH."
9987
+ });
9988
+ }
9989
+ const cwd = process.cwd();
9990
+ const pkgPath = join3(cwd, "package.json");
9991
+ const hasPackageJson = existsSync3(pkgPath);
9992
+ if (hasPackageJson) {
9993
+ try {
9994
+ const rawPkg = readFileSync(pkgPath, "utf8");
9995
+ const pkg = JSON.parse(rawPkg);
9996
+ const hasKitDependency = Boolean(pkg.dependencies && pkg.dependencies["@evitcastudio/kit"] || pkg.devDependencies && pkg.devDependencies["@evitcastudio/kit"] || pkg.name === "@evitcastudio/kit");
9997
+ results.push({
9998
+ category: "Project",
9999
+ title: "package.json configuration",
10000
+ passed: true,
10001
+ details: `Project name: ${pkg.name || "unnamed"}`
10002
+ });
10003
+ results.push({
10004
+ category: "Project",
10005
+ title: "Kit framework dependency",
10006
+ passed: hasKitDependency,
10007
+ details: hasKitDependency ? "Found @evitcastudio/kit in project configuration" : "Missing @evitcastudio/kit dependency in package.json"
10008
+ });
10009
+ const isKitCoreRepo = pkg.name === "@evitcastudio/kit";
10010
+ if (!isKitCoreRepo) {
10011
+ const resourcesDir = join3(cwd, "src", "resources");
10012
+ const hasResources = existsSync3(resourcesDir);
10013
+ results.push({
10014
+ category: "Project",
10015
+ title: "Asset Directory (src/resources)",
10016
+ passed: hasResources,
10017
+ details: hasResources ? "Asset directory present" : "src/resources not found"
10018
+ });
10019
+ }
10020
+ const hasClientEntry = existsSync3(join3(cwd, "src", "client", "index.ts"));
10021
+ const hasServerEntry = existsSync3(join3(cwd, "src", "server", "index.ts"));
10022
+ const hasSingleEntry = existsSync3(join3(cwd, "src", "index.ts"));
10023
+ let projectType = "Unknown";
10024
+ if (hasClientEntry && hasServerEntry) {
10025
+ projectType = "Multiplayer (Client & Server)";
10026
+ } else if (hasClientEntry) {
10027
+ projectType = "Multiplayer (Client)";
10028
+ } else if (hasServerEntry) {
10029
+ projectType = "Dedicated Server";
10030
+ } else if (hasSingleEntry) {
10031
+ projectType = "Singleplayer";
10032
+ }
10033
+ results.push({
10034
+ category: "Project",
10035
+ title: "Project Architecture",
10036
+ passed: projectType !== "Unknown" || isKitCoreRepo,
10037
+ details: isKitCoreRepo ? "Kit Core Framework Repository" : `Detected Type: ${projectType}`
10038
+ });
10039
+ } catch {
10040
+ results.push({
10041
+ category: "Project",
10042
+ title: "package.json format",
10043
+ passed: false,
10044
+ details: "package.json is malformed or invalid JSON"
10045
+ });
10046
+ }
10047
+ const buildScript = join3(cwd, "bun-build.ts");
10048
+ const hasBuildScript = existsSync3(buildScript);
10049
+ let hasKitBuildScript = false;
10050
+ try {
10051
+ const rawPkg = readFileSync(pkgPath, "utf8");
10052
+ const pkg = JSON.parse(rawPkg);
10053
+ if (pkg.scripts && typeof pkg.scripts.build === "string" && pkg.scripts.build.includes("kit build")) {
10054
+ hasKitBuildScript = true;
10055
+ }
10056
+ } catch {
10057
+ }
10058
+ const buildPipelinePassed = hasBuildScript || hasKitBuildScript;
10059
+ let buildDetails = "No build pipeline configured";
10060
+ if (hasKitBuildScript && hasBuildScript) {
10061
+ buildDetails = "Kit CLI build pipeline with bun-build.ts present";
10062
+ } else if (hasKitBuildScript) {
10063
+ buildDetails = "Kit CLI native build pipeline configured";
10064
+ } else if (hasBuildScript) {
10065
+ buildDetails = "Legacy bun-build.ts present";
10066
+ }
10067
+ results.push({
10068
+ category: "Project",
10069
+ title: "Build Pipeline",
10070
+ passed: buildPipelinePassed,
10071
+ details: buildDetails
10072
+ });
10073
+ } else {
10074
+ results.push({
10075
+ category: "Project",
10076
+ title: "Project Context",
10077
+ passed: true,
10078
+ details: "Not currently executed inside a Node/Bun project root."
10079
+ });
10080
+ }
10081
+ let allPassed = true;
10082
+ for (const res of results) {
10083
+ const icon = res.passed ? source_default.green("\u2713") : source_default.red("\u2717");
10084
+ const titleText = res.passed ? source_default.white(res.title) : source_default.red.bold(res.title);
10085
+ console.log(` ${icon} [${source_default.cyan(res.category)}] ${titleText}`);
10086
+ if (res.details && (!res.passed || isVerbose2)) {
10087
+ console.log(` ${source_default.dim(res.details)}`);
10088
+ }
10089
+ if (!res.passed) {
10090
+ allPassed = false;
10091
+ }
10092
+ }
10093
+ console.log(`
10094
+ `);
10095
+ if (allPassed) {
10096
+ console.log(` ${source_default.green.bold("All doctor diagnostics passed!")}
10097
+ `);
10098
+ } else {
10099
+ console.log(` ${source_default.yellow.bold("Some issues were detected. Check the items above.")}
10100
+ `);
10101
+ }
10102
+ return allPassed;
10103
+ }
10104
+
10105
+ // src/cli/create.ts
10106
+ import { promises as fs4 } from "fs";
10107
+ import { join as join4 } from "path";
10108
+ function toPascalCase(pName) {
10109
+ return pName.replace(/[-_](\w)/g, (_2, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toUpperCase());
10110
+ }
10111
+ function toKebabCase(pName) {
10112
+ return pName.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
10113
+ }
10114
+ function generatePluginSource(pClassName, pPluginName) {
10115
+ return `import { KitPlugin } from '@evitcastudio/kit';
10116
+
10117
+ /**
10118
+ * ${pClassName} plugin for the Kit framework.
10119
+ */
10120
+ export class ${pClassName} extends KitPlugin {
10121
+ /**
10122
+ * Unique name identifier of the plugin.
10123
+ */
10124
+ readonly name = '${pPluginName}';
10125
+
10126
+ /**
10127
+ * Entry point for custom initialization when the plugin is registered with Kit.
10128
+ */
10129
+ onRegistered(): void {
10130
+ // Initialize plugin logic
10131
+ }
10132
+ }
10133
+ `;
10134
+ }
10135
+ async function processCreate(pOptions) {
10136
+ const { type, name, verbose } = pOptions;
10137
+ if (!type || !name) {
10138
+ console.error(source_default.red(`
10139
+ Error: Both type and name are required. Usage: kit create <type> <name>`));
10140
+ process.exit(1);
10141
+ }
10142
+ const normalizedType = type.toLowerCase();
10143
+ if (normalizedType !== "plugin") {
10144
+ console.error(source_default.red(`
10145
+ Error: Unknown create type '${type}'. Supported types: 'plugin'`));
10146
+ process.exit(1);
10147
+ }
10148
+ const className = toPascalCase(name);
10149
+ const fileName = `${toKebabCase(name)}.ts`;
10150
+ const pluginsDir = join4(process.cwd(), "src", "plugins");
10151
+ const targetPath = join4(pluginsDir, fileName);
10152
+ try {
10153
+ await fs4.mkdir(pluginsDir, { recursive: true });
10154
+ const fileExists = await fs4.stat(targetPath).then(() => true).catch(() => false);
10155
+ if (fileExists) {
10156
+ console.error(source_default.red(`
10157
+ Error: File already exists at ${targetPath}`));
10158
+ process.exit(1);
10159
+ }
10160
+ const sourceCode = generatePluginSource(className, className);
10161
+ await fs4.writeFile(targetPath, sourceCode, "utf8");
10162
+ console.log(`
10163
+ ${source_default.green("\u2713")} Created plugin ${source_default.cyan(className)} at ${source_default.dim(targetPath)}
10164
+ `);
10165
+ if (verbose) {
10166
+ console.log(source_default.dim(sourceCode));
10167
+ }
10168
+ } catch (pError) {
10169
+ const message = pError instanceof Error ? pError.message : String(pError);
10170
+ console.error(source_default.red(`
10171
+ Error creating plugin: ${message}`));
10172
+ process.exit(1);
10173
+ }
10174
+ }
10175
+
10176
+ // src/cli/host.ts
10177
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
10178
+ import { join as join5, resolve as resolve2 } from "path";
10179
+ import { networkInterfaces } from "os";
10180
+ function getNetworkAddress() {
10181
+ const interfaces = networkInterfaces();
10182
+ for (const name of Object.keys(interfaces)) {
10183
+ const netList = interfaces[name];
10184
+ if (!netList)
10185
+ continue;
10186
+ for (const net of netList) {
10187
+ if (net.family === "IPv4" && !net.internal) {
10188
+ return net.address;
10189
+ }
10190
+ }
10191
+ }
10192
+ return "localhost";
10193
+ }
10194
+ async function processHost(pOptions = {}) {
10195
+ const cwd = process.cwd();
10196
+ const defaultPort = 8090;
10197
+ const port = pOptions.port || defaultPort;
10198
+ const distDir = pOptions.directory ? resolve2(pOptions.directory) : join5(cwd, "dist");
10199
+ const architecture = detectArchitecture(join5(cwd, "src"));
10200
+ if (!existsSync4(distDir)) {
10201
+ const message = `Target directory "${distDir}" does not exist. Run "kit build" or use "kit host -b" first.`;
10202
+ console.error(source_default.red(`
10203
+ [Kit Host] ${message}
10204
+ `));
10205
+ return { success: false, message };
10206
+ }
10207
+ if (architecture === "multi") {
10208
+ const serverJsPath = join5(distDir, "server.js");
10209
+ if (!existsSync4(serverJsPath)) {
10210
+ const message = `Cannot host multiplayer project: "${serverJsPath}" was not found. Please compile the server first using "kit build".`;
10211
+ console.error(source_default.red(`
10212
+ [Kit Host] ${message}
10213
+ `));
10214
+ return { success: false, message };
10215
+ }
10216
+ console.log(source_default.cyan(`
10217
+ \uD83C\uDFAE Starting Multiplayer Server from ${source_default.bold(distDir)}...
10218
+ `));
10219
+ let serverSettingsPort = port;
10220
+ const settingsPath = join5(distDir, "settings.json");
10221
+ if (existsSync4(settingsPath)) {
10222
+ try {
10223
+ const settings = JSON.parse(readFileSync2(settingsPath, "utf8"));
10224
+ if (settings.port)
10225
+ serverSettingsPort = Number(settings.port);
10226
+ } catch {
10227
+ }
10228
+ }
10229
+ const proc = Bun.spawn(["node", "server.js"], {
10230
+ cwd: distDir,
10231
+ stdout: "inherit",
10232
+ stderr: "inherit",
10233
+ stdin: "inherit"
10234
+ });
10235
+ console.log(source_default.green(`\u2713 Multiplayer server process spawned (configured port: ${serverSettingsPort})`));
10236
+ process.on("SIGINT", () => {
10237
+ proc.kill();
10238
+ process.exit(0);
10239
+ });
10240
+ process.on("SIGTERM", () => {
10241
+ proc.kill();
10242
+ process.exit(0);
10243
+ });
10244
+ await proc.exited;
10245
+ return { success: true, message: "Multiplayer server finished running." };
10246
+ }
10247
+ const indexPath = join5(distDir, "index.html");
10248
+ if (!existsSync4(indexPath)) {
10249
+ const message = `Missing entrypoint: "${indexPath}" was not found in dist. Run "kit build" or use "kit host -b" to compile.`;
10250
+ console.error(source_default.red(`
10251
+ [Kit Host] ${message}
10252
+ `));
10253
+ return { success: false, message };
10254
+ }
10255
+ const lanIp = getNetworkAddress();
10256
+ const server = Bun.serve({
10257
+ port,
10258
+ async fetch(pReq) {
10259
+ const path2 = new URL(pReq.url).pathname;
10260
+ const target = path2 === "/" ? "/index.html" : decodeURIComponent(path2);
10261
+ const file = Bun.file(join5(distDir, target));
10262
+ if (!await file.exists()) {
10263
+ if (pOptions.verbose) {
10264
+ console.warn(source_default.yellow(`[Kit Host] 404 Not Found: ${target}`));
10265
+ }
10266
+ return new Response("Not Found", { status: 404 });
10267
+ }
10268
+ return new Response(file);
10269
+ }
10270
+ });
10271
+ console.log(source_default.cyan(`
10272
+ \uD83C\uDFAE Kit Game Host Server
10273
+ `));
10274
+ console.log(` ${source_default.bold("Local:")} ${source_default.green(`http://localhost:${server.port}`)}`);
10275
+ if (lanIp !== "localhost") {
10276
+ console.log(` ${source_default.bold("Network:")} ${source_default.green(`http://${lanIp}:${server.port}`)}`);
10277
+ }
10278
+ console.log(source_default.dim(`
10279
+ Serving files from: ${distDir}`));
10280
+ console.log(source_default.dim(`Press Ctrl+C to stop the server
10281
+ `));
10282
+ process.on("SIGINT", () => {
10283
+ console.log(source_default.yellow(`
10284
+ Shutting down host server...`));
10285
+ server.stop();
10286
+ process.exit(0);
10287
+ });
10288
+ process.on("SIGTERM", () => {
10289
+ server.stop();
10290
+ process.exit(0);
10291
+ });
10292
+ return {
10293
+ success: true,
10294
+ message: `Serving files on port ${server.port}`,
10295
+ server: {
10296
+ stop: () => server.stop(),
10297
+ port: server.port
10298
+ }
10299
+ };
10300
+ }
10301
+
9615
10302
  // src/cli/main.ts
9616
10303
  class KitCLI {
9617
10304
  static async processResources(pProcessOptions) {
@@ -9620,6 +10307,15 @@ class KitCLI {
9620
10307
  static async init(pInitOptions) {
9621
10308
  await processInit(pInitOptions);
9622
10309
  }
10310
+ static async doctor(pDoctorOptions = {}) {
10311
+ return await processDoctor(pDoctorOptions);
10312
+ }
10313
+ static async create(pCreateOptions) {
10314
+ await processCreate(pCreateOptions);
10315
+ }
10316
+ static async host(pHostOptions = {}) {
10317
+ return await processHost(pHostOptions);
10318
+ }
9623
10319
  }
9624
10320
 
9625
10321
  // bin/cli.ts
@@ -9682,17 +10378,33 @@ var formatHelp = (pCmd) => {
9682
10378
  }
9683
10379
  }
9684
10380
  const name = pCmd.name();
9685
- if (isRoot || name === "init" || name === "build") {
10381
+ if (isRoot || name === "init" || name === "build" || name === "create" || name === "doctor") {
9686
10382
  output += ` ${source_default.white.bold("Examples:")}
9687
10383
  `;
9688
10384
  if (isRoot || name === "init") {
9689
10385
  output += ` ${source_default.cyan("kit init")}
9690
10386
  `;
9691
- output += ` ${source_default.cyan("kit init my-game --single")}
10387
+ output += ` ${source_default.cyan("kit init my-game --single --install")}
9692
10388
  `;
9693
10389
  }
9694
10390
  if (isRoot || name === "build") {
9695
- output += ` ${source_default.cyan("kit build --in ./src --out ./dist")}
10391
+ output += ` ${source_default.cyan("kit build --in ./src/resources --out ./dist")}
10392
+ `;
10393
+ output += ` ${source_default.cyan("kit build --in ./src/resources --out ./dist --watch")}
10394
+ `;
10395
+ }
10396
+ if (isRoot || name === "create") {
10397
+ output += ` ${source_default.cyan("kit create plugin Inventory")}
10398
+ `;
10399
+ }
10400
+ if (isRoot || name === "doctor") {
10401
+ output += ` ${source_default.cyan("kit doctor")}
10402
+ `;
10403
+ }
10404
+ if (isRoot || name === "host") {
10405
+ output += ` ${source_default.cyan("kit host")}
10406
+ `;
10407
+ output += ` ${source_default.cyan("kit host -p 8080 -b")}
9696
10408
  `;
9697
10409
  }
9698
10410
  if (isRoot) {
@@ -9708,9 +10420,9 @@ var formatHelp = (pCmd) => {
9708
10420
  }
9709
10421
  return output;
9710
10422
  };
9711
- program2.name("cli").version(`${package_default.version}`).description(package_default["cli-description"]).option("-v, --verbose", "Enable verbose mode for debugging", false);
10423
+ program2.name("kit").version(`${package_default.version}`).description(package_default["cli-description"]).option("-v, --verbose", "Enable verbose mode for debugging", false);
9712
10424
  program2.helpInformation = () => formatHelp(program2);
9713
- var initCommand = program2.command("init [name]").description("Initialize a new Kit project").option("-s, --single", "Quick-start a single player project").option("-m, --multi", "Quick-start a multiplayer project").action(async (pName, pCmdOptions) => {
10425
+ var initCommand = program2.command("init [name]").description("Initialize a new Kit project").option("-s, --single", "Quick-start a single player project").option("-m, --multi", "Quick-start a multiplayer project").option("-f, --force", "Force overwrite if destination already exists", false).option("-i, --install", "Automatically install dependencies using Bun", false).action(async (pName, pCmdOptions) => {
9714
10426
  if (pName === "help") {
9715
10427
  console.log(initCommand.helpInformation());
9716
10428
  return;
@@ -9719,31 +10431,70 @@ var initCommand = program2.command("init [name]").description("Initialize a new
9719
10431
  projectName: pName,
9720
10432
  single: pCmdOptions.single,
9721
10433
  multi: pCmdOptions.multi,
10434
+ force: pCmdOptions.force,
10435
+ install: pCmdOptions.install,
9722
10436
  verbose: program2.opts().verbose
9723
10437
  });
9724
10438
  });
9725
10439
  initCommand.helpInformation = () => formatHelp(initCommand);
9726
- var buildCommand = program2.command("build [help]").description("Build resources from the specified directory").option("-i, --in <path>", "Input directory (required)").option("-o, --out <path>", "Output directory (required)").option("-is, --ignore-sound", "Ignore sound files", false).action((pHelp, pCmdOptions) => {
10440
+ var buildCommand = program2.command("build [help]").description("Build resources and bundle game application").option("-i, --in <path>", "Input directory (defaults to ./src/resources)").option("-o, --out <path>", "Output directory (defaults to ./dist)").option("-m, --manifest <path>", "Custom manifest file path").option("-w, --watch", "Watch files for changes and rebuild automatically", false).option("-is, --ignore-sound", "Ignore sound files", false).option("--app", "Bundle game code and static assets (enabled by default when project entrypoints exist)").option("--no-app", "Disable game code bundling and only process resources").option("-p, --prod", "Production build: enables minification, identifier obfuscation, and strips sourcemaps", false).option("--minify", "Minify bundled JavaScript syntax, whitespace, and identifiers", false).option("--obfuscate", "Mangle and obfuscate variable and property identifiers", false).option("--sourcemap <mode>", "Sourcemap generation mode (none, linked, inline, external)").action((pHelp, pCmdOptions) => {
9727
10441
  if (pHelp === "help") {
9728
10442
  console.log(buildCommand.helpInformation());
9729
10443
  return;
9730
10444
  }
9731
10445
  const verbose = program2.opts().verbose;
9732
- if (!pCmdOptions.in || !pCmdOptions.out) {
9733
- console.error(source_default.red(`
9734
- Error: --in and --out are required flags for the build command.`));
9735
- console.log(buildCommand.helpInformation());
9736
- process.exit(1);
9737
- }
9738
10446
  const processOptions = {
9739
10447
  inDirectory: pCmdOptions.in,
9740
10448
  outDirectory: pCmdOptions.out,
10449
+ manifestPath: pCmdOptions.manifest,
10450
+ watch: pCmdOptions.watch || false,
9741
10451
  ignoreSound: pCmdOptions.ignoreSound || false,
10452
+ app: pCmdOptions.app,
10453
+ minify: pCmdOptions.minify || false,
10454
+ obfuscate: pCmdOptions.obfuscate || false,
10455
+ sourcemap: pCmdOptions.sourcemap,
10456
+ prod: pCmdOptions.prod || false,
9742
10457
  verbose: verbose || false
9743
10458
  };
9744
10459
  KitCLI.processResources(processOptions);
9745
10460
  });
9746
10461
  buildCommand.helpInformation = () => formatHelp(buildCommand);
10462
+ var createCommand2 = program2.command("create [type] [name]").description("Generate boilerplate files (e.g. plugin)").action(async (pType, pName) => {
10463
+ if (pType === "help" || !pType || !pName) {
10464
+ console.log(createCommand2.helpInformation());
10465
+ return;
10466
+ }
10467
+ await KitCLI.create({
10468
+ type: pType,
10469
+ name: pName,
10470
+ verbose: program2.opts().verbose
10471
+ });
10472
+ });
10473
+ createCommand2.helpInformation = () => formatHelp(createCommand2);
10474
+ var doctorCommand = program2.command("doctor").description("Inspect environment and game project diagnostics").action(async () => {
10475
+ const allPassed = await KitCLI.doctor({
10476
+ verbose: program2.opts().verbose
10477
+ });
10478
+ if (!allPassed) {
10479
+ process.exitCode = 1;
10480
+ }
10481
+ });
10482
+ doctorCommand.helpInformation = () => formatHelp(doctorCommand);
10483
+ var hostCommand = program2.command("host").description("Host the game application locally").option("-p, --port <number>", "Port to run host server on (default: 8090)", "8090").option("-d, --dir <path>", "Directory to serve (default: ./dist)").option("-b, --build", "Build the project before hosting", false).action(async (pCmdOptions) => {
10484
+ const verbose = program2.opts().verbose;
10485
+ if (pCmdOptions.build) {
10486
+ await KitCLI.processResources({ verbose });
10487
+ }
10488
+ const result = await KitCLI.host({
10489
+ port: Number(pCmdOptions.port) || 8090,
10490
+ directory: pCmdOptions.dir,
10491
+ verbose
10492
+ });
10493
+ if (!result.success) {
10494
+ process.exitCode = 1;
10495
+ }
10496
+ });
10497
+ hostCommand.helpInformation = () => formatHelp(hostCommand);
9747
10498
  program2.command("help [command]").description("Display help for a command").action((pCommandName) => {
9748
10499
  if (pCommandName) {
9749
10500
  const cmd = program2.commands.find((c) => c.name() === pCommandName);