@evitcastudio/kit 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +224 -123
- package/lib/bundle/cli/cli.js +491 -59
- package/lib/bundle/cli/kit-game-templates/multi/_gitignore +180 -180
- package/lib/bundle/cli/kit-game-templates/multi/package.json +3 -3
- package/lib/bundle/cli/kit-game-templates/multi/resource.json +1 -0
- package/lib/bundle/cli/kit-game-templates/multi/src/client/packets/s-packets.ts +4 -4
- package/lib/bundle/cli/kit-game-templates/multi/src/server/packets/c-packets.ts +4 -4
- package/lib/bundle/cli/kit-game-templates/single/_gitignore +180 -180
- package/lib/bundle/cli/kit-game-templates/single/package.json +3 -3
- package/lib/bundle/cli/kit-game-templates/single/resource.json +1 -0
- package/lib/cli/app-bundler.d.ts +29 -0
- package/lib/cli/app-bundler.d.ts.map +1 -0
- package/lib/cli/app-bundler.js +230 -0
- package/lib/cli/create.d.ts +11 -0
- package/lib/cli/create.d.ts.map +1 -0
- package/lib/cli/create.js +88 -0
- package/lib/cli/doctor.d.ts +9 -0
- package/lib/cli/doctor.d.ts.map +1 -0
- package/lib/cli/doctor.js +179 -0
- package/lib/cli/host.d.ts +49 -0
- package/lib/cli/host.d.ts.map +1 -0
- package/lib/cli/host.js +127 -0
- package/lib/cli/init.d.ts +2 -0
- package/lib/cli/init.d.ts.map +1 -1
- package/lib/cli/init.js +42 -15
- package/lib/cli/main.d.ts +22 -1
- package/lib/cli/main.d.ts.map +1 -1
- package/lib/cli/main.js +28 -1
- package/lib/cli/resource-builder.d.ts +1 -1
- package/lib/cli/resource-builder.d.ts.map +1 -1
- package/lib/cli/resource-builder.js +264 -19
- package/lib/cli/types.d.ts +12 -6
- package/lib/cli/types.d.ts.map +1 -1
- package/lib/types/vylo.d.ts +3848 -3848
- package/lib/vendor/vyi/index.js +26 -26
- package/package.json +73 -73
- package/lib/bundle/cli/kit-game-templates/multi/bun-build.ts +0 -109
- package/lib/bundle/cli/kit-game-templates/single/bun-build.ts +0 -33
- package/lib/bundle/cli/kit-game-templates/single/bun-serve.ts +0 -28
package/lib/bundle/cli/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/*!
|
|
4
|
-
* @evitcastudio/kit@3.1.
|
|
5
|
-
* Compiled
|
|
4
|
+
* @evitcastudio/kit@3.1.1 git+https://github.com/EvitcaStudio/Kit.git
|
|
5
|
+
* Compiled Wed, 09 Sep 2026 07:29:03 UTC
|
|
6
6
|
* Copyright (c) 2026 Jared Bates, Evitca Studio, "doubleactii"
|
|
7
7
|
*
|
|
8
8
|
* @evitcastudio/kit is licensed under the MIT License.
|
|
@@ -1943,8 +1943,8 @@ var {
|
|
|
1943
1943
|
} = import__.default;
|
|
1944
1944
|
|
|
1945
1945
|
// src/cli/resource-builder.ts
|
|
1946
|
-
import { promises as fs } from "fs";
|
|
1947
|
-
import { join, extname, basename } from "path";
|
|
1946
|
+
import { promises as fs, watch as fsWatch } from "fs";
|
|
1947
|
+
import { join, extname, basename, resolve } from "path";
|
|
1948
1948
|
|
|
1949
1949
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
1950
1950
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -2475,19 +2475,19 @@ function v4(options, buf, offset) {
|
|
|
2475
2475
|
}
|
|
2476
2476
|
var v4_default = v4;
|
|
2477
2477
|
// 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.
|
|
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.
|
|
2484
2484
|
*/
|
|
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.
|
|
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.
|
|
2491
2491
|
*/
|
|
2492
2492
|
|
|
2493
2493
|
class Logger {
|
|
@@ -2758,19 +2758,19 @@ class Frame {
|
|
|
2758
2758
|
return frameData;
|
|
2759
2759
|
}
|
|
2760
2760
|
}
|
|
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.
|
|
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.
|
|
2767
2767
|
*/
|
|
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.
|
|
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.
|
|
2774
2774
|
*/
|
|
2775
2775
|
|
|
2776
2776
|
class Logger2 {
|
|
@@ -7999,7 +7999,9 @@ var isVerbose = false;
|
|
|
7999
7999
|
var ignoringSound = false;
|
|
8000
8000
|
var resourceInDirectory = "";
|
|
8001
8001
|
var resourceOutDirectory = "";
|
|
8002
|
+
var customManifestPath = undefined;
|
|
8002
8003
|
var resourcesToProcess = [];
|
|
8004
|
+
var subdirectoriesToMirror = [];
|
|
8003
8005
|
function initializeResourceJSON() {
|
|
8004
8006
|
return RESOURCE_TYPES.reduce((acc, type) => {
|
|
8005
8007
|
acc[type] = [];
|
|
@@ -8046,8 +8048,14 @@ async function processDirectory(pDirectoryPath) {
|
|
|
8046
8048
|
const contents = await fs.readdir(pDirectoryPath);
|
|
8047
8049
|
for (const item of contents) {
|
|
8048
8050
|
const itemPath = join(pDirectoryPath, item);
|
|
8051
|
+
if (resolve(itemPath) === resourceOutDirectory) {
|
|
8052
|
+
continue;
|
|
8053
|
+
}
|
|
8049
8054
|
const stats = await fs.stat(itemPath);
|
|
8050
8055
|
if (stats.isDirectory()) {
|
|
8056
|
+
if (pDirectoryPath === resourceInDirectory) {
|
|
8057
|
+
subdirectoriesToMirror.push(item);
|
|
8058
|
+
}
|
|
8051
8059
|
await processDirectory(itemPath);
|
|
8052
8060
|
} else if (isValidExtension(extname(itemPath).slice(1))) {
|
|
8053
8061
|
prepareFileForProcessing(itemPath);
|
|
@@ -8060,6 +8068,22 @@ async function processDirectory(pDirectoryPath) {
|
|
|
8060
8068
|
function isValidExtension(pExtension) {
|
|
8061
8069
|
return VALID_EXTENSIONS.includes(pExtension);
|
|
8062
8070
|
}
|
|
8071
|
+
async function mirrorDirectory(pSourceDir, pDestDir) {
|
|
8072
|
+
const entries = await fs.readdir(pSourceDir, { withFileTypes: true });
|
|
8073
|
+
await fs.mkdir(pDestDir, { recursive: true });
|
|
8074
|
+
for (const entry of entries) {
|
|
8075
|
+
const srcPath = join(pSourceDir, entry.name);
|
|
8076
|
+
const destPath = join(pDestDir, entry.name);
|
|
8077
|
+
if (entry.isDirectory()) {
|
|
8078
|
+
await mirrorDirectory(srcPath, destPath);
|
|
8079
|
+
} else {
|
|
8080
|
+
const ext = extname(entry.name).slice(1);
|
|
8081
|
+
if (!isValidExtension(ext)) {
|
|
8082
|
+
await fs.copyFile(srcPath, destPath);
|
|
8083
|
+
}
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
}
|
|
8063
8087
|
async function processAllFiles() {
|
|
8064
8088
|
try {
|
|
8065
8089
|
await clearResourceTypeDirectories(`${resourceOutDirectory}/resources`);
|
|
@@ -8074,10 +8098,19 @@ async function processAllFiles() {
|
|
|
8074
8098
|
return copyFile(filePath, destination, resourceName);
|
|
8075
8099
|
});
|
|
8076
8100
|
await Promise.all(copyOperations);
|
|
8101
|
+
for (const subDir of subdirectoriesToMirror) {
|
|
8102
|
+
const srcPath = join(resourceInDirectory, subDir);
|
|
8103
|
+
const destPath = join(resourceOutDirectory, "resources", subDir);
|
|
8104
|
+
await mirrorDirectory(srcPath, destPath);
|
|
8105
|
+
}
|
|
8077
8106
|
logVerbose(`[Kit CLI] All resources have been processed.`);
|
|
8078
8107
|
await saveResourceJSON();
|
|
8079
8108
|
const boundsData = await buildBoundsJSON();
|
|
8080
8109
|
await saveBoundsJSON(boundsData);
|
|
8110
|
+
const pointsData = await buildIconPointsJSON();
|
|
8111
|
+
await saveIconPointsJSON(pointsData);
|
|
8112
|
+
const sizesData = await buildSizesJSON();
|
|
8113
|
+
await saveSizesJSON(sizesData);
|
|
8081
8114
|
} catch (pError) {
|
|
8082
8115
|
const errorMessage = pError instanceof Error ? pError.message : String(pError);
|
|
8083
8116
|
logError(`[Error] Processing files in batch: ${errorMessage}`);
|
|
@@ -8130,11 +8163,114 @@ async function buildBoundsJSON() {
|
|
|
8130
8163
|
async function saveBoundsJSON(pBoundsData) {
|
|
8131
8164
|
const filePath = "bounds.json";
|
|
8132
8165
|
try {
|
|
8133
|
-
await fs.writeFile(filePath, JSON.stringify(pBoundsData
|
|
8166
|
+
await fs.writeFile(filePath, JSON.stringify(pBoundsData));
|
|
8134
8167
|
} catch (pError) {
|
|
8135
8168
|
logError(`[Error] Saving bounds JSON: ${pError}`);
|
|
8136
8169
|
}
|
|
8137
8170
|
}
|
|
8171
|
+
async function buildIconPointsJSON() {
|
|
8172
|
+
const pointsData = {};
|
|
8173
|
+
for (const { filePath, type } of resourcesToProcess) {
|
|
8174
|
+
if (type !== "icon")
|
|
8175
|
+
continue;
|
|
8176
|
+
try {
|
|
8177
|
+
const fileBuffer = await fs.readFile(filePath);
|
|
8178
|
+
const vyi = new VYI().parse(fileBuffer);
|
|
8179
|
+
const atlasName = basename(filePath, ".vyi");
|
|
8180
|
+
const atlasEntry = {};
|
|
8181
|
+
for (const icon of vyi.getIcons()) {
|
|
8182
|
+
const iconName = icon.getName();
|
|
8183
|
+
const iconPoints = icon.getIconPointsExport();
|
|
8184
|
+
const hasIconPoints = iconPoints && iconPoints.length > 0;
|
|
8185
|
+
const iconEntry = {};
|
|
8186
|
+
if (hasIconPoints) {
|
|
8187
|
+
const pointsMap = {};
|
|
8188
|
+
for (const pt of iconPoints) {
|
|
8189
|
+
pointsMap[pt.id] = {
|
|
8190
|
+
width: pt.width,
|
|
8191
|
+
height: pt.height,
|
|
8192
|
+
x: pt.x,
|
|
8193
|
+
y: pt.y
|
|
8194
|
+
};
|
|
8195
|
+
}
|
|
8196
|
+
iconEntry.points = pointsMap;
|
|
8197
|
+
}
|
|
8198
|
+
const statesEntry = {};
|
|
8199
|
+
for (const state of icon.getStates()) {
|
|
8200
|
+
const stateName = state.getName();
|
|
8201
|
+
const statePoints = state.getIconPointsExport();
|
|
8202
|
+
if (statePoints && statePoints.length > 0) {
|
|
8203
|
+
const statePointsMap = {};
|
|
8204
|
+
for (const pt of statePoints) {
|
|
8205
|
+
statePointsMap[pt.id] = {
|
|
8206
|
+
width: pt.width,
|
|
8207
|
+
height: pt.height,
|
|
8208
|
+
x: pt.x,
|
|
8209
|
+
y: pt.y
|
|
8210
|
+
};
|
|
8211
|
+
}
|
|
8212
|
+
statesEntry[stateName] = {
|
|
8213
|
+
points: statePointsMap
|
|
8214
|
+
};
|
|
8215
|
+
}
|
|
8216
|
+
}
|
|
8217
|
+
if (Object.keys(statesEntry).length > 0) {
|
|
8218
|
+
iconEntry.states = statesEntry;
|
|
8219
|
+
}
|
|
8220
|
+
if (Object.keys(iconEntry).length > 0) {
|
|
8221
|
+
atlasEntry[iconName] = iconEntry;
|
|
8222
|
+
}
|
|
8223
|
+
}
|
|
8224
|
+
if (Object.keys(atlasEntry).length > 0) {
|
|
8225
|
+
pointsData[atlasName] = atlasEntry;
|
|
8226
|
+
}
|
|
8227
|
+
} catch (pError) {
|
|
8228
|
+
logError(`[Error] Failed to parse icon points from ${filePath}: ${pError}`);
|
|
8229
|
+
}
|
|
8230
|
+
}
|
|
8231
|
+
return pointsData;
|
|
8232
|
+
}
|
|
8233
|
+
async function saveIconPointsJSON(pPointsData) {
|
|
8234
|
+
const filePath = "icon-points.json";
|
|
8235
|
+
try {
|
|
8236
|
+
await fs.writeFile(filePath, JSON.stringify(pPointsData));
|
|
8237
|
+
} catch (pError) {
|
|
8238
|
+
logError(`[Error] Saving icon points JSON: ${pError}`);
|
|
8239
|
+
}
|
|
8240
|
+
}
|
|
8241
|
+
async function buildSizesJSON() {
|
|
8242
|
+
const sizesData = {};
|
|
8243
|
+
for (const { filePath, type } of resourcesToProcess) {
|
|
8244
|
+
if (type !== "icon")
|
|
8245
|
+
continue;
|
|
8246
|
+
try {
|
|
8247
|
+
const fileBuffer = await fs.readFile(filePath);
|
|
8248
|
+
const vyi = new VYI().parse(fileBuffer);
|
|
8249
|
+
const atlasName = basename(filePath, ".vyi");
|
|
8250
|
+
const atlasEntry = {};
|
|
8251
|
+
for (const icon of vyi.getIcons()) {
|
|
8252
|
+
atlasEntry[icon.getName()] = {
|
|
8253
|
+
width: icon.getWidth(),
|
|
8254
|
+
height: icon.getHeight()
|
|
8255
|
+
};
|
|
8256
|
+
}
|
|
8257
|
+
if (Object.keys(atlasEntry).length > 0) {
|
|
8258
|
+
sizesData[atlasName] = atlasEntry;
|
|
8259
|
+
}
|
|
8260
|
+
} catch (pError) {
|
|
8261
|
+
logError(`[Error] Failed to parse sizes from ${filePath}: ${pError}`);
|
|
8262
|
+
}
|
|
8263
|
+
}
|
|
8264
|
+
return sizesData;
|
|
8265
|
+
}
|
|
8266
|
+
async function saveSizesJSON(pSizesData) {
|
|
8267
|
+
const filePath = "sizes.json";
|
|
8268
|
+
try {
|
|
8269
|
+
await fs.writeFile(filePath, JSON.stringify(pSizesData));
|
|
8270
|
+
} catch (pError) {
|
|
8271
|
+
logError(`[Error] Saving sizes JSON: ${pError}`);
|
|
8272
|
+
}
|
|
8273
|
+
}
|
|
8138
8274
|
async function clearResourceTypeDirectories(pBaseDirectory) {
|
|
8139
8275
|
try {
|
|
8140
8276
|
const directoryExists = await fs.stat(pBaseDirectory).then((stat) => stat.isDirectory()).catch(() => false);
|
|
@@ -8154,31 +8290,65 @@ async function copyFile(pSource, pDestinationDir, pNewName) {
|
|
|
8154
8290
|
}
|
|
8155
8291
|
}
|
|
8156
8292
|
async function saveResourceJSON() {
|
|
8157
|
-
const
|
|
8293
|
+
const jsonContent = JSON.stringify(resourceJSON, null, 4);
|
|
8294
|
+
const targetPath = customManifestPath || "resource.json";
|
|
8158
8295
|
try {
|
|
8159
|
-
await fs.writeFile(
|
|
8296
|
+
await fs.writeFile(targetPath, jsonContent, "utf8");
|
|
8160
8297
|
} catch (pError) {
|
|
8161
|
-
logError(`[Error] Saving resource JSON: ${pError}`);
|
|
8298
|
+
logError(`[Error] Saving resource JSON to ${targetPath}: ${pError}`);
|
|
8162
8299
|
}
|
|
8163
8300
|
}
|
|
8164
|
-
async function
|
|
8165
|
-
resourceInDirectory = inDirectory;
|
|
8166
|
-
resourceOutDirectory = outDirectory;
|
|
8167
|
-
isVerbose = verbose;
|
|
8168
|
-
ignoringSound = ignoreSound;
|
|
8301
|
+
async function runBuild() {
|
|
8169
8302
|
resourceJSON = initializeResourceJSON();
|
|
8170
8303
|
resourcesToProcess.length = 0;
|
|
8171
|
-
|
|
8172
|
-
logError("[Error] Input and output directories must be specified");
|
|
8173
|
-
return;
|
|
8174
|
-
}
|
|
8304
|
+
subdirectoriesToMirror.length = 0;
|
|
8175
8305
|
await processDirectory(resourceInDirectory);
|
|
8176
|
-
if (resourcesToProcess.length > 0) {
|
|
8306
|
+
if (resourcesToProcess.length > 0 || subdirectoriesToMirror.length > 0) {
|
|
8177
8307
|
await processAllFiles();
|
|
8178
8308
|
} else {
|
|
8179
8309
|
logAlert("No resources found!");
|
|
8180
8310
|
await saveResourceJSON();
|
|
8181
8311
|
await saveBoundsJSON({});
|
|
8312
|
+
await saveIconPointsJSON({});
|
|
8313
|
+
await saveSizesJSON({});
|
|
8314
|
+
}
|
|
8315
|
+
logVerbose(`[Kit CLI] Resources built successfully.`);
|
|
8316
|
+
}
|
|
8317
|
+
async function runWatch() {
|
|
8318
|
+
await runBuild();
|
|
8319
|
+
console.log(source_default.cyan(`
|
|
8320
|
+
\uD83D\uDC40 Watching for changes in: ${source_default.bold(resourceInDirectory)}`));
|
|
8321
|
+
let debounceTimer = null;
|
|
8322
|
+
const watcher = fsWatch(resourceInDirectory, { recursive: true }, (_eventType, pFilename) => {
|
|
8323
|
+
if (!pFilename)
|
|
8324
|
+
return;
|
|
8325
|
+
if (debounceTimer)
|
|
8326
|
+
clearTimeout(debounceTimer);
|
|
8327
|
+
debounceTimer = setTimeout(async () => {
|
|
8328
|
+
console.log(source_default.dim(`
|
|
8329
|
+
Asset changed: ${pFilename}, rebuilding...`));
|
|
8330
|
+
await runBuild();
|
|
8331
|
+
}, 150);
|
|
8332
|
+
});
|
|
8333
|
+
process.on("SIGINT", () => {
|
|
8334
|
+
watcher.close();
|
|
8335
|
+
process.exit(0);
|
|
8336
|
+
});
|
|
8337
|
+
}
|
|
8338
|
+
async function processResources({ inDirectory, outDirectory, manifestPath, watch, verbose, ignoreSound }) {
|
|
8339
|
+
resourceInDirectory = inDirectory ? resolve(inDirectory) : "";
|
|
8340
|
+
resourceOutDirectory = outDirectory ? resolve(outDirectory) : "";
|
|
8341
|
+
customManifestPath = manifestPath;
|
|
8342
|
+
isVerbose = verbose;
|
|
8343
|
+
ignoringSound = ignoreSound;
|
|
8344
|
+
if (!resourceInDirectory || !resourceOutDirectory) {
|
|
8345
|
+
logError("[Error] Input and output directories must be specified");
|
|
8346
|
+
return;
|
|
8347
|
+
}
|
|
8348
|
+
if (watch) {
|
|
8349
|
+
await runWatch();
|
|
8350
|
+
} else {
|
|
8351
|
+
await runBuild();
|
|
8182
8352
|
}
|
|
8183
8353
|
}
|
|
8184
8354
|
function logVerbose(pMessage) {
|
|
@@ -9246,7 +9416,7 @@ import os2 from "node:os";
|
|
|
9246
9416
|
// package.json
|
|
9247
9417
|
var package_default = {
|
|
9248
9418
|
name: "@evitcastudio/kit",
|
|
9249
|
-
version: "3.1.
|
|
9419
|
+
version: "3.1.1",
|
|
9250
9420
|
author: "doubleactii 56242467+doubleactii@users.noreply.github.com (https://evitcastudio.com)",
|
|
9251
9421
|
main: "./lib/index.js",
|
|
9252
9422
|
types: "./lib/index.d.ts",
|
|
@@ -9400,7 +9570,9 @@ Note: Kit projects cannot build or run without Bun.`);
|
|
|
9400
9570
|
}
|
|
9401
9571
|
let projectName = pOptions.projectName;
|
|
9402
9572
|
let gameType = "single";
|
|
9403
|
-
|
|
9573
|
+
let shouldInstall = Boolean(pOptions.install);
|
|
9574
|
+
const isInteractive = !pOptions.single && !pOptions.multi && !projectName;
|
|
9575
|
+
if (isInteractive) {
|
|
9404
9576
|
const name = await Zt({
|
|
9405
9577
|
message: "What is the name of your project?",
|
|
9406
9578
|
placeholder: "my-amazing-project",
|
|
@@ -9429,6 +9601,13 @@ Note: Kit projects cannot build or run without Bun.`);
|
|
|
9429
9601
|
process.exit(0);
|
|
9430
9602
|
}
|
|
9431
9603
|
gameType = type;
|
|
9604
|
+
const installChoice = await Rt({
|
|
9605
|
+
message: "Install dependencies with Bun now?",
|
|
9606
|
+
initialValue: true
|
|
9607
|
+
});
|
|
9608
|
+
if (!Ct(installChoice)) {
|
|
9609
|
+
shouldInstall = Boolean(installChoice);
|
|
9610
|
+
}
|
|
9432
9611
|
} else {
|
|
9433
9612
|
if (pOptions.single)
|
|
9434
9613
|
gameType = "single";
|
|
@@ -9441,13 +9620,19 @@ Note: Kit projects cannot build or run without Bun.`);
|
|
|
9441
9620
|
}
|
|
9442
9621
|
const projectDir = path.join(process.cwd(), projectName);
|
|
9443
9622
|
if (fs2.existsSync(projectDir)) {
|
|
9444
|
-
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9623
|
+
if (isInteractive) {
|
|
9624
|
+
const overwrite = await Rt({
|
|
9625
|
+
message: `Directory ${source_default.cyan(projectName)} already exists. Overwrite?`,
|
|
9626
|
+
initialValue: false
|
|
9627
|
+
});
|
|
9628
|
+
if (Ct(overwrite) || !overwrite) {
|
|
9629
|
+
Nt("Installation aborted.");
|
|
9630
|
+
process.exit(0);
|
|
9631
|
+
}
|
|
9632
|
+
} else if (!pOptions.force) {
|
|
9633
|
+
console.error(source_default.red(`
|
|
9634
|
+
Error: Destination directory '${projectName}' already exists. Use --force (-f) to overwrite.`));
|
|
9635
|
+
process.exit(1);
|
|
9451
9636
|
}
|
|
9452
9637
|
}
|
|
9453
9638
|
const s = be();
|
|
@@ -9483,11 +9668,25 @@ Note: Kit projects cannot build or run without Bun.`);
|
|
|
9483
9668
|
} catch {
|
|
9484
9669
|
}
|
|
9485
9670
|
s.stop(`Project ${source_default.green(projectName)} created!`);
|
|
9671
|
+
if (shouldInstall) {
|
|
9672
|
+
const installSpinner = be();
|
|
9673
|
+
installSpinner.start("Installing project dependencies with Bun...");
|
|
9674
|
+
const installResult = spawnSync("bun", ["install"], { cwd: projectPath, stdio: "ignore", shell: true });
|
|
9675
|
+
if (installResult.status === 0) {
|
|
9676
|
+
installSpinner.stop(source_default.green("Dependencies installed successfully!"));
|
|
9677
|
+
} else {
|
|
9678
|
+
installSpinner.stop(source_default.yellow("Dependency installation finished with warnings."));
|
|
9679
|
+
}
|
|
9680
|
+
}
|
|
9486
9681
|
console.log(`${source_default.cyan("│")}`);
|
|
9487
9682
|
console.log(`${source_default.cyan("│")} ${source_default.white.bold("Next steps:")}`);
|
|
9488
9683
|
console.log(`${source_default.cyan("│")} ${source_default.dim("1.")} cd ${source_default.cyan(projectName)}`);
|
|
9489
|
-
|
|
9490
|
-
|
|
9684
|
+
if (!shouldInstall) {
|
|
9685
|
+
console.log(`${source_default.cyan("│")} ${source_default.dim("2.")} bun install`);
|
|
9686
|
+
console.log(`${source_default.cyan("│")} ${source_default.dim("3.")} bun run build`);
|
|
9687
|
+
} else {
|
|
9688
|
+
console.log(`${source_default.cyan("│")} ${source_default.dim("2.")} bun run build`);
|
|
9689
|
+
}
|
|
9491
9690
|
console.log(`${source_default.cyan("│")}`);
|
|
9492
9691
|
Gt(source_default.green.bold("Happy coding!"));
|
|
9493
9692
|
} catch (pError) {
|
|
@@ -9503,6 +9702,198 @@ Note: Kit projects cannot build or run without Bun.`);
|
|
|
9503
9702
|
}
|
|
9504
9703
|
}
|
|
9505
9704
|
|
|
9705
|
+
// src/cli/doctor.ts
|
|
9706
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
9707
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9708
|
+
import { join as join2 } from "node:path";
|
|
9709
|
+
async function processDoctor(pOptions = {}) {
|
|
9710
|
+
const isVerbose2 = Boolean(pOptions.verbose);
|
|
9711
|
+
const results = [];
|
|
9712
|
+
console.log(`
|
|
9713
|
+
${source_default.cyan.bold("Kit Doctor")} ${source_default.dim("-")} Environment & Project Health Check
|
|
9714
|
+
`);
|
|
9715
|
+
const bunCheck = spawnSync2("bun", ["--version"], { encoding: "utf8", shell: true });
|
|
9716
|
+
if (!bunCheck.error && bunCheck.status === 0) {
|
|
9717
|
+
results.push({
|
|
9718
|
+
category: "Runtime",
|
|
9719
|
+
title: "Bun Runtime",
|
|
9720
|
+
passed: true,
|
|
9721
|
+
details: `Installed version v${bunCheck.stdout.trim()}`
|
|
9722
|
+
});
|
|
9723
|
+
} else {
|
|
9724
|
+
results.push({
|
|
9725
|
+
category: "Runtime",
|
|
9726
|
+
title: "Bun Runtime",
|
|
9727
|
+
passed: false,
|
|
9728
|
+
details: "Bun is not installed or not in PATH. Download at https://bun.sh/"
|
|
9729
|
+
});
|
|
9730
|
+
}
|
|
9731
|
+
const gitCheck = spawnSync2("git", ["--version"], { encoding: "utf8", shell: true });
|
|
9732
|
+
if (!gitCheck.error && gitCheck.status === 0) {
|
|
9733
|
+
results.push({
|
|
9734
|
+
category: "VCS",
|
|
9735
|
+
title: "Git Installation",
|
|
9736
|
+
passed: true,
|
|
9737
|
+
details: gitCheck.stdout.trim()
|
|
9738
|
+
});
|
|
9739
|
+
} else {
|
|
9740
|
+
results.push({
|
|
9741
|
+
category: "VCS",
|
|
9742
|
+
title: "Git Installation",
|
|
9743
|
+
passed: false,
|
|
9744
|
+
details: "Git was not found in your PATH."
|
|
9745
|
+
});
|
|
9746
|
+
}
|
|
9747
|
+
const cwd = process.cwd();
|
|
9748
|
+
const pkgPath = join2(cwd, "package.json");
|
|
9749
|
+
const hasPackageJson = existsSync(pkgPath);
|
|
9750
|
+
if (hasPackageJson) {
|
|
9751
|
+
try {
|
|
9752
|
+
const rawPkg = readFileSync(pkgPath, "utf8");
|
|
9753
|
+
const pkg = JSON.parse(rawPkg);
|
|
9754
|
+
const hasKitDependency = Boolean(pkg.dependencies && pkg.dependencies["@evitcastudio/kit"] || pkg.devDependencies && pkg.devDependencies["@evitcastudio/kit"] || pkg.name === "@evitcastudio/kit");
|
|
9755
|
+
results.push({
|
|
9756
|
+
category: "Project",
|
|
9757
|
+
title: "package.json configuration",
|
|
9758
|
+
passed: true,
|
|
9759
|
+
details: `Project name: ${pkg.name || "unnamed"}`
|
|
9760
|
+
});
|
|
9761
|
+
results.push({
|
|
9762
|
+
category: "Project",
|
|
9763
|
+
title: "Kit framework dependency",
|
|
9764
|
+
passed: hasKitDependency,
|
|
9765
|
+
details: hasKitDependency ? "Found @evitcastudio/kit in project configuration" : "Missing @evitcastudio/kit dependency in package.json"
|
|
9766
|
+
});
|
|
9767
|
+
const isKitCoreRepo = pkg.name === "@evitcastudio/kit";
|
|
9768
|
+
if (!isKitCoreRepo) {
|
|
9769
|
+
const resourcesDir = join2(cwd, "src", "resources");
|
|
9770
|
+
const hasResources = existsSync(resourcesDir);
|
|
9771
|
+
results.push({
|
|
9772
|
+
category: "Project",
|
|
9773
|
+
title: "Asset Directory (src/resources)",
|
|
9774
|
+
passed: hasResources,
|
|
9775
|
+
details: hasResources ? "Asset directory present" : "src/resources not found"
|
|
9776
|
+
});
|
|
9777
|
+
}
|
|
9778
|
+
} catch {
|
|
9779
|
+
results.push({
|
|
9780
|
+
category: "Project",
|
|
9781
|
+
title: "package.json format",
|
|
9782
|
+
passed: false,
|
|
9783
|
+
details: "package.json is malformed or invalid JSON"
|
|
9784
|
+
});
|
|
9785
|
+
}
|
|
9786
|
+
const buildScript = join2(cwd, "bun-build.ts");
|
|
9787
|
+
const hasBuildScript = existsSync(buildScript);
|
|
9788
|
+
results.push({
|
|
9789
|
+
category: "Project",
|
|
9790
|
+
title: "Build Pipeline (bun-build.ts)",
|
|
9791
|
+
passed: hasBuildScript,
|
|
9792
|
+
details: hasBuildScript ? "Build script present" : "bun-build.ts not found"
|
|
9793
|
+
});
|
|
9794
|
+
} else {
|
|
9795
|
+
results.push({
|
|
9796
|
+
category: "Project",
|
|
9797
|
+
title: "Project Context",
|
|
9798
|
+
passed: true,
|
|
9799
|
+
details: "Not currently executed inside a Node/Bun project root."
|
|
9800
|
+
});
|
|
9801
|
+
}
|
|
9802
|
+
let allPassed = true;
|
|
9803
|
+
for (const res of results) {
|
|
9804
|
+
const icon = res.passed ? source_default.green("✓") : source_default.red("✗");
|
|
9805
|
+
const titleText = res.passed ? source_default.white(res.title) : source_default.red.bold(res.title);
|
|
9806
|
+
console.log(` ${icon} [${source_default.cyan(res.category)}] ${titleText}`);
|
|
9807
|
+
if (res.details && (!res.passed || isVerbose2)) {
|
|
9808
|
+
console.log(` ${source_default.dim(res.details)}`);
|
|
9809
|
+
}
|
|
9810
|
+
if (!res.passed) {
|
|
9811
|
+
allPassed = false;
|
|
9812
|
+
}
|
|
9813
|
+
}
|
|
9814
|
+
console.log(`
|
|
9815
|
+
`);
|
|
9816
|
+
if (allPassed) {
|
|
9817
|
+
console.log(` ${source_default.green.bold("All doctor diagnostics passed!")}
|
|
9818
|
+
`);
|
|
9819
|
+
} else {
|
|
9820
|
+
console.log(` ${source_default.yellow.bold("Some issues were detected. Check the items above.")}
|
|
9821
|
+
`);
|
|
9822
|
+
}
|
|
9823
|
+
return allPassed;
|
|
9824
|
+
}
|
|
9825
|
+
|
|
9826
|
+
// src/cli/create.ts
|
|
9827
|
+
import { promises as fs3 } from "node:fs";
|
|
9828
|
+
import { join as join3 } from "node:path";
|
|
9829
|
+
function toPascalCase(pName) {
|
|
9830
|
+
return pName.replace(/[-_](\w)/g, (_2, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toUpperCase());
|
|
9831
|
+
}
|
|
9832
|
+
function toKebabCase(pName) {
|
|
9833
|
+
return pName.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
9834
|
+
}
|
|
9835
|
+
function generatePluginSource(pClassName, pPluginName) {
|
|
9836
|
+
return `import { KitPlugin } from '@evitcastudio/kit';
|
|
9837
|
+
|
|
9838
|
+
/**
|
|
9839
|
+
* ${pClassName} plugin for the Kit framework.
|
|
9840
|
+
*/
|
|
9841
|
+
export class ${pClassName} extends KitPlugin {
|
|
9842
|
+
/**
|
|
9843
|
+
* Unique name identifier of the plugin.
|
|
9844
|
+
*/
|
|
9845
|
+
readonly name = '${pPluginName}';
|
|
9846
|
+
|
|
9847
|
+
/**
|
|
9848
|
+
* Entry point for custom initialization when the plugin is registered with Kit.
|
|
9849
|
+
*/
|
|
9850
|
+
onRegistered(): void {
|
|
9851
|
+
// Initialize plugin logic
|
|
9852
|
+
}
|
|
9853
|
+
}
|
|
9854
|
+
`;
|
|
9855
|
+
}
|
|
9856
|
+
async function processCreate(pOptions) {
|
|
9857
|
+
const { type, name, verbose } = pOptions;
|
|
9858
|
+
if (!type || !name) {
|
|
9859
|
+
console.error(source_default.red(`
|
|
9860
|
+
Error: Both type and name are required. Usage: kit create <type> <name>`));
|
|
9861
|
+
process.exit(1);
|
|
9862
|
+
}
|
|
9863
|
+
const normalizedType = type.toLowerCase();
|
|
9864
|
+
if (normalizedType !== "plugin") {
|
|
9865
|
+
console.error(source_default.red(`
|
|
9866
|
+
Error: Unknown create type '${type}'. Supported types: 'plugin'`));
|
|
9867
|
+
process.exit(1);
|
|
9868
|
+
}
|
|
9869
|
+
const className = toPascalCase(name);
|
|
9870
|
+
const fileName = `${toKebabCase(name)}.ts`;
|
|
9871
|
+
const pluginsDir = join3(process.cwd(), "src", "plugins");
|
|
9872
|
+
const targetPath = join3(pluginsDir, fileName);
|
|
9873
|
+
try {
|
|
9874
|
+
await fs3.mkdir(pluginsDir, { recursive: true });
|
|
9875
|
+
const fileExists = await fs3.stat(targetPath).then(() => true).catch(() => false);
|
|
9876
|
+
if (fileExists) {
|
|
9877
|
+
console.error(source_default.red(`
|
|
9878
|
+
Error: File already exists at ${targetPath}`));
|
|
9879
|
+
process.exit(1);
|
|
9880
|
+
}
|
|
9881
|
+
const sourceCode = generatePluginSource(className, className);
|
|
9882
|
+
await fs3.writeFile(targetPath, sourceCode, "utf8");
|
|
9883
|
+
console.log(`
|
|
9884
|
+
${source_default.green("✓")} Created plugin ${source_default.cyan(className)} at ${source_default.dim(targetPath)}
|
|
9885
|
+
`);
|
|
9886
|
+
if (verbose) {
|
|
9887
|
+
console.log(source_default.dim(sourceCode));
|
|
9888
|
+
}
|
|
9889
|
+
} catch (pError) {
|
|
9890
|
+
const message = pError instanceof Error ? pError.message : String(pError);
|
|
9891
|
+
console.error(source_default.red(`
|
|
9892
|
+
Error creating plugin: ${message}`));
|
|
9893
|
+
process.exit(1);
|
|
9894
|
+
}
|
|
9895
|
+
}
|
|
9896
|
+
|
|
9506
9897
|
// src/cli/main.ts
|
|
9507
9898
|
class KitCLI {
|
|
9508
9899
|
static async processResources(pProcessOptions) {
|
|
@@ -9511,6 +9902,12 @@ class KitCLI {
|
|
|
9511
9902
|
static async init(pInitOptions) {
|
|
9512
9903
|
await processInit(pInitOptions);
|
|
9513
9904
|
}
|
|
9905
|
+
static async doctor(pDoctorOptions = {}) {
|
|
9906
|
+
return await processDoctor(pDoctorOptions);
|
|
9907
|
+
}
|
|
9908
|
+
static async create(pCreateOptions) {
|
|
9909
|
+
await processCreate(pCreateOptions);
|
|
9910
|
+
}
|
|
9514
9911
|
}
|
|
9515
9912
|
|
|
9516
9913
|
// bin/cli.ts
|
|
@@ -9573,17 +9970,27 @@ var formatHelp = (pCmd) => {
|
|
|
9573
9970
|
}
|
|
9574
9971
|
}
|
|
9575
9972
|
const name = pCmd.name();
|
|
9576
|
-
if (isRoot || name === "init" || name === "build") {
|
|
9973
|
+
if (isRoot || name === "init" || name === "build" || name === "create" || name === "doctor") {
|
|
9577
9974
|
output += ` ${source_default.white.bold("Examples:")}
|
|
9578
9975
|
`;
|
|
9579
9976
|
if (isRoot || name === "init") {
|
|
9580
9977
|
output += ` ${source_default.cyan("kit init")}
|
|
9581
9978
|
`;
|
|
9582
|
-
output += ` ${source_default.cyan("kit init my-game --single")}
|
|
9979
|
+
output += ` ${source_default.cyan("kit init my-game --single --install")}
|
|
9583
9980
|
`;
|
|
9584
9981
|
}
|
|
9585
9982
|
if (isRoot || name === "build") {
|
|
9586
|
-
output += ` ${source_default.cyan("kit build --in ./src --out ./dist")}
|
|
9983
|
+
output += ` ${source_default.cyan("kit build --in ./src/resources --out ./dist")}
|
|
9984
|
+
`;
|
|
9985
|
+
output += ` ${source_default.cyan("kit build --in ./src/resources --out ./dist --watch")}
|
|
9986
|
+
`;
|
|
9987
|
+
}
|
|
9988
|
+
if (isRoot || name === "create") {
|
|
9989
|
+
output += ` ${source_default.cyan("kit create plugin Inventory")}
|
|
9990
|
+
`;
|
|
9991
|
+
}
|
|
9992
|
+
if (isRoot || name === "doctor") {
|
|
9993
|
+
output += ` ${source_default.cyan("kit doctor")}
|
|
9587
9994
|
`;
|
|
9588
9995
|
}
|
|
9589
9996
|
if (isRoot) {
|
|
@@ -9599,9 +10006,9 @@ var formatHelp = (pCmd) => {
|
|
|
9599
10006
|
}
|
|
9600
10007
|
return output;
|
|
9601
10008
|
};
|
|
9602
|
-
program2.name("
|
|
10009
|
+
program2.name("kit").version(`${package_default.version}`).description(package_default["cli-description"]).option("-v, --verbose", "Enable verbose mode for debugging", false);
|
|
9603
10010
|
program2.helpInformation = () => formatHelp(program2);
|
|
9604
|
-
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) => {
|
|
10011
|
+
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) => {
|
|
9605
10012
|
if (pName === "help") {
|
|
9606
10013
|
console.log(initCommand.helpInformation());
|
|
9607
10014
|
return;
|
|
@@ -9610,11 +10017,13 @@ var initCommand = program2.command("init [name]").description("Initialize a new
|
|
|
9610
10017
|
projectName: pName,
|
|
9611
10018
|
single: pCmdOptions.single,
|
|
9612
10019
|
multi: pCmdOptions.multi,
|
|
10020
|
+
force: pCmdOptions.force,
|
|
10021
|
+
install: pCmdOptions.install,
|
|
9613
10022
|
verbose: program2.opts().verbose
|
|
9614
10023
|
});
|
|
9615
10024
|
});
|
|
9616
10025
|
initCommand.helpInformation = () => formatHelp(initCommand);
|
|
9617
|
-
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) => {
|
|
10026
|
+
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("-m, --manifest <path>", "Custom manifest file path").option("-w, --watch", "Watch input directory for changes and rebuild", false).option("-is, --ignore-sound", "Ignore sound files", false).action((pHelp, pCmdOptions) => {
|
|
9618
10027
|
if (pHelp === "help") {
|
|
9619
10028
|
console.log(buildCommand.helpInformation());
|
|
9620
10029
|
return;
|
|
@@ -9629,12 +10038,35 @@ var buildCommand = program2.command("build [help]").description("Build resources
|
|
|
9629
10038
|
const processOptions = {
|
|
9630
10039
|
inDirectory: pCmdOptions.in,
|
|
9631
10040
|
outDirectory: pCmdOptions.out,
|
|
10041
|
+
manifestPath: pCmdOptions.manifest,
|
|
10042
|
+
watch: pCmdOptions.watch || false,
|
|
9632
10043
|
ignoreSound: pCmdOptions.ignoreSound || false,
|
|
9633
10044
|
verbose: verbose || false
|
|
9634
10045
|
};
|
|
9635
10046
|
KitCLI.processResources(processOptions);
|
|
9636
10047
|
});
|
|
9637
10048
|
buildCommand.helpInformation = () => formatHelp(buildCommand);
|
|
10049
|
+
var createCommand2 = program2.command("create [type] [name]").description("Generate boilerplate files (e.g. plugin)").action(async (pType, pName) => {
|
|
10050
|
+
if (pType === "help" || !pType || !pName) {
|
|
10051
|
+
console.log(createCommand2.helpInformation());
|
|
10052
|
+
return;
|
|
10053
|
+
}
|
|
10054
|
+
await KitCLI.create({
|
|
10055
|
+
type: pType,
|
|
10056
|
+
name: pName,
|
|
10057
|
+
verbose: program2.opts().verbose
|
|
10058
|
+
});
|
|
10059
|
+
});
|
|
10060
|
+
createCommand2.helpInformation = () => formatHelp(createCommand2);
|
|
10061
|
+
var doctorCommand = program2.command("doctor").description("Inspect environment and game project diagnostics").action(async () => {
|
|
10062
|
+
const allPassed = await KitCLI.doctor({
|
|
10063
|
+
verbose: program2.opts().verbose
|
|
10064
|
+
});
|
|
10065
|
+
if (!allPassed) {
|
|
10066
|
+
process.exitCode = 1;
|
|
10067
|
+
}
|
|
10068
|
+
});
|
|
10069
|
+
doctorCommand.helpInformation = () => formatHelp(doctorCommand);
|
|
9638
10070
|
program2.command("help [command]").description("Display help for a command").action((pCommandName) => {
|
|
9639
10071
|
if (pCommandName) {
|
|
9640
10072
|
const cmd = program2.commands.find((c) => c.name() === pCommandName);
|