@gnsx/genesys.sdk 4.2.9

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 (185) hide show
  1. package/README.md +60 -0
  2. package/dist/src/asset-pack/eslint.config.js +58 -0
  3. package/dist/src/asset-pack/scripts/post-install.js +64 -0
  4. package/dist/src/asset-pack/src/index.js +1 -0
  5. package/dist/src/core/cli.js +303 -0
  6. package/dist/src/core/common.js +325 -0
  7. package/dist/src/core/index.js +6 -0
  8. package/dist/src/core/tools/build-project.js +456 -0
  9. package/dist/src/core/tools/index.js +2 -0
  10. package/dist/src/core/tools/new-asset-pack.js +153 -0
  11. package/dist/src/core/tools/new-project.js +293 -0
  12. package/dist/src/core/types.js +1 -0
  13. package/dist/src/dependencies.js +84 -0
  14. package/dist/src/electron/IpcSerializableError.js +38 -0
  15. package/dist/src/electron/api.js +7 -0
  16. package/dist/src/electron/backend/actions.js +56 -0
  17. package/dist/src/electron/backend/handler.js +452 -0
  18. package/dist/src/electron/backend/logging.js +41 -0
  19. package/dist/src/electron/backend/main.js +369 -0
  20. package/dist/src/electron/backend/menu.js +196 -0
  21. package/dist/src/electron/backend/state.js +201 -0
  22. package/dist/src/electron/backend/telemetry.js +9 -0
  23. package/dist/src/electron/backend/tools/const.js +9 -0
  24. package/dist/src/electron/backend/tools/file-server.js +383 -0
  25. package/dist/src/electron/backend/tools/open-project.js +249 -0
  26. package/dist/src/electron/backend/window.js +161 -0
  27. package/dist/src/templates/eslint.config.js +58 -0
  28. package/dist/src/templates/scripts/genesys/build-project.js +42 -0
  29. package/dist/src/templates/scripts/genesys/calc-bounding-box.js +205 -0
  30. package/dist/src/templates/scripts/genesys/common.js +36 -0
  31. package/dist/src/templates/scripts/genesys/const.js +9 -0
  32. package/dist/src/templates/scripts/genesys/dev/dump-default-scene.js +8 -0
  33. package/dist/src/templates/scripts/genesys/dev/generate-manifest.js +116 -0
  34. package/dist/src/templates/scripts/genesys/dev/launcher.js +39 -0
  35. package/dist/src/templates/scripts/genesys/dev/storage-provider.js +188 -0
  36. package/dist/src/templates/scripts/genesys/dev/update-template-scenes.js +67 -0
  37. package/dist/src/templates/scripts/genesys/doc-server.js +12 -0
  38. package/dist/src/templates/scripts/genesys/genesys-mcp.js +413 -0
  39. package/dist/src/templates/scripts/genesys/mcp/doc-tools.js +70 -0
  40. package/dist/src/templates/scripts/genesys/mcp/editor-functions.js +123 -0
  41. package/dist/src/templates/scripts/genesys/mcp/editor-tools.js +51 -0
  42. package/dist/src/templates/scripts/genesys/mcp/get-scene-state.js +26 -0
  43. package/dist/src/templates/scripts/genesys/mcp/run-subprocess.js +23 -0
  44. package/dist/src/templates/scripts/genesys/mcp/search-actors.js +703 -0
  45. package/dist/src/templates/scripts/genesys/mcp/search-assets.js +296 -0
  46. package/dist/src/templates/scripts/genesys/mcp/utils.js +234 -0
  47. package/dist/src/templates/scripts/genesys/migrate-scenes-and-prefabs.js +252 -0
  48. package/dist/src/templates/scripts/genesys/misc.js +32 -0
  49. package/dist/src/templates/scripts/genesys/mock.js +5 -0
  50. package/dist/src/templates/scripts/genesys/place-actors.js +112 -0
  51. package/dist/src/templates/scripts/genesys/post-install.js +33 -0
  52. package/dist/src/templates/scripts/genesys/remove-engine-comments.js +113 -0
  53. package/dist/src/templates/scripts/genesys/storageProvider.js +146 -0
  54. package/dist/src/templates/scripts/genesys/validate-prefabs.js +115 -0
  55. package/dist/src/templates/src/index.js +20 -0
  56. package/dist/src/templates/src/templates/firstPerson/src/auto-imports.js +1 -0
  57. package/dist/src/templates/src/templates/firstPerson/src/game.js +30 -0
  58. package/dist/src/templates/src/templates/firstPerson/src/player.js +55 -0
  59. package/dist/src/templates/src/templates/fps/src/auto-imports.js +1 -0
  60. package/dist/src/templates/src/templates/fps/src/game.js +30 -0
  61. package/dist/src/templates/src/templates/fps/src/player.js +60 -0
  62. package/dist/src/templates/src/templates/fps/src/weapon.js +54 -0
  63. package/dist/src/templates/src/templates/freeCamera/src/auto-imports.js +1 -0
  64. package/dist/src/templates/src/templates/freeCamera/src/game.js +30 -0
  65. package/dist/src/templates/src/templates/freeCamera/src/player.js +38 -0
  66. package/dist/src/templates/src/templates/sideScroller/src/auto-imports.js +1 -0
  67. package/dist/src/templates/src/templates/sideScroller/src/const.js +43 -0
  68. package/dist/src/templates/src/templates/sideScroller/src/game.js +102 -0
  69. package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
  70. package/dist/src/templates/src/templates/sideScroller/src/player.js +100 -0
  71. package/dist/src/templates/src/templates/thirdPerson/src/auto-imports.js +1 -0
  72. package/dist/src/templates/src/templates/thirdPerson/src/game.js +30 -0
  73. package/dist/src/templates/src/templates/thirdPerson/src/player.js +58 -0
  74. package/dist/src/templates/src/templates/vehicle/src/auto-imports.js +1 -0
  75. package/dist/src/templates/src/templates/vehicle/src/base-vehicle.js +122 -0
  76. package/dist/src/templates/src/templates/vehicle/src/game.js +33 -0
  77. package/dist/src/templates/src/templates/vehicle/src/mesh-vehicle.js +188 -0
  78. package/dist/src/templates/src/templates/vehicle/src/player.js +97 -0
  79. package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +258 -0
  80. package/dist/src/templates/src/templates/vehicle/src/ui-hints.js +100 -0
  81. package/dist/src/templates/src/templates/vr-game/src/auto-imports.js +1 -0
  82. package/dist/src/templates/src/templates/vr-game/src/game.js +55 -0
  83. package/dist/src/templates/src/templates/vr-game/src/sample-vr-actor.js +29 -0
  84. package/dist/src/templates/vite.config.js +46 -0
  85. package/package.json +181 -0
  86. package/scripts/post-install.ts +143 -0
  87. package/src/asset-pack/.gitattributes +89 -0
  88. package/src/asset-pack/.github/workflows/publish.yml +90 -0
  89. package/src/asset-pack/eslint.config.js +59 -0
  90. package/src/asset-pack/gitignore +11 -0
  91. package/src/asset-pack/scripts/post-install.ts +81 -0
  92. package/src/asset-pack/src/index.ts +0 -0
  93. package/src/asset-pack/tsconfig.json +34 -0
  94. package/src/templates/.cursor/mcp.json +20 -0
  95. package/src/templates/.cursorignore +2 -0
  96. package/src/templates/.gitattributes +89 -0
  97. package/src/templates/.vscode/settings.json +6 -0
  98. package/src/templates/AGENTS.md +104 -0
  99. package/src/templates/CLAUDE.md +1 -0
  100. package/src/templates/README.md +24 -0
  101. package/src/templates/eslint.config.js +60 -0
  102. package/src/templates/gitignore +11 -0
  103. package/src/templates/index.html +34 -0
  104. package/src/templates/pnpm-lock.yaml +3676 -0
  105. package/src/templates/scripts/genesys/build-project.ts +51 -0
  106. package/src/templates/scripts/genesys/calc-bounding-box.ts +272 -0
  107. package/src/templates/scripts/genesys/common.ts +46 -0
  108. package/src/templates/scripts/genesys/const.ts +9 -0
  109. package/src/templates/scripts/genesys/dev/dump-default-scene.ts +11 -0
  110. package/src/templates/scripts/genesys/dev/generate-manifest.ts +146 -0
  111. package/src/templates/scripts/genesys/dev/launcher.ts +46 -0
  112. package/src/templates/scripts/genesys/dev/storage-provider.ts +229 -0
  113. package/src/templates/scripts/genesys/dev/update-template-scenes.ts +84 -0
  114. package/src/templates/scripts/genesys/doc-server.ts +16 -0
  115. package/src/templates/scripts/genesys/genesys-mcp.ts +526 -0
  116. package/src/templates/scripts/genesys/mcp/doc-tools.ts +86 -0
  117. package/src/templates/scripts/genesys/mcp/editor-functions.ts +151 -0
  118. package/src/templates/scripts/genesys/mcp/editor-tools.ts +73 -0
  119. package/src/templates/scripts/genesys/mcp/get-scene-state.ts +35 -0
  120. package/src/templates/scripts/genesys/mcp/run-subprocess.ts +30 -0
  121. package/src/templates/scripts/genesys/mcp/search-actors.ts +858 -0
  122. package/src/templates/scripts/genesys/mcp/search-assets.ts +380 -0
  123. package/src/templates/scripts/genesys/mcp/utils.ts +281 -0
  124. package/src/templates/scripts/genesys/migrate-scenes-and-prefabs.ts +301 -0
  125. package/src/templates/scripts/genesys/misc.ts +42 -0
  126. package/src/templates/scripts/genesys/mock.ts +6 -0
  127. package/src/templates/scripts/genesys/place-actors.ts +179 -0
  128. package/src/templates/scripts/genesys/post-install.ts +39 -0
  129. package/src/templates/scripts/genesys/prefab.schema.json +85 -0
  130. package/src/templates/scripts/genesys/remove-engine-comments.ts +135 -0
  131. package/src/templates/scripts/genesys/run-mcp-inspector.bat +5 -0
  132. package/src/templates/scripts/genesys/storageProvider.ts +182 -0
  133. package/src/templates/scripts/genesys/validate-prefabs.ts +138 -0
  134. package/src/templates/src/index.ts +22 -0
  135. package/src/templates/src/templates/firstPerson/assets/default.genesys-scene +166 -0
  136. package/src/templates/src/templates/firstPerson/src/auto-imports.ts +0 -0
  137. package/src/templates/src/templates/firstPerson/src/game.ts +39 -0
  138. package/src/templates/src/templates/firstPerson/src/player.ts +59 -0
  139. package/src/templates/src/templates/fps/assets/default.genesys-scene +9460 -0
  140. package/src/templates/src/templates/fps/assets/models/SM_Beam_400.glb +0 -0
  141. package/src/templates/src/templates/fps/assets/models/SM_ChamferCube.glb +0 -0
  142. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400.glb +0 -0
  143. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400_Orange.glb +0 -0
  144. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400.glb +0 -0
  145. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400_Orange.glb +0 -0
  146. package/src/templates/src/templates/fps/assets/models/SM_Ramp_400x400.glb +0 -0
  147. package/src/templates/src/templates/fps/assets/models/SM_Rifle.glb +0 -0
  148. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200.glb +0 -0
  149. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200_Orange.glb +0 -0
  150. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400.glb +0 -0
  151. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400_Orange.glb +0 -0
  152. package/src/templates/src/templates/fps/src/auto-imports.ts +0 -0
  153. package/src/templates/src/templates/fps/src/game.ts +39 -0
  154. package/src/templates/src/templates/fps/src/player.ts +66 -0
  155. package/src/templates/src/templates/fps/src/weapon.ts +47 -0
  156. package/src/templates/src/templates/freeCamera/assets/default.genesys-scene +166 -0
  157. package/src/templates/src/templates/freeCamera/src/auto-imports.ts +0 -0
  158. package/src/templates/src/templates/freeCamera/src/game.ts +39 -0
  159. package/src/templates/src/templates/freeCamera/src/player.ts +40 -0
  160. package/src/templates/src/templates/sideScroller/assets/default.genesys-scene +122 -0
  161. package/src/templates/src/templates/sideScroller/src/auto-imports.ts +0 -0
  162. package/src/templates/src/templates/sideScroller/src/const.ts +46 -0
  163. package/src/templates/src/templates/sideScroller/src/game.ts +121 -0
  164. package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
  165. package/src/templates/src/templates/sideScroller/src/player.ts +123 -0
  166. package/src/templates/src/templates/thirdPerson/assets/default.genesys-scene +166 -0
  167. package/src/templates/src/templates/thirdPerson/src/auto-imports.ts +0 -0
  168. package/src/templates/src/templates/thirdPerson/src/game.ts +39 -0
  169. package/src/templates/src/templates/thirdPerson/src/player.ts +58 -0
  170. package/src/templates/src/templates/vehicle/assets/default.genesys-scene +226 -0
  171. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/chassis.glb +0 -0
  172. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/wheel.glb +0 -0
  173. package/src/templates/src/templates/vehicle/src/auto-imports.ts +0 -0
  174. package/src/templates/src/templates/vehicle/src/base-vehicle.ts +145 -0
  175. package/src/templates/src/templates/vehicle/src/game.ts +43 -0
  176. package/src/templates/src/templates/vehicle/src/mesh-vehicle.ts +189 -0
  177. package/src/templates/src/templates/vehicle/src/player.ts +106 -0
  178. package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +264 -0
  179. package/src/templates/src/templates/vehicle/src/ui-hints.ts +101 -0
  180. package/src/templates/src/templates/vr-game/assets/default.genesys-scene +247 -0
  181. package/src/templates/src/templates/vr-game/src/auto-imports.ts +1 -0
  182. package/src/templates/src/templates/vr-game/src/game.ts +66 -0
  183. package/src/templates/src/templates/vr-game/src/sample-vr-actor.ts +26 -0
  184. package/src/templates/tsconfig.json +35 -0
  185. package/src/templates/vite.config.ts +52 -0
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ [![CI](https://github.com/directivegames/genesys.sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/directivegames/genesys.sdk/actions/workflows/ci.yml)
2
+ [![Publish](https://github.com/directivegames/genesys.sdk/actions/workflows/publish.yml/badge.svg)](https://github.com/directivegames/genesys.sdk/actions/workflows/publish.yml)
3
+
4
+ ![Version](https://gist.githubusercontent.com/haowang1013/d024d16ac57a7bfd7038ae32bf239d07/raw/genesys.sdk.svg)
5
+
6
+ # User Workflow
7
+ - Download and install the latest version from the [Release](https://github.com/directivegames/genesys.sdk/releases) page.
8
+ - Create an empty folder on your disk to store the project.
9
+ - Open the empty folder created earlier in this app, select a template and create a project, then start the file server.
10
+ - Launch the web editor and cursor to develop.
11
+
12
+ # Developer
13
+
14
+ ## Run Locally
15
+ - `pnpm install`
16
+ - `pnpm dev`: to run the dev version, connects to localhost:3000 if available
17
+ - run `pnpm dev` on [genesys.ai](https://github.com/directivegames/genesys.ai) to start localhost:3000
18
+ - if localhost:3000 is started after the sdk, refresh the sdk with Ctrl+R/Ctrl+Shift+R
19
+ - `pnpm dev:watch`: same as `pnpm dev` but with auto-restart on file changes using nodemon
20
+ - `pnpm dev:hosted`: connects to the hosted genesys.ai site.
21
+ - `pnpm dist`: to build the app locally. Installer will be generated in the `dist` folder that you can use to install the app directly on your machine.
22
+
23
+ ## CLI Tools
24
+ The SDK includes command-line tools for creating and building projects without launching the GUI.
25
+
26
+ ### Available Commands
27
+ ```bash
28
+ # Show help and available commands
29
+ genesys-sdk --help
30
+
31
+ # Show version
32
+ genesys-sdk --version
33
+
34
+ # Create a new project
35
+ genesys-sdk new -n <project-name> -t <template-id> [-p <parent-path>]
36
+
37
+ # Build an existing project (with TypeScript type checking)
38
+ genesys-sdk build [-p <project-path>]
39
+
40
+ # Build without type checking (faster)
41
+ genesys-sdk build [-p <project-path>] --no-tsc
42
+
43
+ # List available project templates
44
+ genesys-sdk list-templates
45
+ ```
46
+
47
+ ## New Project Template
48
+ - The logic to setup a new project is in [new-project.ts](src/backend/tools//new-project.ts), it contains a few steps:
49
+ - Generate `game.ts` and `default.genesys-scene` based on the selected template.
50
+ - Generate `package.json` and `{project}.code-workspace` from code.
51
+ - Copy the files from `assets/new-project` to the project folder.
52
+ - Run `pnpm install` and `pnpm build` in the project folder.
53
+
54
+ ## Add Electron API
55
+ Electron API is for exposing code that relies on the nodejs environment to the frontend environment.
56
+
57
+ To add a new one, following this:
58
+ - Define the API in [api.ts](src/api.ts)
59
+ - Add the API wrapper in [preload.ts](src/preload.ts)
60
+ - Implement the API in [handler.ts](src/backend/handler.ts)
@@ -0,0 +1,58 @@
1
+ import tsParser from '@typescript-eslint/parser';
2
+ import noDefaultClassFields from './node_modules/@gnsx/genesys.js/eslint-rules/no-default-class-fields.js';
3
+ import defaultGetterReturnType from './node_modules/@gnsx/genesys.js/eslint-rules/default-getter-return-type.js';
4
+ import noOverrideMethods from './node_modules/@gnsx/genesys.js/eslint-rules/no-override-methods.js';
5
+ import noAsyncOverrideMismatch from './node_modules/@gnsx/genesys.js/eslint-rules/no-async-override-mismatch.js';
6
+ import noDeprecatedConstructor from './node_modules/@gnsx/genesys.js/eslint-rules/no-deprecated-constructor.js';
7
+ import sceneComponentMaterialType from './node_modules/@gnsx/genesys.js/eslint-rules/scene-component-material-type.js';
8
+ import propertyMetadataType from './node_modules/@gnsx/genesys.js/eslint-rules/property-metadata-type.js';
9
+ import tweenTimeArgument from './node_modules/@gnsx/genesys.js/eslint-rules/tween-time-argument.js';
10
+ import requireCreateMethod from './node_modules/@gnsx/genesys.js/eslint-rules/require-create-method.js';
11
+ export default [
12
+ {
13
+ ignores: ['dist/**', '.engine/**', 'node_modules/**']
14
+ },
15
+ {
16
+ files: ['**/*.ts', '**/*.tsx'],
17
+ languageOptions: {
18
+ parser: tsParser,
19
+ parserOptions: {
20
+ project: ['./tsconfig.json']
21
+ }
22
+ },
23
+ plugins: {
24
+ 'custom': {
25
+ rules: {
26
+ 'no-override-methods': noOverrideMethods,
27
+ 'no-default-class-fields': noDefaultClassFields,
28
+ 'default-getter-return-type': defaultGetterReturnType,
29
+ 'no-async-override-mismatch': noAsyncOverrideMismatch,
30
+ 'no-deprecated-constructor': noDeprecatedConstructor,
31
+ 'scene-component-material-type': sceneComponentMaterialType,
32
+ 'property-metadata-type': propertyMetadataType,
33
+ 'tween-time-argument': tweenTimeArgument,
34
+ 'require-create-method': requireCreateMethod
35
+ }
36
+ }
37
+ },
38
+ rules: {
39
+ 'custom/no-override-methods': 'error',
40
+ 'custom/no-default-class-fields': 'error',
41
+ 'custom/default-getter-return-type': 'error',
42
+ 'custom/no-async-override-mismatch': 'error',
43
+ 'custom/no-deprecated-constructor': 'error',
44
+ 'custom/scene-component-material-type': 'error',
45
+ 'custom/property-metadata-type': 'error',
46
+ 'custom/tween-time-argument': 'error',
47
+ 'custom/require-create-method': 'error'
48
+ }
49
+ },
50
+ {
51
+ files: ['games/**/*.ts', 'games/**/*.tsx'],
52
+ rules: {
53
+ 'no-restricted-imports': ['error', {
54
+ patterns: ['../src/**', '!../src/index.js']
55
+ }]
56
+ }
57
+ }
58
+ ];
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ // Get the directory of this script
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ /**
9
+ * Find the parent project root by traversing up from node_modules
10
+ * For pnpm structure like: /project/node_modules/.pnpm/package@version/node_modules/package
11
+ * We want to find: /project
12
+ */
13
+ function findProjectRoot() {
14
+ // Split the current directory path into parts
15
+ const parts = __dirname.split(path.sep);
16
+ // Find the first occurrence of 'node_modules' in the path
17
+ const nodeModulesIndex = parts.indexOf('node_modules');
18
+ if (nodeModulesIndex > 0) {
19
+ // Take everything before 'node_modules' and join it back
20
+ return parts.slice(0, nodeModulesIndex).join(path.sep);
21
+ }
22
+ return null;
23
+ }
24
+ // Only run when installed as a dependency in another project
25
+ // Skip if running in the package's own directory during development
26
+ const isInstalledAsDependency = __dirname.includes('node_modules');
27
+ if (isInstalledAsDependency) {
28
+ try {
29
+ // Read package.json to get the package name
30
+ const packageJsonPath = path.resolve(__dirname, '../package.json');
31
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
32
+ const packageName = packageJson.name;
33
+ // Source: assets folder in this package
34
+ const sourceAssetsDir = path.resolve(__dirname, '../assets');
35
+ // Find the parent project root
36
+ const parentProjectRoot = findProjectRoot();
37
+ if (!parentProjectRoot) {
38
+ console.error('Error: Could not find parent project root');
39
+ process.exit(1);
40
+ }
41
+ // Destination: <parent-project>/packs/<package-name>/assets
42
+ const targetPackDir = path.join(parentProjectRoot, 'packs', packageName);
43
+ const targetAssetsDir = path.join(targetPackDir, 'assets');
44
+ // Check if source assets directory exists
45
+ if (fs.existsSync(sourceAssetsDir)) {
46
+ // Delete target directory if it already exists
47
+ if (fs.existsSync(targetPackDir)) {
48
+ fs.rmSync(targetPackDir, { recursive: true, force: true });
49
+ }
50
+ // Create target directory
51
+ fs.mkdirSync(targetPackDir, { recursive: true });
52
+ // Copy entire assets folder
53
+ fs.cpSync(sourceAssetsDir, targetAssetsDir, { recursive: true });
54
+ console.log(`✓ Assets from "${packageName}" copied to: ${path.relative(parentProjectRoot, targetPackDir)}`);
55
+ }
56
+ else {
57
+ console.log(`⚠ No assets folder found in "${packageName}"`);
58
+ }
59
+ }
60
+ catch (error) {
61
+ console.error('Error during postinstall:', error);
62
+ process.exit(1);
63
+ }
64
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'fs';
3
+ import path from 'path';
4
+ import { createInterface } from 'readline';
5
+ import { fileURLToPath } from 'url';
6
+ import { Command } from 'commander';
7
+ import { getProjectRoot } from './common.js';
8
+ import { buildProject } from './tools/build-project.js';
9
+ import { newAssetPack } from './tools/new-asset-pack.js';
10
+ import { newProject, TEMPLATES } from './tools/new-project.js';
11
+ // CLI Logger implementation
12
+ class ConsoleLogger {
13
+ getTimestamp() {
14
+ return new Date().toLocaleTimeString('en-US', { hour12: false });
15
+ }
16
+ log(...params) {
17
+ console.log(`[${this.getTimestamp()}] [INFO]`, ...params);
18
+ }
19
+ warn(...params) {
20
+ console.warn(`[${this.getTimestamp()}] [WARN]`, ...params);
21
+ }
22
+ error(...params) {
23
+ console.error(`[${this.getTimestamp()}] [ERROR]`, ...params);
24
+ }
25
+ verbose(...params) {
26
+ if (process.env.VERBOSE) {
27
+ console.log(`[${this.getTimestamp()}] [VERBOSE]`, ...params);
28
+ }
29
+ }
30
+ }
31
+ // Module-level logger instance
32
+ const logger = new ConsoleLogger();
33
+ // CLI Handler implementation (stub for UI/OS interactions)
34
+ class ConsoleHandler {
35
+ ui = {
36
+ async showLoadingOverlay(message) {
37
+ if (message) {
38
+ logger.log(message);
39
+ }
40
+ },
41
+ async showErrorDialog(title, message) {
42
+ logger.error(`${title}: ${message}`);
43
+ }
44
+ };
45
+ os = {
46
+ async openPath(path) {
47
+ logger.log(`Project created at: ${path}`);
48
+ }
49
+ };
50
+ app = {
51
+ isPackaged: false,
52
+ resourcesPath: getProjectRoot()
53
+ };
54
+ }
55
+ function printTemplates() {
56
+ logger.log('\nAvailable Project Templates:\n');
57
+ for (const template of TEMPLATES) {
58
+ logger.log(` ${template.id.padEnd(15)} - ${template.name}`);
59
+ logger.log('');
60
+ }
61
+ }
62
+ // Check if running from an installed package (not local development)
63
+ function isInstalledPackage() {
64
+ try {
65
+ const currentFile = fileURLToPath(import.meta.url);
66
+ return currentFile.includes('node_modules');
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ // Get package.json
73
+ function getPackageJson() {
74
+ const packageJsonPath = path.join(getProjectRoot(), 'package.json');
75
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
76
+ return packageJson;
77
+ }
78
+ // Check for updates and prompt user
79
+ async function checkForUpdates() {
80
+ try {
81
+ // Only check for updates if running from an installed package
82
+ if (!isInstalledPackage())
83
+ return;
84
+ logger.log('Checking for updates...');
85
+ const packageJson = getPackageJson();
86
+ const currentVersion = packageJson.version;
87
+ const packageName = packageJson.name;
88
+ if (currentVersion === 'unknown')
89
+ return;
90
+ // Fetch latest version from npm registry
91
+ const response = await fetch(`https://registry.npmjs.org/${packageJson.name}/latest`);
92
+ if (!response.ok)
93
+ return;
94
+ const data = await response.json();
95
+ const latestVersion = data.version;
96
+ if (!latestVersion || latestVersion === currentVersion)
97
+ return;
98
+ // Compare versions (simple comparison - assumes semantic versioning)
99
+ if (isNewerVersion(latestVersion, currentVersion)) {
100
+ logger.log('\n' + '='.repeat(60));
101
+ logger.log(`🔔 Update Available: ${currentVersion} -> ${latestVersion}`);
102
+ logger.log('='.repeat(60));
103
+ // Prompt user if they want to upgrade now
104
+ const answer = await promptUser('Would you like to upgrade now? (Y/n): ');
105
+ if (answer === '' || answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
106
+ logger.log(`\nUpgrading ${packageName}...\n`);
107
+ const { execSync } = await import('child_process');
108
+ try {
109
+ execSync(`pnpm remove -g ${packageName} && pnpm add -g ${packageName}`, {
110
+ stdio: 'inherit'
111
+ });
112
+ logger.log('\n✅ Upgrade complete! Please run your command again.');
113
+ process.exit(0);
114
+ }
115
+ catch (error) {
116
+ logger.error('\n❌ Upgrade failed. Please run the commands manually.');
117
+ logger.log(` pnpm remove -g ${packageName}`);
118
+ logger.log(` pnpm add -g ${packageName}\n`);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ catch {
124
+ // Silently fail - don't interrupt user workflow with version check errors
125
+ }
126
+ }
127
+ // Compare semantic versions
128
+ function isNewerVersion(latest, current) {
129
+ const latestParts = latest.split('.').map(Number);
130
+ const currentParts = current.split('.').map(Number);
131
+ for (let i = 0; i < 3; i++) {
132
+ const latestPart = latestParts[i] || 0;
133
+ const currentPart = currentParts[i] || 0;
134
+ if (latestPart > currentPart)
135
+ return true;
136
+ if (latestPart < currentPart)
137
+ return false;
138
+ }
139
+ return false;
140
+ }
141
+ // Prompt user for input
142
+ function promptUser(question) {
143
+ const rl = createInterface({
144
+ input: process.stdin,
145
+ output: process.stdout
146
+ });
147
+ return new Promise((resolve) => {
148
+ rl.question(question, (answer) => {
149
+ rl.close();
150
+ resolve(answer.trim());
151
+ });
152
+ });
153
+ }
154
+ async function main() {
155
+ // Check for updates at startup
156
+ await checkForUpdates();
157
+ const program = new Command();
158
+ const handler = new ConsoleHandler();
159
+ const packageJson = getPackageJson();
160
+ const currentVersion = packageJson.version;
161
+ program
162
+ .name('genesys-sdk')
163
+ .description('Genesys SDK CLI - Game Project Management Tool')
164
+ .version(currentVersion)
165
+ .option('--verbose', 'Enable verbose logging');
166
+ // New project command
167
+ program
168
+ .command('new')
169
+ .description('Create a new game project')
170
+ .option('-p, --parent-path <path>', 'Parent directory where the project will be created (defaults to current directory)')
171
+ .requiredOption('-n, --name <name>', 'Name of the new project')
172
+ .requiredOption('-t, --template <id>', 'Template ID (use list-templates to see available templates)')
173
+ .action(async (options) => {
174
+ try {
175
+ // Validate template ID
176
+ const template = TEMPLATES.find(t => t.id === options.template);
177
+ if (!template) {
178
+ logger.error(`Error: Invalid template ID "${options.template}"\n`);
179
+ printTemplates();
180
+ process.exit(1);
181
+ }
182
+ const absoluteParentPath = path.resolve(options.parentPath ?? process.cwd());
183
+ logger.log(`Creating new project "${options.name}" with template "${options.template}"...`);
184
+ logger.log(`Parent directory: ${absoluteParentPath}\n`);
185
+ const result = await newProject(absoluteParentPath, options.name, options.template, logger, handler);
186
+ if (result.success) {
187
+ logger.log(`\n✅ ${result.message}`);
188
+ process.exit(0);
189
+ }
190
+ else {
191
+ logger.error(`\n❌ ${result.message}`);
192
+ if (result.error) {
193
+ logger.error(result.error);
194
+ }
195
+ process.exit(1);
196
+ }
197
+ }
198
+ catch (error) {
199
+ logger.error('\n❌ An unexpected error occurred:');
200
+ logger.error(error);
201
+ process.exit(1);
202
+ }
203
+ });
204
+ // Build project command
205
+ program
206
+ .command('build')
207
+ .description('Build an existing game project')
208
+ .option('-p, --path <path>', 'Path to the project to build (defaults to current directory)')
209
+ .option('--no-tsc', 'Skip TypeScript type checking (faster builds)')
210
+ .action(async (options) => {
211
+ try {
212
+ const absoluteProjectPath = path.resolve(options.path ?? process.cwd());
213
+ const runTsc = options.tsc;
214
+ logger.log(`Building project at: ${absoluteProjectPath}`);
215
+ if (!runTsc) {
216
+ logger.log('(Skipping TypeScript type checking)');
217
+ }
218
+ logger.log('');
219
+ const result = await buildProject(absoluteProjectPath, runTsc, logger, handler);
220
+ if (result.success) {
221
+ logger.log(`\n✅ ${result.message}`);
222
+ process.exit(0);
223
+ }
224
+ else {
225
+ logger.error(`\n❌ ${result.message}`);
226
+ if (result.error) {
227
+ logger.error(result.error);
228
+ }
229
+ process.exit(1);
230
+ }
231
+ }
232
+ catch (error) {
233
+ logger.error('\n❌ An unexpected error occurred:');
234
+ logger.error(error);
235
+ process.exit(1);
236
+ }
237
+ });
238
+ // New asset pack command
239
+ program
240
+ .command('new-asset-pack')
241
+ .description('Create a new asset pack')
242
+ .option('-p, --parent-path <path>', 'Parent directory where the asset pack will be created (defaults to current directory)')
243
+ .requiredOption('-n, --name <name>', 'Name of the new asset pack')
244
+ .action(async (options) => {
245
+ try {
246
+ const absoluteParentPath = path.resolve(options.parentPath ?? process.cwd());
247
+ logger.log(`Creating new asset pack "${options.name}"...`);
248
+ logger.log(`Parent directory: ${absoluteParentPath}\n`);
249
+ const result = await newAssetPack(absoluteParentPath, options.name, logger, handler);
250
+ if (result.success) {
251
+ logger.log(`\n✅ ${result.message}`);
252
+ process.exit(0);
253
+ }
254
+ else {
255
+ logger.error(`\n❌ ${result.message}`);
256
+ if (result.error) {
257
+ logger.error(result.error);
258
+ }
259
+ process.exit(1);
260
+ }
261
+ }
262
+ catch (error) {
263
+ logger.error('\n❌ An unexpected error occurred:');
264
+ logger.error(error);
265
+ process.exit(1);
266
+ }
267
+ });
268
+ // List templates command
269
+ program
270
+ .command('list-templates')
271
+ .description('List available project templates')
272
+ .action(() => {
273
+ printTemplates();
274
+ });
275
+ // Add examples to help
276
+ program.addHelpText('after', `
277
+ Examples:
278
+ # Create a new FPS game project in current directory
279
+ $ genesys-sdk new -n my-fps-game -t fps
280
+
281
+ # Create a new FPS game project in a specific directory
282
+ $ genesys-sdk new -p ./projects -n my-fps-game -t fps
283
+
284
+ # Build current directory project with type checking
285
+ $ genesys-sdk build
286
+
287
+ # Build a specific project with type checking
288
+ $ genesys-sdk build -p ./projects/my-game
289
+
290
+ # Create a new asset pack in current directory
291
+ $ genesys-sdk new-asset-pack -n my-asset-pack
292
+
293
+ # Create a new asset pack in a specific directory
294
+ $ genesys-sdk new-asset-pack -p ./packs -n my-asset-pack
295
+
296
+ # List all available templates
297
+ $ genesys-sdk list-templates
298
+ `);
299
+ // Parse arguments
300
+ await program.parseAsync(process.argv);
301
+ }
302
+ // Run the CLI
303
+ main();