@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,315 @@
1
+ import path from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { app, dialog, Menu } from 'electron';
4
+ import { BrowserWindow } from 'electron';
5
+ import { installExtension, MOBX_DEVTOOLS, REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer';
6
+ import isDev from 'electron-is-dev';
7
+ import log from 'electron-log';
8
+ import electronUpdater from 'electron-updater';
9
+ import { getAppInfo } from './handler.js';
10
+ import { configureLogging, logger } from './logging.js';
11
+ import { buildAppMenu } from './menu.js';
12
+ import { GENESYS_LOCAL_URL, GENESYS_URL } from './tools/const.js';
13
+ import { createWindow, parseFeatures } from './window.js';
14
+ const { autoUpdater } = electronUpdater;
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+ export let mainWindow = null;
18
+ // Deep link URL storage
19
+ let pendingDeepLinkUrl = null;
20
+ export function getPendingDeepLinkUrl() {
21
+ return pendingDeepLinkUrl;
22
+ }
23
+ export function clearPendingDeepLinkUrl() {
24
+ pendingDeepLinkUrl = null;
25
+ }
26
+ configureLogging();
27
+ start();
28
+ function start() {
29
+ // Register deep link protocols
30
+ registerDeepLinkProtocols();
31
+ const hasLock = app.requestSingleInstanceLock();
32
+ app.on('second-instance', (event, argv, workingDirectory, additionalData) => {
33
+ logger.log('🔗 [deep-link] Second instance detected, checking for deep link URL');
34
+ // Handle deep link from second instance
35
+ const deepLinkUrl = getDeepLinkFromArgs(argv);
36
+ if (deepLinkUrl) {
37
+ logger.log('🔗 [deep-link] Processing URL from second instance:', deepLinkUrl);
38
+ handleDeepLink(deepLinkUrl);
39
+ }
40
+ if (mainWindow) {
41
+ mainWindow.isMinimized() && mainWindow.restore();
42
+ mainWindow.focus();
43
+ }
44
+ });
45
+ if (!hasLock) {
46
+ return app.quit();
47
+ }
48
+ // Handle deep link from first instance
49
+ const deepLinkUrl = getDeepLinkFromArgs(process.argv);
50
+ if (deepLinkUrl) {
51
+ logger.log('🔗 [deep-link] Processing URL from first instance:', deepLinkUrl);
52
+ pendingDeepLinkUrl = deepLinkUrl;
53
+ }
54
+ // Get custom URL from command line arguments (--url=https://example.com)
55
+ const customUrl = app.commandLine.hasSwitch('url') ? app.commandLine.getSwitchValue('url') : undefined;
56
+ if (customUrl) {
57
+ logger.log('Custom URL provided:', customUrl);
58
+ }
59
+ logger.log('===============================================');
60
+ logger.log(`\n${JSON.stringify(getAppInfo(), null, 2)}`);
61
+ logger.log('===============================================');
62
+ // Handle macOS deep links
63
+ app.on('open-url', (event, url) => {
64
+ event.preventDefault();
65
+ logger.log('🔗 [deep-link] macOS open-url event:', url);
66
+ handleDeepLink(url);
67
+ });
68
+ app.whenReady().then(async () => {
69
+ await initMainWindow();
70
+ Menu.setApplicationMenu(buildAppMenu(mainWindow));
71
+ checkForUpdates();
72
+ // Process pending deep link after window is ready
73
+ if (pendingDeepLinkUrl) {
74
+ logger.log('🔗 [deep-link] Processing pending deep link URL:', pendingDeepLinkUrl);
75
+ handleDeepLink(pendingDeepLinkUrl);
76
+ pendingDeepLinkUrl = null;
77
+ }
78
+ });
79
+ app.on('window-all-closed', () => {
80
+ if (process.platform !== 'darwin')
81
+ app.quit();
82
+ });
83
+ }
84
+ /** Register deep link protocols based on environment */
85
+ function registerDeepLinkProtocols() {
86
+ const protocol = isDev ? 'genesys-dev' : 'genesys';
87
+ let success = false;
88
+ if (process.defaultApp) {
89
+ // Development mode - need to specify execPath and argv
90
+ if (process.argv.length >= 2) {
91
+ success = app.setAsDefaultProtocolClient(protocol, process.execPath, [path.resolve(process.argv[1])]);
92
+ }
93
+ }
94
+ else {
95
+ // Production mode - simple registration
96
+ success = app.setAsDefaultProtocolClient(protocol);
97
+ }
98
+ if (success) {
99
+ logger.log(`🔗 [deep-link] Successfully registered protocol: ${protocol}://`);
100
+ }
101
+ else {
102
+ logger.warn(`⚠️ [deep-link] Failed to register protocol: ${protocol}://`);
103
+ }
104
+ }
105
+ /** Extract deep link URL from command line arguments */
106
+ function getDeepLinkFromArgs(argv) {
107
+ const protocol = isDev ? 'genesys-dev://' : 'genesys://';
108
+ for (const arg of argv) {
109
+ if (arg.startsWith(protocol)) {
110
+ return arg;
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+ /** Handle deep link URL */
116
+ function handleDeepLink(url) {
117
+ logger.log('🔗 [deep-link] Handling deep link:', url);
118
+ try {
119
+ const parsedUrl = new URL(url);
120
+ logger.log('🔗 [deep-link] Parsed URL:', parsedUrl.toString());
121
+ // Send deep link to renderer process if window is ready
122
+ if (mainWindow && !mainWindow.isDestroyed()) {
123
+ mainWindow.webContents.send('deep-link', parsedUrl.toString());
124
+ logger.log('🔗 [deep-link] Deep link sent to renderer process');
125
+ }
126
+ else {
127
+ // Store for later if window isn't ready
128
+ pendingDeepLinkUrl = url;
129
+ logger.log('🔗 [deep-link] Window not ready, storing deep link for later');
130
+ }
131
+ }
132
+ catch (error) {
133
+ logger.error('❌ [deep-link] Failed to parse deep link URL:', error);
134
+ }
135
+ }
136
+ const windowOptions = {
137
+ backgroundColor: '#13171b',
138
+ hasShadow: true,
139
+ titleBarStyle: 'hidden',
140
+ titleBarOverlay: false,
141
+ minWidth: 1024,
142
+ minHeight: 720,
143
+ };
144
+ async function showLocalDevError() {
145
+ const result = await dialog.showMessageBox(mainWindow, {
146
+ type: 'error',
147
+ buttons: ['Refresh (Ctrl+Shift+R)', 'OK'],
148
+ title: 'Local Development Server Not Running',
149
+ message: 'Failed to connect to local development server',
150
+ detail: 'Run "pnpm dev" on the .ai project and then refresh this page'
151
+ });
152
+ if (result.response === 0) {
153
+ // Refresh the page
154
+ try {
155
+ await mainWindow.loadURL(GENESYS_LOCAL_URL);
156
+ logger.log('Genesys.ai localhost');
157
+ }
158
+ catch (error) {
159
+ logger.error('Failed to load local URL:', error);
160
+ await showLocalDevError();
161
+ }
162
+ }
163
+ }
164
+ async function showUrlLoadError(message) {
165
+ await dialog.showMessageBox(mainWindow, {
166
+ type: 'error',
167
+ buttons: ['OK'],
168
+ title: 'Connection Error',
169
+ message,
170
+ detail: 'Please check your internet connection and try again'
171
+ });
172
+ }
173
+ async function initMainWindow() {
174
+ // Create main window with title bar overlay
175
+ mainWindow = createWindow('main', {
176
+ show: false,
177
+ title: 'Genesys',
178
+ ...windowOptions,
179
+ webPreferences: {
180
+ sandbox: true,
181
+ contextIsolation: true,
182
+ preload: path.join(__dirname, '../../../preload/electron/preload.js'),
183
+ nodeIntegration: false,
184
+ },
185
+ });
186
+ mainWindow.webContents.on('did-finish-load', async () => {
187
+ logger.log('🌐 Website loaded successfully...');
188
+ if (isDev && !extensionsLoaded) {
189
+ await loadDevExtensions();
190
+ }
191
+ mainWindow.show();
192
+ });
193
+ // Options for new windows
194
+ mainWindow.webContents.setWindowOpenHandler(({ url, frameName, features }) => {
195
+ const parsedFeatures = parseFeatures(features);
196
+ logger.log('Open window', url, features, parsedFeatures);
197
+ return {
198
+ action: 'allow',
199
+ createWindow: (options) => {
200
+ const newWindow = new BrowserWindow(options);
201
+ newWindow.setMenu(null); // Remove menu bar
202
+ return newWindow.webContents;
203
+ },
204
+ overrideBrowserWindowOptions: {
205
+ ...windowOptions,
206
+ titleBarOverlay: (process.platform === 'darwin') ? false : {
207
+ color: '#13171b',
208
+ symbolColor: '#FFFFFF',
209
+ height: 44,
210
+ },
211
+ minWidth: 800,
212
+ minHeight: 600,
213
+ width: parsedFeatures.width,
214
+ height: parsedFeatures.height,
215
+ fullscreen: parsedFeatures.fullscreen,
216
+ title: parsedFeatures.title,
217
+ }
218
+ };
219
+ });
220
+ // Get custom URL from command line arguments
221
+ const customUrl = process.argv.find(arg => arg.startsWith('--url='))?.split('=')[1];
222
+ if (customUrl) {
223
+ try {
224
+ await mainWindow.loadURL(customUrl);
225
+ logger.log('Loading custom URL:', customUrl);
226
+ }
227
+ catch (error) {
228
+ logger.error('Failed to load custom URL:', error);
229
+ await showUrlLoadError('Failed to load custom URL');
230
+ }
231
+ }
232
+ else if (isDev) {
233
+ if (process.env.DEV_HOSTED) {
234
+ try {
235
+ await mainWindow.loadURL(GENESYS_URL);
236
+ logger.log('Genesys.ai hosted');
237
+ }
238
+ catch (error) {
239
+ logger.error('Failed to load hosted URL:', error);
240
+ await showUrlLoadError('Failed to load hosted Genesys.ai');
241
+ }
242
+ }
243
+ else {
244
+ try {
245
+ await mainWindow.loadURL(GENESYS_LOCAL_URL);
246
+ logger.log('Genesys.ai localhost');
247
+ }
248
+ catch (error) {
249
+ logger.error('Failed to load local URL:', error);
250
+ await showLocalDevError();
251
+ }
252
+ }
253
+ mainWindow.webContents.openDevTools();
254
+ }
255
+ else {
256
+ try {
257
+ await mainWindow.loadURL(GENESYS_URL);
258
+ }
259
+ catch (error) {
260
+ logger.error('Failed to load production URL:', error);
261
+ await showUrlLoadError('Failed to load Genesys.ai');
262
+ }
263
+ }
264
+ }
265
+ ;
266
+ function checkForUpdates() {
267
+ autoUpdater.logger = log;
268
+ autoUpdater.checkForUpdatesAndNotify();
269
+ autoUpdater.on('update-available', () => {
270
+ logger.log('App update available');
271
+ mainWindow?.webContents.send('update_available');
272
+ });
273
+ autoUpdater.on('update-downloaded', () => {
274
+ logger.log('App update downloaded');
275
+ dialog.showMessageBox(mainWindow, {
276
+ type: 'info',
277
+ buttons: ['Restart', 'Later'],
278
+ title: 'SDK App Update Ready',
279
+ message: 'A new app version has been downloaded. Restart now to complete the update?',
280
+ }).then(({ response }) => {
281
+ if (response === 0)
282
+ autoUpdater.quitAndInstall();
283
+ });
284
+ });
285
+ autoUpdater.on('error', (error) => {
286
+ logger.error('Update error:', error);
287
+ });
288
+ }
289
+ let extensionsLoaded = false;
290
+ /** Load development extensions only once after website loads successfully */
291
+ async function loadDevExtensions() {
292
+ // Only load extensions in dev mode or when explicitly enabled
293
+ if (!isDev && !app.commandLine.hasSwitch('devtoolextensions')) {
294
+ return;
295
+ }
296
+ if (app.commandLine.hasSwitch('devtoolextensions') && app.commandLine.getSwitchValue('devtoolextensions') === '0') {
297
+ return;
298
+ }
299
+ try {
300
+ const reactDevTools = await installExtension(REACT_DEVELOPER_TOOLS);
301
+ logger.log(`🔧 Added Extension: ${reactDevTools}`);
302
+ }
303
+ catch (err) {
304
+ logger.log('❌ React DevTools installation failed:', err);
305
+ }
306
+ try {
307
+ const mobxDevTools = await installExtension(MOBX_DEVTOOLS);
308
+ logger.log(`🔧 Added Extension: ${mobxDevTools}`);
309
+ }
310
+ catch (err) {
311
+ logger.log('❌ MobX DevTools installation failed:', err);
312
+ }
313
+ extensionsLoaded = true;
314
+ logger.log('🔧 Extension loading completed');
315
+ }
@@ -0,0 +1,208 @@
1
+ import { app, Menu } from 'electron';
2
+ import { buildProject, checkUpdates, openAppLog, showAbout, showInExplorer } from './actions.js';
3
+ export function buildAppMenu(mainWindow) {
4
+ const isMac = process.platform === 'darwin';
5
+ if (isMac) {
6
+ return buildMacMenu(mainWindow);
7
+ }
8
+ return buildWindowsMenu(mainWindow);
9
+ }
10
+ function buildMacMenu(mainWindow) {
11
+ const menuTemplate = [
12
+ {
13
+ label: app.name,
14
+ submenu: [
15
+ {
16
+ label: `About ${app.name}`,
17
+ click: () => showAbout(mainWindow)
18
+ },
19
+ { type: 'separator' },
20
+ {
21
+ label: 'Check for Updates',
22
+ click: checkUpdates
23
+ },
24
+ { type: 'separator' },
25
+ { role: 'services' },
26
+ { type: 'separator' },
27
+ { role: 'hide' },
28
+ { role: 'hideOthers' },
29
+ { role: 'unhide' },
30
+ { type: 'separator' },
31
+ {
32
+ label: `Quit ${app.name}`,
33
+ accelerator: 'Cmd+Q',
34
+ click: () => app.quit()
35
+ }
36
+ ]
37
+ },
38
+ {
39
+ label: 'Project',
40
+ submenu: [
41
+ {
42
+ label: 'Build Project',
43
+ accelerator: 'Cmd+B',
44
+ click: () => buildProject(true)
45
+ },
46
+ { type: 'separator' },
47
+ {
48
+ label: 'Show in Finder',
49
+ accelerator: 'Cmd+E',
50
+ click: showInExplorer
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ label: 'Edit',
56
+ submenu: [
57
+ { label: 'Undo', role: 'undo' },
58
+ { label: 'Redo', role: 'redo' },
59
+ { type: 'separator' },
60
+ { label: 'Cut', role: 'cut' },
61
+ { label: 'Copy', role: 'copy' },
62
+ { label: 'Paste', role: 'paste' },
63
+ { label: 'Paste and Match Style', role: 'pasteAndMatchStyle' },
64
+ { label: 'Delete', role: 'delete' },
65
+ { label: 'Select All', role: 'selectAll' }
66
+ ]
67
+ },
68
+ {
69
+ label: 'View',
70
+ submenu: [
71
+ {
72
+ label: 'Reload',
73
+ accelerator: 'Cmd+R',
74
+ click: () => mainWindow?.reload()
75
+ },
76
+ {
77
+ label: 'Force Reload',
78
+ accelerator: 'Cmd+Shift+R',
79
+ click: () => mainWindow?.webContents.reloadIgnoringCache()
80
+ },
81
+ { type: 'separator' },
82
+ { label: 'Actual Size', role: 'resetZoom' },
83
+ { label: 'Zoom In', role: 'zoomIn' },
84
+ { label: 'Zoom Out', role: 'zoomOut' },
85
+ { type: 'separator' },
86
+ { label: 'Toggle Full Screen', role: 'togglefullscreen' },
87
+ {
88
+ label: 'Toggle Full Screen',
89
+ accelerator: 'F11',
90
+ visible: false,
91
+ click: () => mainWindow?.setFullScreen(!mainWindow.isFullScreen())
92
+ }
93
+ ]
94
+ },
95
+ {
96
+ label: 'Tools',
97
+ submenu: [
98
+ {
99
+ label: 'Toggle Developer Console',
100
+ accelerator: 'F12',
101
+ click: () => mainWindow?.webContents.toggleDevTools()
102
+ },
103
+ { type: 'separator' },
104
+ {
105
+ label: 'Open App Log',
106
+ click: openAppLog
107
+ }
108
+ ]
109
+ }
110
+ ];
111
+ return Menu.buildFromTemplate(menuTemplate);
112
+ }
113
+ function buildWindowsMenu(mainWindow) {
114
+ const menuTemplate = [
115
+ {
116
+ label: 'Project',
117
+ submenu: [
118
+ {
119
+ label: 'Build Project',
120
+ accelerator: 'Ctrl+B',
121
+ click: () => buildProject(true)
122
+ },
123
+ { type: 'separator' },
124
+ {
125
+ label: 'Show in Explorer',
126
+ accelerator: 'Ctrl+E',
127
+ click: showInExplorer
128
+ }
129
+ ]
130
+ },
131
+ {
132
+ label: 'Edit',
133
+ submenu: [
134
+ { label: 'Undo', role: 'undo' },
135
+ { label: 'Redo', role: 'redo' },
136
+ { type: 'separator' },
137
+ { label: 'Cut', role: 'cut' },
138
+ { label: 'Copy', role: 'copy' },
139
+ { label: 'Paste', role: 'paste' },
140
+ { label: 'Paste and Match Style', role: 'pasteAndMatchStyle' },
141
+ { label: 'Delete', role: 'delete' },
142
+ { label: 'Select All', role: 'selectAll' }
143
+ ]
144
+ },
145
+ {
146
+ label: 'View',
147
+ submenu: [
148
+ {
149
+ label: 'Reload',
150
+ accelerator: 'Ctrl+R',
151
+ click: () => mainWindow?.reload()
152
+ },
153
+ {
154
+ label: 'Force Reload',
155
+ accelerator: 'Ctrl+Shift+R',
156
+ click: () => mainWindow?.webContents.reloadIgnoringCache()
157
+ },
158
+ { type: 'separator' },
159
+ {
160
+ label: 'Toggle Developer Console',
161
+ accelerator: 'F12',
162
+ click: () => mainWindow?.webContents.toggleDevTools()
163
+ },
164
+ { type: 'separator' },
165
+ { label: 'Actual Size', role: 'resetZoom' },
166
+ { label: 'Zoom In', role: 'zoomIn' },
167
+ { label: 'Zoom Out', role: 'zoomOut' },
168
+ { type: 'separator' },
169
+ { label: 'Toggle Full Screen', role: 'togglefullscreen', accelerator: 'F11' }
170
+ ]
171
+ },
172
+ {
173
+ label: 'Tools',
174
+ submenu: [
175
+ {
176
+ label: 'Check for Updates',
177
+ click: checkUpdates
178
+ },
179
+ { type: 'separator' },
180
+ {
181
+ label: 'Open App Log',
182
+ click: openAppLog
183
+ }
184
+ ]
185
+ },
186
+ {
187
+ label: 'Help',
188
+ submenu: [
189
+ {
190
+ label: `About ${app.name}`,
191
+ click: () => showAbout(mainWindow)
192
+ }
193
+ ]
194
+ },
195
+ {
196
+ label: '',
197
+ submenu: [
198
+ {
199
+ label: `Quit ${app.name}`,
200
+ accelerator: 'Ctrl+Q',
201
+ click: () => app.quit()
202
+ }
203
+ ],
204
+ visible: false
205
+ }
206
+ ];
207
+ return Menu.buildFromTemplate(menuTemplate);
208
+ }