@directivegames/genesys.sdk 3.2.2

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 (181) hide show
  1. package/README.md +60 -0
  2. package/dist/src/asset-pack/eslint.config.js +43 -0
  3. package/dist/src/asset-pack/scripts/postinstall.js +64 -0
  4. package/dist/src/asset-pack/src/index.js +1 -0
  5. package/dist/src/core/cli.js +306 -0
  6. package/dist/src/core/common.js +324 -0
  7. package/dist/src/core/index.js +6 -0
  8. package/dist/src/core/tools/build-project.js +450 -0
  9. package/dist/src/core/tools/index.js +2 -0
  10. package/dist/src/core/tools/new-asset-pack.js +150 -0
  11. package/dist/src/core/tools/new-project.js +292 -0
  12. package/dist/src/core/types.js +1 -0
  13. package/dist/src/dependencies.js +82 -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 +441 -0
  18. package/dist/src/electron/backend/logging.js +41 -0
  19. package/dist/src/electron/backend/main.js +315 -0
  20. package/dist/src/electron/backend/menu.js +208 -0
  21. package/dist/src/electron/backend/state.js +201 -0
  22. package/dist/src/electron/backend/tools/const.js +9 -0
  23. package/dist/src/electron/backend/tools/file-server.js +383 -0
  24. package/dist/src/electron/backend/tools/open-project.js +261 -0
  25. package/dist/src/electron/backend/window.js +161 -0
  26. package/dist/src/templates/eslint.config.js +43 -0
  27. package/dist/src/templates/scripts/genesys/build-project.js +42 -0
  28. package/dist/src/templates/scripts/genesys/calc-bounding-box.js +205 -0
  29. package/dist/src/templates/scripts/genesys/common.js +36 -0
  30. package/dist/src/templates/scripts/genesys/const.js +9 -0
  31. package/dist/src/templates/scripts/genesys/dev/dump-default-scene.js +8 -0
  32. package/dist/src/templates/scripts/genesys/dev/generate-manifest.js +116 -0
  33. package/dist/src/templates/scripts/genesys/dev/launcher.js +39 -0
  34. package/dist/src/templates/scripts/genesys/dev/storage-provider.js +188 -0
  35. package/dist/src/templates/scripts/genesys/dev/update-template-scenes.js +67 -0
  36. package/dist/src/templates/scripts/genesys/doc-server.js +12 -0
  37. package/dist/src/templates/scripts/genesys/genesys-mcp.js +413 -0
  38. package/dist/src/templates/scripts/genesys/mcp/doc-tools.js +70 -0
  39. package/dist/src/templates/scripts/genesys/mcp/editor-functions.js +123 -0
  40. package/dist/src/templates/scripts/genesys/mcp/editor-tools.js +51 -0
  41. package/dist/src/templates/scripts/genesys/mcp/get-scene-state.js +26 -0
  42. package/dist/src/templates/scripts/genesys/mcp/run-subprocess.js +23 -0
  43. package/dist/src/templates/scripts/genesys/mcp/search-actors.js +703 -0
  44. package/dist/src/templates/scripts/genesys/mcp/search-assets.js +296 -0
  45. package/dist/src/templates/scripts/genesys/mcp/utils.js +234 -0
  46. package/dist/src/templates/scripts/genesys/misc.js +32 -0
  47. package/dist/src/templates/scripts/genesys/mock.js +5 -0
  48. package/dist/src/templates/scripts/genesys/place-actors.js +112 -0
  49. package/dist/src/templates/scripts/genesys/post-install.js +25 -0
  50. package/dist/src/templates/scripts/genesys/remove-engine-comments.js +113 -0
  51. package/dist/src/templates/scripts/genesys/storageProvider.js +146 -0
  52. package/dist/src/templates/scripts/genesys/validate-prefabs.js +115 -0
  53. package/dist/src/templates/src/index.js +20 -0
  54. package/dist/src/templates/src/templates/firstPerson/src/auto-imports.js +1 -0
  55. package/dist/src/templates/src/templates/firstPerson/src/game.js +30 -0
  56. package/dist/src/templates/src/templates/firstPerson/src/player.js +60 -0
  57. package/dist/src/templates/src/templates/fps/src/auto-imports.js +1 -0
  58. package/dist/src/templates/src/templates/fps/src/game.js +30 -0
  59. package/dist/src/templates/src/templates/fps/src/player.js +64 -0
  60. package/dist/src/templates/src/templates/fps/src/weapon.js +62 -0
  61. package/dist/src/templates/src/templates/freeCamera/src/auto-imports.js +1 -0
  62. package/dist/src/templates/src/templates/freeCamera/src/game.js +30 -0
  63. package/dist/src/templates/src/templates/freeCamera/src/player.js +43 -0
  64. package/dist/src/templates/src/templates/sideScroller/src/auto-imports.js +1 -0
  65. package/dist/src/templates/src/templates/sideScroller/src/const.js +43 -0
  66. package/dist/src/templates/src/templates/sideScroller/src/game.js +103 -0
  67. package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
  68. package/dist/src/templates/src/templates/sideScroller/src/player.js +105 -0
  69. package/dist/src/templates/src/templates/thirdPerson/src/auto-imports.js +1 -0
  70. package/dist/src/templates/src/templates/thirdPerson/src/game.js +30 -0
  71. package/dist/src/templates/src/templates/thirdPerson/src/player.js +63 -0
  72. package/dist/src/templates/src/templates/vehicle/src/auto-imports.js +1 -0
  73. package/dist/src/templates/src/templates/vehicle/src/base-vehicle.js +122 -0
  74. package/dist/src/templates/src/templates/vehicle/src/game.js +33 -0
  75. package/dist/src/templates/src/templates/vehicle/src/mesh-vehicle.js +189 -0
  76. package/dist/src/templates/src/templates/vehicle/src/player.js +102 -0
  77. package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +259 -0
  78. package/dist/src/templates/src/templates/vehicle/src/ui-hints.js +100 -0
  79. package/dist/src/templates/src/templates/vr-game/src/auto-imports.js +1 -0
  80. package/dist/src/templates/src/templates/vr-game/src/game.js +55 -0
  81. package/dist/src/templates/src/templates/vr-game/src/sample-vr-actor.js +29 -0
  82. package/dist/src/templates/vite.config.js +46 -0
  83. package/package.json +176 -0
  84. package/scripts/post-install.ts +143 -0
  85. package/src/asset-pack/.gitattributes +89 -0
  86. package/src/asset-pack/eslint.config.js +45 -0
  87. package/src/asset-pack/gitignore +11 -0
  88. package/src/asset-pack/scripts/postinstall.ts +81 -0
  89. package/src/asset-pack/src/index.ts +0 -0
  90. package/src/asset-pack/tsconfig.json +34 -0
  91. package/src/templates/.cursor/mcp.json +20 -0
  92. package/src/templates/.cursorignore +2 -0
  93. package/src/templates/.gitattributes +89 -0
  94. package/src/templates/.vscode/settings.json +6 -0
  95. package/src/templates/AGENTS.md +86 -0
  96. package/src/templates/CLAUDE.md +1 -0
  97. package/src/templates/README.md +24 -0
  98. package/src/templates/eslint.config.js +45 -0
  99. package/src/templates/gitignore +11 -0
  100. package/src/templates/index.html +34 -0
  101. package/src/templates/pnpm-lock.yaml +3676 -0
  102. package/src/templates/scripts/genesys/build-project.ts +51 -0
  103. package/src/templates/scripts/genesys/calc-bounding-box.ts +272 -0
  104. package/src/templates/scripts/genesys/common.ts +46 -0
  105. package/src/templates/scripts/genesys/const.ts +9 -0
  106. package/src/templates/scripts/genesys/dev/dump-default-scene.ts +11 -0
  107. package/src/templates/scripts/genesys/dev/generate-manifest.ts +146 -0
  108. package/src/templates/scripts/genesys/dev/launcher.ts +46 -0
  109. package/src/templates/scripts/genesys/dev/storage-provider.ts +229 -0
  110. package/src/templates/scripts/genesys/dev/update-template-scenes.ts +84 -0
  111. package/src/templates/scripts/genesys/doc-server.ts +16 -0
  112. package/src/templates/scripts/genesys/genesys-mcp.ts +526 -0
  113. package/src/templates/scripts/genesys/mcp/doc-tools.ts +86 -0
  114. package/src/templates/scripts/genesys/mcp/editor-functions.ts +151 -0
  115. package/src/templates/scripts/genesys/mcp/editor-tools.ts +73 -0
  116. package/src/templates/scripts/genesys/mcp/get-scene-state.ts +35 -0
  117. package/src/templates/scripts/genesys/mcp/run-subprocess.ts +30 -0
  118. package/src/templates/scripts/genesys/mcp/search-actors.ts +858 -0
  119. package/src/templates/scripts/genesys/mcp/search-assets.ts +380 -0
  120. package/src/templates/scripts/genesys/mcp/utils.ts +281 -0
  121. package/src/templates/scripts/genesys/misc.ts +42 -0
  122. package/src/templates/scripts/genesys/mock.ts +6 -0
  123. package/src/templates/scripts/genesys/place-actors.ts +179 -0
  124. package/src/templates/scripts/genesys/post-install.ts +30 -0
  125. package/src/templates/scripts/genesys/prefab.schema.json +85 -0
  126. package/src/templates/scripts/genesys/remove-engine-comments.ts +135 -0
  127. package/src/templates/scripts/genesys/run-mcp-inspector.bat +5 -0
  128. package/src/templates/scripts/genesys/storageProvider.ts +182 -0
  129. package/src/templates/scripts/genesys/validate-prefabs.ts +138 -0
  130. package/src/templates/src/index.ts +22 -0
  131. package/src/templates/src/templates/firstPerson/assets/default.genesys-scene +166 -0
  132. package/src/templates/src/templates/firstPerson/src/auto-imports.ts +0 -0
  133. package/src/templates/src/templates/firstPerson/src/game.ts +39 -0
  134. package/src/templates/src/templates/firstPerson/src/player.ts +63 -0
  135. package/src/templates/src/templates/fps/assets/default.genesys-scene +9460 -0
  136. package/src/templates/src/templates/fps/assets/models/SM_Beam_400.glb +0 -0
  137. package/src/templates/src/templates/fps/assets/models/SM_ChamferCube.glb +0 -0
  138. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400.glb +0 -0
  139. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400_Orange.glb +0 -0
  140. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400.glb +0 -0
  141. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400_Orange.glb +0 -0
  142. package/src/templates/src/templates/fps/assets/models/SM_Ramp_400x400.glb +0 -0
  143. package/src/templates/src/templates/fps/assets/models/SM_Rifle.glb +0 -0
  144. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200.glb +0 -0
  145. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200_Orange.glb +0 -0
  146. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400.glb +0 -0
  147. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400_Orange.glb +0 -0
  148. package/src/templates/src/templates/fps/src/auto-imports.ts +0 -0
  149. package/src/templates/src/templates/fps/src/game.ts +39 -0
  150. package/src/templates/src/templates/fps/src/player.ts +69 -0
  151. package/src/templates/src/templates/fps/src/weapon.ts +54 -0
  152. package/src/templates/src/templates/freeCamera/assets/default.genesys-scene +166 -0
  153. package/src/templates/src/templates/freeCamera/src/auto-imports.ts +0 -0
  154. package/src/templates/src/templates/freeCamera/src/game.ts +39 -0
  155. package/src/templates/src/templates/freeCamera/src/player.ts +45 -0
  156. package/src/templates/src/templates/sideScroller/assets/default.genesys-scene +122 -0
  157. package/src/templates/src/templates/sideScroller/src/auto-imports.ts +0 -0
  158. package/src/templates/src/templates/sideScroller/src/const.ts +46 -0
  159. package/src/templates/src/templates/sideScroller/src/game.ts +122 -0
  160. package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
  161. package/src/templates/src/templates/sideScroller/src/player.ts +125 -0
  162. package/src/templates/src/templates/thirdPerson/assets/default.genesys-scene +166 -0
  163. package/src/templates/src/templates/thirdPerson/src/auto-imports.ts +0 -0
  164. package/src/templates/src/templates/thirdPerson/src/game.ts +39 -0
  165. package/src/templates/src/templates/thirdPerson/src/player.ts +61 -0
  166. package/src/templates/src/templates/vehicle/assets/default.genesys-scene +226 -0
  167. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/chassis.glb +0 -0
  168. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/wheel.glb +0 -0
  169. package/src/templates/src/templates/vehicle/src/auto-imports.ts +0 -0
  170. package/src/templates/src/templates/vehicle/src/base-vehicle.ts +145 -0
  171. package/src/templates/src/templates/vehicle/src/game.ts +43 -0
  172. package/src/templates/src/templates/vehicle/src/mesh-vehicle.ts +191 -0
  173. package/src/templates/src/templates/vehicle/src/player.ts +109 -0
  174. package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +266 -0
  175. package/src/templates/src/templates/vehicle/src/ui-hints.ts +101 -0
  176. package/src/templates/src/templates/vr-game/assets/default.genesys-scene +247 -0
  177. package/src/templates/src/templates/vr-game/src/auto-imports.ts +1 -0
  178. package/src/templates/src/templates/vr-game/src/game.ts +66 -0
  179. package/src/templates/src/templates/vr-game/src/sample-vr-actor.ts +26 -0
  180. package/src/templates/tsconfig.json +35 -0
  181. package/src/templates/vite.config.ts +52 -0
@@ -0,0 +1,441 @@
1
+ import fs from 'fs';
2
+ import pathlib from 'path';
3
+ import path from 'path';
4
+ import { dialog, ipcMain, shell } from 'electron';
5
+ import { app } from 'electron';
6
+ import isDev from 'electron-is-dev';
7
+ import electronUpdater from 'electron-updater';
8
+ import upath from 'upath';
9
+ import { getAppVersion, getEngineVersion, getProjectFolderAndFile, IgnoredFiles, newProject, TEMPLATES } from '../../core/index.js';
10
+ import { buildProject } from '../../core/tools/build-project.js';
11
+ import { IpcSerializableError } from '../IpcSerializableError.js';
12
+ import { getLogPath, logger } from './logging.js';
13
+ import { clearPendingDeepLinkUrl, getPendingDeepLinkUrl, mainWindow } from './main.js';
14
+ import { appState } from './state.js';
15
+ import { ReleaseUrl } from './tools/const.js';
16
+ import { fileServer } from './tools/file-server.js';
17
+ import { openProject } from './tools/open-project.js';
18
+ const { autoUpdater } = electronUpdater;
19
+ export const handlers = {
20
+ fileServer: {
21
+ start: async (port, rootDir) => {
22
+ try {
23
+ await fileServer.start(port, fs.lstatSync(rootDir).isDirectory() ? rootDir : pathlib.dirname(rootDir));
24
+ return null;
25
+ }
26
+ catch (error) {
27
+ return IpcSerializableError.serialize(error);
28
+ }
29
+ },
30
+ stop: async () => {
31
+ try {
32
+ await fileServer.stop();
33
+ return null;
34
+ }
35
+ catch (error) {
36
+ return IpcSerializableError.serialize(error);
37
+ }
38
+ },
39
+ status: async () => {
40
+ return {
41
+ isRunning: fileServer.isServerRunning(),
42
+ port: fileServer.getPort(),
43
+ };
44
+ },
45
+ },
46
+ os: {
47
+ chooseDirectory: async (title) => {
48
+ const { canceled, filePaths } = await dialog.showOpenDialog({
49
+ title,
50
+ properties: ['openDirectory'],
51
+ });
52
+ return canceled ? null : upath.normalize(filePaths[0]);
53
+ },
54
+ chooseGenesysProject: async (title) => {
55
+ const { canceled, filePaths } = await dialog.showOpenDialog({
56
+ title,
57
+ properties: ['openFile'],
58
+ filters: [
59
+ { name: 'Genesys Project', extensions: ['genesys-project'] }
60
+ ]
61
+ });
62
+ return canceled ? null : upath.normalize(filePaths[0]);
63
+ },
64
+ openPath: async (path) => {
65
+ const { folder } = getProjectFolderAndFile(path, logger);
66
+ await shell.openPath(folder);
67
+ },
68
+ openUrl: async (url) => {
69
+ await shell.openExternal(url);
70
+ },
71
+ showItemInFolder: (path) => {
72
+ shell.showItemInFolder(path);
73
+ },
74
+ readDirectory: async (path) => {
75
+ if (!fs.existsSync(path)) {
76
+ return null;
77
+ }
78
+ const folder = fs.lstatSync(path).isDirectory() ? path : pathlib.dirname(path);
79
+ return fs.readdirSync(folder).filter(file => !IgnoredFiles.includes(file));
80
+ },
81
+ exists: async (path) => {
82
+ return fs.existsSync(path);
83
+ },
84
+ },
85
+ tools: {
86
+ // given a folder or a file path, return the folder and the project file name
87
+ // if it's a directory, will try find the project file in that directory
88
+ // if folder is invalid or no project file is found, return empty strings
89
+ getProjectFolderAndFile: async (path) => {
90
+ return getProjectFolderAndFile(path, logger);
91
+ },
92
+ createProject: async (parentPath, projectName, templateId) => {
93
+ handlers.ui.showLoadingOverlay('Creating Project...');
94
+ const res = await newProject(parentPath, projectName, templateId, logger, handlerForCore);
95
+ if (res.error instanceof Error) {
96
+ res.error = IpcSerializableError.serialize(res.error);
97
+ }
98
+ // Track project creation time if successful
99
+ if (res.success && res.path) {
100
+ console.log(`[projects] 📝 Tracking new project: ${res.path}`);
101
+ appState.updateProjectLastOpened(res.path);
102
+ }
103
+ handlers.ui.hideLoadingOverlay();
104
+ return res;
105
+ },
106
+ openProject: async (projectPath) => {
107
+ const res = await openProject(projectPath, () => handlers.ui.showLoadingOverlay('Opening Project...'), () => handlers.ui.hideLoadingOverlay(), () => handlers.ui.showLoadingOverlay('Verifying Project...'), () => handlers.ui.hideLoadingOverlay(), () => handlers.ui.showLoadingOverlay('Updating Project...'), () => handlers.ui.hideLoadingOverlay());
108
+ if (res.error instanceof Error) {
109
+ res.error = IpcSerializableError.serialize(res.error);
110
+ }
111
+ // Track project open time if successful
112
+ if (res.success && res.path) {
113
+ console.log(`[projects] 📂 Tracking opened project: ${res.path}`);
114
+ appState.updateProjectLastOpened(res.path);
115
+ }
116
+ return res;
117
+ },
118
+ deleteProject: async (projectPath) => {
119
+ if (!fs.existsSync(projectPath)) {
120
+ return {
121
+ success: false,
122
+ message: 'Project not found',
123
+ path: projectPath
124
+ };
125
+ }
126
+ handlers.ui.showLoadingOverlay('Deleting Project...');
127
+ try {
128
+ const { folder: projectFolder } = getProjectFolderAndFile(projectPath, logger);
129
+ const entries = fs.readdirSync(projectFolder, { withFileTypes: true });
130
+ for (const entry of entries) {
131
+ const fullPath = pathlib.join(projectFolder, entry.name);
132
+ fs.rmSync(fullPath, { recursive: true, force: true });
133
+ }
134
+ // Remove the project from the projects list
135
+ appState.removeProject(projectPath);
136
+ return {
137
+ success: true,
138
+ message: `Project ${projectPath} deleted`,
139
+ path: projectPath
140
+ };
141
+ }
142
+ catch (error) {
143
+ return {
144
+ success: false,
145
+ message: 'Failed to delete project',
146
+ path: projectPath,
147
+ error: IpcSerializableError.serialize(error),
148
+ };
149
+ }
150
+ finally {
151
+ handlers.ui.hideLoadingOverlay();
152
+ }
153
+ },
154
+ buildProject: async (projectPath, runTsc) => {
155
+ handlers.ui.showLoadingOverlay('Building Project...');
156
+ const res = await buildProject(projectPath, runTsc, logger, handlerForCore);
157
+ if (res.error instanceof Error) {
158
+ res.error = IpcSerializableError.serialize(res.error);
159
+ }
160
+ handlers.ui.hideLoadingOverlay();
161
+ return res;
162
+ },
163
+ getProjectTemplates: async () => {
164
+ return TEMPLATES;
165
+ },
166
+ getProjects: async () => {
167
+ const projects = appState.getAllProjects();
168
+ return Object.entries(projects)
169
+ .map(([projectFilePath, lastOpened]) => {
170
+ // Check if the project path exists
171
+ const pathExists = fs.existsSync(projectFilePath);
172
+ let projectFileExists = false;
173
+ let projectFile = '';
174
+ let projectFolder = '';
175
+ if (pathExists) {
176
+ try {
177
+ // Get project folder and file info
178
+ const { folder, file } = getProjectFolderAndFile(projectFilePath, logger);
179
+ projectFolder = folder;
180
+ projectFile = file;
181
+ // Check if the project file exists
182
+ if (folder && file) {
183
+ const projectFilePath = path.join(folder, file);
184
+ projectFileExists = fs.existsSync(projectFilePath);
185
+ }
186
+ }
187
+ catch (error) {
188
+ // If getProjectFolderAndFile throws an error, consider the project as not found
189
+ projectFileExists = false;
190
+ }
191
+ }
192
+ const isFound = pathExists && projectFileExists;
193
+ if (!isFound) {
194
+ [projectFolder, projectFile] = [path.dirname(projectFilePath), path.basename(projectFilePath)];
195
+ }
196
+ return {
197
+ folder: projectFolder,
198
+ file: projectFile,
199
+ lastOpened: lastOpened,
200
+ isFound
201
+ };
202
+ })
203
+ .sort((a, b) => b.lastOpened - a.lastOpened);
204
+ },
205
+ },
206
+ app: {
207
+ getInfo: async () => {
208
+ return getAppInfo();
209
+ },
210
+ checkForUpdates: async (notifyWhenNoUpdates) => {
211
+ const result = await autoUpdater.checkForUpdates();
212
+ if (!result || !result.isUpdateAvailable) {
213
+ if (notifyWhenNoUpdates) {
214
+ dialog.showMessageBox(mainWindow, {
215
+ type: 'info',
216
+ buttons: ['OK'],
217
+ title: 'No Updates Available',
218
+ message: 'You are running the latest version of the application',
219
+ });
220
+ }
221
+ return;
222
+ }
223
+ else {
224
+ dialog.showMessageBox(mainWindow, {
225
+ type: 'info',
226
+ buttons: ['Manual Download', 'OK'],
227
+ title: 'Update Available',
228
+ message: 'An update is available and is being downloaded. You will be notified when it is ready to install.',
229
+ }).then(async ({ response }) => {
230
+ if (response === 0)
231
+ await shell.openExternal(ReleaseUrl);
232
+ });
233
+ return;
234
+ }
235
+ },
236
+ getPath: (name) => {
237
+ return app.getPath(name);
238
+ },
239
+ getState: async (key) => {
240
+ return appState.getState(key);
241
+ },
242
+ setState: async (key, value) => {
243
+ appState.setState(key, value);
244
+ },
245
+ },
246
+ notifications: {
247
+ sendNotification: async (level, title, message) => {
248
+ const notification = {
249
+ level,
250
+ title,
251
+ message,
252
+ };
253
+ // Send notification to all renderer processes
254
+ if (mainWindow && !mainWindow.isDestroyed()) {
255
+ mainWindow.webContents.send('notification', notification);
256
+ }
257
+ },
258
+ },
259
+ ui: {
260
+ reload: (force) => {
261
+ force ? mainWindow?.webContents.reloadIgnoringCache() : mainWindow?.reload();
262
+ },
263
+ showLoadingOverlay: async (message) => {
264
+ if (mainWindow && !mainWindow.isDestroyed()) {
265
+ mainWindow.webContents.send('loading-overlay-show', message ?? 'Loading...');
266
+ mainWindow.setProgressBar(99, { mode: 'indeterminate' });
267
+ }
268
+ },
269
+ hideLoadingOverlay: async () => {
270
+ if (mainWindow && !mainWindow.isDestroyed()) {
271
+ mainWindow.webContents.send('loading-overlay-hide');
272
+ mainWindow.setProgressBar(-1);
273
+ }
274
+ },
275
+ showErrorDialog: async (title, message) => {
276
+ dialog.showErrorBox(title, message);
277
+ },
278
+ },
279
+ window: {
280
+ minimize: () => {
281
+ if (mainWindow && !mainWindow.isDestroyed()) {
282
+ mainWindow.minimize();
283
+ }
284
+ },
285
+ maximize: () => {
286
+ if (mainWindow && !mainWindow.isDestroyed()) {
287
+ if (mainWindow.isMaximized()) {
288
+ mainWindow.unmaximize();
289
+ }
290
+ else {
291
+ mainWindow.maximize();
292
+ }
293
+ }
294
+ },
295
+ unmaximize: () => {
296
+ if (mainWindow && !mainWindow.isDestroyed()) {
297
+ mainWindow.unmaximize();
298
+ }
299
+ },
300
+ isMaximized: async () => {
301
+ if (mainWindow && !mainWindow.isDestroyed()) {
302
+ return mainWindow.isMaximized();
303
+ }
304
+ return false;
305
+ },
306
+ close: () => {
307
+ if (mainWindow && !mainWindow.isDestroyed()) {
308
+ mainWindow.close();
309
+ }
310
+ },
311
+ },
312
+ };
313
+ const handlerForCore = {
314
+ ui: handlers.ui,
315
+ os: handlers.os,
316
+ app: {
317
+ isPackaged: app.isPackaged,
318
+ resourcesPath: process.resourcesPath,
319
+ }
320
+ };
321
+ ipcMain.handle('fileServer.start', async (_, port, rootDir) => {
322
+ return handlers.fileServer.start(port, rootDir);
323
+ });
324
+ ipcMain.handle('fileServer.stop', async () => {
325
+ return handlers.fileServer.stop();
326
+ });
327
+ ipcMain.handle('fileServer.status', async () => {
328
+ return handlers.fileServer.status();
329
+ });
330
+ ipcMain.handle('os.chooseDirectory', async (_, title) => {
331
+ return handlers.os.chooseDirectory(title);
332
+ });
333
+ ipcMain.handle('os.chooseGenesysProject', async (_, title) => {
334
+ return handlers.os.chooseGenesysProject(title);
335
+ });
336
+ ipcMain.handle('os.openPath', async (_, path) => {
337
+ return handlers.os.openPath(path);
338
+ });
339
+ ipcMain.handle('os.openUrl', async (_, url) => {
340
+ return handlers.os.openUrl(url);
341
+ });
342
+ ipcMain.on('os.showItemInFolder', (_, path) => {
343
+ return handlers.os.showItemInFolder(path);
344
+ });
345
+ ipcMain.handle('os.readDirectory', async (_, path) => {
346
+ return handlers.os.readDirectory(path);
347
+ });
348
+ ipcMain.handle('os.exists', async (_, path) => {
349
+ return handlers.os.exists(path);
350
+ });
351
+ ipcMain.handle('os.platform', async () => {
352
+ return process.platform;
353
+ });
354
+ ipcMain.handle('tools.getProjectFolderAndFile', async (_, path) => {
355
+ return handlers.tools.getProjectFolderAndFile(path);
356
+ });
357
+ ipcMain.handle('tools.createProject', async (_, parentPath, projectName, templateId) => {
358
+ return handlers.tools.createProject(parentPath, projectName, templateId);
359
+ });
360
+ ipcMain.handle('tools.openProject', async (_, projectPath) => {
361
+ return handlers.tools.openProject(projectPath);
362
+ });
363
+ ipcMain.handle('tools.deleteProject', async (_, projectPath) => {
364
+ return handlers.tools.deleteProject(projectPath);
365
+ });
366
+ ipcMain.handle('tools.buildProject', async (_, projectPath, runTsc) => {
367
+ return handlers.tools.buildProject(projectPath, runTsc);
368
+ });
369
+ ipcMain.handle('tools.getProjectTemplates', async () => {
370
+ return handlers.tools.getProjectTemplates();
371
+ });
372
+ ipcMain.handle('tools.getProjects', async () => {
373
+ return handlers.tools.getProjects();
374
+ });
375
+ ipcMain.on('tools.toggleDevConsole', () => {
376
+ mainWindow && mainWindow.webContents.toggleDevTools();
377
+ });
378
+ ipcMain.handle('app.getInfo', async () => {
379
+ return handlers.app.getInfo();
380
+ });
381
+ ipcMain.handle('app.getPath', async (_, name) => {
382
+ return handlers.app.getPath(name);
383
+ });
384
+ ipcMain.handle('app.checkForUpdates', async (_, notifyWhenNoUpdates) => {
385
+ return handlers.app.checkForUpdates(notifyWhenNoUpdates);
386
+ });
387
+ ipcMain.handle('app.getState', async (_, key) => {
388
+ return handlers.app.getState(key);
389
+ });
390
+ ipcMain.handle('app.setState', async (_, key, value) => {
391
+ return handlers.app.setState(key, value);
392
+ });
393
+ ipcMain.handle('notifications.sendNotification', async (_, level, title, message) => {
394
+ return handlers.notifications.sendNotification(level, title, message);
395
+ });
396
+ ipcMain.on('ui.reload', (_, force) => {
397
+ handlers.ui.reload(force);
398
+ });
399
+ ipcMain.handle('ui.showLoadingOverlay', async (_, message) => {
400
+ return handlers.ui.showLoadingOverlay(message);
401
+ });
402
+ ipcMain.handle('ui.hideLoadingOverlay', async () => {
403
+ return handlers.ui.hideLoadingOverlay();
404
+ });
405
+ ipcMain.on('dev.loadUrl', (_, url) => {
406
+ isDev && mainWindow?.loadURL(url);
407
+ });
408
+ ipcMain.on('window.minimize', () => {
409
+ handlers.window.minimize();
410
+ });
411
+ ipcMain.on('window.maximize', () => {
412
+ handlers.window.maximize();
413
+ });
414
+ ipcMain.on('window.unmaximize', () => {
415
+ handlers.window.unmaximize();
416
+ });
417
+ ipcMain.handle('window.isMaximized', async () => {
418
+ return handlers.window.isMaximized();
419
+ });
420
+ ipcMain.on('window.close', () => {
421
+ handlers.window.close();
422
+ });
423
+ ipcMain.on('register-deep-link', () => {
424
+ console.log('🔗 [deep-link] Renderer registered for deep links');
425
+ // Check if there's a pending deep link URL
426
+ const pendingUrl = getPendingDeepLinkUrl();
427
+ if (pendingUrl && mainWindow && !mainWindow.isDestroyed()) {
428
+ console.log('🔗 [deep-link] Sending pending deep link to renderer:', pendingUrl);
429
+ mainWindow.webContents.send('deep-link', pendingUrl);
430
+ clearPendingDeepLinkUrl();
431
+ }
432
+ });
433
+ export function getAppInfo() {
434
+ return {
435
+ isDev: isDev,
436
+ engineVersion: getEngineVersion(),
437
+ appVersion: getAppVersion(),
438
+ appName: app.getName(),
439
+ logPath: getLogPath(),
440
+ };
441
+ }
@@ -0,0 +1,41 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { app, BrowserWindow } from 'electron';
4
+ import log from 'electron-log';
5
+ class BackendLogger {
6
+ /** Logs normally but without forwarding to frontend windows */
7
+ verbose(...params) {
8
+ console.log(...params);
9
+ }
10
+ log(...params) {
11
+ console.log(...params);
12
+ BrowserWindow.getAllWindows().forEach(window => {
13
+ window.webContents.send('log', ...params);
14
+ });
15
+ }
16
+ error(...params) {
17
+ console.error(...params);
18
+ BrowserWindow.getAllWindows().forEach(window => {
19
+ window.webContents.send('error', ...params);
20
+ });
21
+ }
22
+ warn(...params) {
23
+ console.warn(...params);
24
+ BrowserWindow.getAllWindows().forEach(window => {
25
+ window.webContents.send('warn', ...params);
26
+ });
27
+ }
28
+ }
29
+ export function getLogPath() {
30
+ return path.join(app.getPath('userData'), 'logs', `${app.getName()}.log`);
31
+ }
32
+ export function configureLogging() {
33
+ const logPath = getLogPath();
34
+ fs.mkdirSync(path.dirname(logPath), { recursive: true });
35
+ log.transports.file.resolvePathFn = () => logPath;
36
+ log.initialize();
37
+ console.log = log.log;
38
+ console.error = log.error;
39
+ console.warn = log.warn;
40
+ }
41
+ export const logger = new BackendLogger();