@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.
- package/README.md +60 -0
- package/dist/src/asset-pack/eslint.config.js +58 -0
- package/dist/src/asset-pack/scripts/post-install.js +64 -0
- package/dist/src/asset-pack/src/index.js +1 -0
- package/dist/src/core/cli.js +303 -0
- package/dist/src/core/common.js +325 -0
- package/dist/src/core/index.js +6 -0
- package/dist/src/core/tools/build-project.js +456 -0
- package/dist/src/core/tools/index.js +2 -0
- package/dist/src/core/tools/new-asset-pack.js +153 -0
- package/dist/src/core/tools/new-project.js +293 -0
- package/dist/src/core/types.js +1 -0
- package/dist/src/dependencies.js +84 -0
- package/dist/src/electron/IpcSerializableError.js +38 -0
- package/dist/src/electron/api.js +7 -0
- package/dist/src/electron/backend/actions.js +56 -0
- package/dist/src/electron/backend/handler.js +452 -0
- package/dist/src/electron/backend/logging.js +41 -0
- package/dist/src/electron/backend/main.js +369 -0
- package/dist/src/electron/backend/menu.js +196 -0
- package/dist/src/electron/backend/state.js +201 -0
- package/dist/src/electron/backend/telemetry.js +9 -0
- package/dist/src/electron/backend/tools/const.js +9 -0
- package/dist/src/electron/backend/tools/file-server.js +383 -0
- package/dist/src/electron/backend/tools/open-project.js +249 -0
- package/dist/src/electron/backend/window.js +161 -0
- package/dist/src/templates/eslint.config.js +58 -0
- package/dist/src/templates/scripts/genesys/build-project.js +42 -0
- package/dist/src/templates/scripts/genesys/calc-bounding-box.js +205 -0
- package/dist/src/templates/scripts/genesys/common.js +36 -0
- package/dist/src/templates/scripts/genesys/const.js +9 -0
- package/dist/src/templates/scripts/genesys/dev/dump-default-scene.js +8 -0
- package/dist/src/templates/scripts/genesys/dev/generate-manifest.js +116 -0
- package/dist/src/templates/scripts/genesys/dev/launcher.js +39 -0
- package/dist/src/templates/scripts/genesys/dev/storage-provider.js +188 -0
- package/dist/src/templates/scripts/genesys/dev/update-template-scenes.js +67 -0
- package/dist/src/templates/scripts/genesys/doc-server.js +12 -0
- package/dist/src/templates/scripts/genesys/genesys-mcp.js +413 -0
- package/dist/src/templates/scripts/genesys/mcp/doc-tools.js +70 -0
- package/dist/src/templates/scripts/genesys/mcp/editor-functions.js +123 -0
- package/dist/src/templates/scripts/genesys/mcp/editor-tools.js +51 -0
- package/dist/src/templates/scripts/genesys/mcp/get-scene-state.js +26 -0
- package/dist/src/templates/scripts/genesys/mcp/run-subprocess.js +23 -0
- package/dist/src/templates/scripts/genesys/mcp/search-actors.js +703 -0
- package/dist/src/templates/scripts/genesys/mcp/search-assets.js +296 -0
- package/dist/src/templates/scripts/genesys/mcp/utils.js +234 -0
- package/dist/src/templates/scripts/genesys/migrate-scenes-and-prefabs.js +252 -0
- package/dist/src/templates/scripts/genesys/misc.js +32 -0
- package/dist/src/templates/scripts/genesys/mock.js +5 -0
- package/dist/src/templates/scripts/genesys/place-actors.js +112 -0
- package/dist/src/templates/scripts/genesys/post-install.js +33 -0
- package/dist/src/templates/scripts/genesys/remove-engine-comments.js +113 -0
- package/dist/src/templates/scripts/genesys/storageProvider.js +146 -0
- package/dist/src/templates/scripts/genesys/validate-prefabs.js +115 -0
- package/dist/src/templates/src/index.js +20 -0
- package/dist/src/templates/src/templates/firstPerson/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/firstPerson/src/game.js +30 -0
- package/dist/src/templates/src/templates/firstPerson/src/player.js +55 -0
- package/dist/src/templates/src/templates/fps/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/fps/src/game.js +30 -0
- package/dist/src/templates/src/templates/fps/src/player.js +60 -0
- package/dist/src/templates/src/templates/fps/src/weapon.js +54 -0
- package/dist/src/templates/src/templates/freeCamera/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/freeCamera/src/game.js +30 -0
- package/dist/src/templates/src/templates/freeCamera/src/player.js +38 -0
- package/dist/src/templates/src/templates/sideScroller/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/sideScroller/src/const.js +43 -0
- package/dist/src/templates/src/templates/sideScroller/src/game.js +102 -0
- package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
- package/dist/src/templates/src/templates/sideScroller/src/player.js +100 -0
- package/dist/src/templates/src/templates/thirdPerson/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/thirdPerson/src/game.js +30 -0
- package/dist/src/templates/src/templates/thirdPerson/src/player.js +58 -0
- package/dist/src/templates/src/templates/vehicle/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/vehicle/src/base-vehicle.js +122 -0
- package/dist/src/templates/src/templates/vehicle/src/game.js +33 -0
- package/dist/src/templates/src/templates/vehicle/src/mesh-vehicle.js +188 -0
- package/dist/src/templates/src/templates/vehicle/src/player.js +97 -0
- package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +258 -0
- package/dist/src/templates/src/templates/vehicle/src/ui-hints.js +100 -0
- package/dist/src/templates/src/templates/vr-game/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/vr-game/src/game.js +55 -0
- package/dist/src/templates/src/templates/vr-game/src/sample-vr-actor.js +29 -0
- package/dist/src/templates/vite.config.js +46 -0
- package/package.json +181 -0
- package/scripts/post-install.ts +143 -0
- package/src/asset-pack/.gitattributes +89 -0
- package/src/asset-pack/.github/workflows/publish.yml +90 -0
- package/src/asset-pack/eslint.config.js +59 -0
- package/src/asset-pack/gitignore +11 -0
- package/src/asset-pack/scripts/post-install.ts +81 -0
- package/src/asset-pack/src/index.ts +0 -0
- package/src/asset-pack/tsconfig.json +34 -0
- package/src/templates/.cursor/mcp.json +20 -0
- package/src/templates/.cursorignore +2 -0
- package/src/templates/.gitattributes +89 -0
- package/src/templates/.vscode/settings.json +6 -0
- package/src/templates/AGENTS.md +104 -0
- package/src/templates/CLAUDE.md +1 -0
- package/src/templates/README.md +24 -0
- package/src/templates/eslint.config.js +60 -0
- package/src/templates/gitignore +11 -0
- package/src/templates/index.html +34 -0
- package/src/templates/pnpm-lock.yaml +3676 -0
- package/src/templates/scripts/genesys/build-project.ts +51 -0
- package/src/templates/scripts/genesys/calc-bounding-box.ts +272 -0
- package/src/templates/scripts/genesys/common.ts +46 -0
- package/src/templates/scripts/genesys/const.ts +9 -0
- package/src/templates/scripts/genesys/dev/dump-default-scene.ts +11 -0
- package/src/templates/scripts/genesys/dev/generate-manifest.ts +146 -0
- package/src/templates/scripts/genesys/dev/launcher.ts +46 -0
- package/src/templates/scripts/genesys/dev/storage-provider.ts +229 -0
- package/src/templates/scripts/genesys/dev/update-template-scenes.ts +84 -0
- package/src/templates/scripts/genesys/doc-server.ts +16 -0
- package/src/templates/scripts/genesys/genesys-mcp.ts +526 -0
- package/src/templates/scripts/genesys/mcp/doc-tools.ts +86 -0
- package/src/templates/scripts/genesys/mcp/editor-functions.ts +151 -0
- package/src/templates/scripts/genesys/mcp/editor-tools.ts +73 -0
- package/src/templates/scripts/genesys/mcp/get-scene-state.ts +35 -0
- package/src/templates/scripts/genesys/mcp/run-subprocess.ts +30 -0
- package/src/templates/scripts/genesys/mcp/search-actors.ts +858 -0
- package/src/templates/scripts/genesys/mcp/search-assets.ts +380 -0
- package/src/templates/scripts/genesys/mcp/utils.ts +281 -0
- package/src/templates/scripts/genesys/migrate-scenes-and-prefabs.ts +301 -0
- package/src/templates/scripts/genesys/misc.ts +42 -0
- package/src/templates/scripts/genesys/mock.ts +6 -0
- package/src/templates/scripts/genesys/place-actors.ts +179 -0
- package/src/templates/scripts/genesys/post-install.ts +39 -0
- package/src/templates/scripts/genesys/prefab.schema.json +85 -0
- package/src/templates/scripts/genesys/remove-engine-comments.ts +135 -0
- package/src/templates/scripts/genesys/run-mcp-inspector.bat +5 -0
- package/src/templates/scripts/genesys/storageProvider.ts +182 -0
- package/src/templates/scripts/genesys/validate-prefabs.ts +138 -0
- package/src/templates/src/index.ts +22 -0
- package/src/templates/src/templates/firstPerson/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/firstPerson/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/firstPerson/src/game.ts +39 -0
- package/src/templates/src/templates/firstPerson/src/player.ts +59 -0
- package/src/templates/src/templates/fps/assets/default.genesys-scene +9460 -0
- package/src/templates/src/templates/fps/assets/models/SM_Beam_400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_ChamferCube.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Ramp_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Rifle.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/fps/src/game.ts +39 -0
- package/src/templates/src/templates/fps/src/player.ts +66 -0
- package/src/templates/src/templates/fps/src/weapon.ts +47 -0
- package/src/templates/src/templates/freeCamera/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/freeCamera/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/freeCamera/src/game.ts +39 -0
- package/src/templates/src/templates/freeCamera/src/player.ts +40 -0
- package/src/templates/src/templates/sideScroller/assets/default.genesys-scene +122 -0
- package/src/templates/src/templates/sideScroller/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/sideScroller/src/const.ts +46 -0
- package/src/templates/src/templates/sideScroller/src/game.ts +121 -0
- package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
- package/src/templates/src/templates/sideScroller/src/player.ts +123 -0
- package/src/templates/src/templates/thirdPerson/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/thirdPerson/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/thirdPerson/src/game.ts +39 -0
- package/src/templates/src/templates/thirdPerson/src/player.ts +58 -0
- package/src/templates/src/templates/vehicle/assets/default.genesys-scene +226 -0
- package/src/templates/src/templates/vehicle/assets/models/cyberTruck/chassis.glb +0 -0
- package/src/templates/src/templates/vehicle/assets/models/cyberTruck/wheel.glb +0 -0
- package/src/templates/src/templates/vehicle/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/vehicle/src/base-vehicle.ts +145 -0
- package/src/templates/src/templates/vehicle/src/game.ts +43 -0
- package/src/templates/src/templates/vehicle/src/mesh-vehicle.ts +189 -0
- package/src/templates/src/templates/vehicle/src/player.ts +106 -0
- package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +264 -0
- package/src/templates/src/templates/vehicle/src/ui-hints.ts +101 -0
- package/src/templates/src/templates/vr-game/assets/default.genesys-scene +247 -0
- package/src/templates/src/templates/vr-game/src/auto-imports.ts +1 -0
- package/src/templates/src/templates/vr-game/src/game.ts +66 -0
- package/src/templates/src/templates/vr-game/src/sample-vr-actor.ts +26 -0
- package/src/templates/tsconfig.json +35 -0
- package/src/templates/vite.config.ts +52 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { app, BrowserWindow, dialog, Menu, session } from 'electron';
|
|
5
|
+
import isDev from 'electron-is-dev';
|
|
6
|
+
import log from 'electron-log';
|
|
7
|
+
import electronUpdater from 'electron-updater';
|
|
8
|
+
import { getAppInfo } from './handler.js';
|
|
9
|
+
import { configureLogging, logger } from './logging.js';
|
|
10
|
+
import { buildAppMenu } from './menu.js';
|
|
11
|
+
import { configureTelemetry } from './telemetry.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
|
+
configureTelemetry();
|
|
27
|
+
configureLogging();
|
|
28
|
+
start();
|
|
29
|
+
function start() {
|
|
30
|
+
// Register deep link protocols
|
|
31
|
+
registerDeepLinkProtocols();
|
|
32
|
+
const hasLock = app.requestSingleInstanceLock();
|
|
33
|
+
app.on('second-instance', (event, argv, workingDirectory, additionalData) => {
|
|
34
|
+
logger.log('🔗 [deep-link] Second instance detected, checking for deep link URL');
|
|
35
|
+
// Handle deep link from second instance
|
|
36
|
+
const deepLinkUrl = getDeepLinkFromArgs(argv);
|
|
37
|
+
if (deepLinkUrl) {
|
|
38
|
+
logger.log('🔗 [deep-link] Processing URL from second instance:', deepLinkUrl);
|
|
39
|
+
handleDeepLink(deepLinkUrl);
|
|
40
|
+
}
|
|
41
|
+
if (mainWindow) {
|
|
42
|
+
mainWindow.isMinimized() && mainWindow.restore();
|
|
43
|
+
mainWindow.focus();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
if (!hasLock) {
|
|
47
|
+
return app.quit();
|
|
48
|
+
}
|
|
49
|
+
// Handle deep link from first instance
|
|
50
|
+
const deepLinkUrl = getDeepLinkFromArgs(process.argv);
|
|
51
|
+
if (deepLinkUrl) {
|
|
52
|
+
logger.log('🔗 [deep-link] Processing URL from first instance:', deepLinkUrl);
|
|
53
|
+
pendingDeepLinkUrl = deepLinkUrl;
|
|
54
|
+
}
|
|
55
|
+
// Get custom URL from command line arguments (--url=https://example.com)
|
|
56
|
+
const customUrl = app.commandLine.hasSwitch('url') ? app.commandLine.getSwitchValue('url') : undefined;
|
|
57
|
+
if (customUrl) {
|
|
58
|
+
logger.log('Custom URL provided:', customUrl);
|
|
59
|
+
}
|
|
60
|
+
logger.log('===============================================');
|
|
61
|
+
logger.log(`\n${JSON.stringify(getAppInfo(), null, 2)}`);
|
|
62
|
+
logger.log('===============================================');
|
|
63
|
+
// Handle macOS deep links
|
|
64
|
+
app.on('open-url', (event, url) => {
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
logger.log('🔗 [deep-link] macOS open-url event:', url);
|
|
67
|
+
handleDeepLink(url);
|
|
68
|
+
});
|
|
69
|
+
app.whenReady().then(async () => {
|
|
70
|
+
await initMainWindow();
|
|
71
|
+
Menu.setApplicationMenu(buildAppMenu(mainWindow));
|
|
72
|
+
checkForUpdates();
|
|
73
|
+
// Process pending deep link after window is ready
|
|
74
|
+
if (pendingDeepLinkUrl) {
|
|
75
|
+
logger.log('🔗 [deep-link] Processing pending deep link URL:', pendingDeepLinkUrl);
|
|
76
|
+
handleDeepLink(pendingDeepLinkUrl);
|
|
77
|
+
pendingDeepLinkUrl = null;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
app.on('window-all-closed', () => {
|
|
81
|
+
if (process.platform !== 'darwin')
|
|
82
|
+
app.quit();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Register deep link protocols based on environment */
|
|
86
|
+
function registerDeepLinkProtocols() {
|
|
87
|
+
const protocol = isDev ? 'genesys-dev' : 'genesys';
|
|
88
|
+
let success = false;
|
|
89
|
+
if (process.defaultApp) {
|
|
90
|
+
// Development mode - need to specify execPath and argv
|
|
91
|
+
if (process.argv.length >= 2) {
|
|
92
|
+
success = app.setAsDefaultProtocolClient(protocol, process.execPath, [path.resolve(process.argv[1])]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// Production mode - simple registration
|
|
97
|
+
success = app.setAsDefaultProtocolClient(protocol);
|
|
98
|
+
}
|
|
99
|
+
if (success) {
|
|
100
|
+
logger.log(`🔗 [deep-link] Successfully registered protocol: ${protocol}://`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
logger.warn(`⚠️ [deep-link] Failed to register protocol: ${protocol}://`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Extract deep link URL from command line arguments */
|
|
107
|
+
function getDeepLinkFromArgs(argv) {
|
|
108
|
+
const protocol = isDev ? 'genesys-dev://' : 'genesys://';
|
|
109
|
+
for (const arg of argv) {
|
|
110
|
+
if (arg.startsWith(protocol)) {
|
|
111
|
+
return arg;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
/** Handle deep link URL */
|
|
117
|
+
function handleDeepLink(url) {
|
|
118
|
+
logger.log('🔗 [deep-link] Handling deep link:', url);
|
|
119
|
+
try {
|
|
120
|
+
const parsedUrl = new URL(url);
|
|
121
|
+
logger.log('🔗 [deep-link] Parsed URL:', parsedUrl.toString());
|
|
122
|
+
// Send deep link to renderer process if window is ready
|
|
123
|
+
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
124
|
+
mainWindow.webContents.send('deep-link', parsedUrl.toString());
|
|
125
|
+
logger.log('🔗 [deep-link] Deep link sent to renderer process');
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Store for later if window isn't ready
|
|
129
|
+
pendingDeepLinkUrl = url;
|
|
130
|
+
logger.log('🔗 [deep-link] Window not ready, storing deep link for later');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
logger.error('❌ [deep-link] Failed to parse deep link URL:', error);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const windowOptions = {
|
|
138
|
+
backgroundColor: '#13171b',
|
|
139
|
+
hasShadow: true,
|
|
140
|
+
titleBarStyle: 'hidden',
|
|
141
|
+
titleBarOverlay: false,
|
|
142
|
+
minWidth: 1024,
|
|
143
|
+
minHeight: 720,
|
|
144
|
+
};
|
|
145
|
+
async function showLocalDevError() {
|
|
146
|
+
const result = await dialog.showMessageBox(mainWindow, {
|
|
147
|
+
type: 'error',
|
|
148
|
+
buttons: ['Refresh (Ctrl+Shift+R)', 'OK'],
|
|
149
|
+
title: 'Local Development Server Not Running',
|
|
150
|
+
message: 'Failed to connect to local development server',
|
|
151
|
+
detail: 'Run "pnpm dev" on the .ai project and then refresh this page'
|
|
152
|
+
});
|
|
153
|
+
if (result.response === 0) {
|
|
154
|
+
// Refresh the page
|
|
155
|
+
try {
|
|
156
|
+
await mainWindow.loadURL(GENESYS_LOCAL_URL);
|
|
157
|
+
logger.log('Genesys.ai localhost');
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
logger.error('Failed to load local URL:', error);
|
|
161
|
+
await showLocalDevError();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function showUrlLoadError(message) {
|
|
166
|
+
await dialog.showMessageBox(mainWindow, {
|
|
167
|
+
type: 'error',
|
|
168
|
+
buttons: ['OK'],
|
|
169
|
+
title: 'Connection Error',
|
|
170
|
+
message,
|
|
171
|
+
detail: 'Please check your internet connection and try again'
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
async function initMainWindow() {
|
|
175
|
+
// Create main window with title bar overlay
|
|
176
|
+
mainWindow = createWindow('main', {
|
|
177
|
+
show: false,
|
|
178
|
+
title: 'Genesys',
|
|
179
|
+
...windowOptions,
|
|
180
|
+
webPreferences: {
|
|
181
|
+
sandbox: true,
|
|
182
|
+
contextIsolation: true,
|
|
183
|
+
preload: path.join(__dirname, '../../../preload/electron/preload.js'),
|
|
184
|
+
nodeIntegration: false,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
mainWindow.webContents.on('did-finish-load', async () => {
|
|
188
|
+
logger.log('🌐 Website loaded successfully...');
|
|
189
|
+
if (isDev && !extensionsLoaded) {
|
|
190
|
+
await loadDevExtensions();
|
|
191
|
+
}
|
|
192
|
+
mainWindow.show();
|
|
193
|
+
});
|
|
194
|
+
// Options for new windows
|
|
195
|
+
mainWindow.webContents.setWindowOpenHandler(({ url, frameName, features }) => {
|
|
196
|
+
const parsedFeatures = parseFeatures(features);
|
|
197
|
+
logger.log('Open window', url, features, parsedFeatures);
|
|
198
|
+
return {
|
|
199
|
+
action: 'allow',
|
|
200
|
+
createWindow: (options) => {
|
|
201
|
+
const newWindow = new BrowserWindow(options);
|
|
202
|
+
newWindow.setMenu(null); // Remove menu bar
|
|
203
|
+
return newWindow.webContents;
|
|
204
|
+
},
|
|
205
|
+
overrideBrowserWindowOptions: {
|
|
206
|
+
...windowOptions,
|
|
207
|
+
titleBarOverlay: (process.platform === 'darwin') ? false : {
|
|
208
|
+
color: '#13171b',
|
|
209
|
+
symbolColor: '#FFFFFF',
|
|
210
|
+
height: 44,
|
|
211
|
+
},
|
|
212
|
+
minWidth: 800,
|
|
213
|
+
minHeight: 600,
|
|
214
|
+
width: parsedFeatures.width,
|
|
215
|
+
height: parsedFeatures.height,
|
|
216
|
+
fullscreen: parsedFeatures.fullscreen,
|
|
217
|
+
title: parsedFeatures.title,
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
// Get custom URL from command line arguments
|
|
222
|
+
const customUrl = process.argv.find(arg => arg.startsWith('--url='))?.split('=')[1];
|
|
223
|
+
if (customUrl) {
|
|
224
|
+
try {
|
|
225
|
+
await mainWindow.loadURL(customUrl);
|
|
226
|
+
logger.log('Loading custom URL:', customUrl);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
logger.error('Failed to load custom URL:', error);
|
|
230
|
+
await showUrlLoadError('Failed to load custom URL');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else if (isDev) {
|
|
234
|
+
if (process.env.DEV_HOSTED) {
|
|
235
|
+
try {
|
|
236
|
+
await mainWindow.loadURL(GENESYS_URL);
|
|
237
|
+
logger.log('Genesys.ai hosted');
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
logger.error('Failed to load hosted URL:', error);
|
|
241
|
+
await showUrlLoadError('Failed to load hosted Genesys.ai');
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
try {
|
|
246
|
+
await mainWindow.loadURL(GENESYS_LOCAL_URL);
|
|
247
|
+
logger.log('Genesys.ai localhost');
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
logger.error('Failed to load local URL:', error);
|
|
251
|
+
await showLocalDevError();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
mainWindow.webContents.openDevTools();
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
try {
|
|
258
|
+
await mainWindow.loadURL(GENESYS_URL);
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
logger.error('Failed to load production URL:', error);
|
|
262
|
+
await showUrlLoadError('Failed to load Genesys.ai');
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
;
|
|
267
|
+
function checkForUpdates() {
|
|
268
|
+
// Check for GH_TOKEN environment variable
|
|
269
|
+
if (!process.env.GH_TOKEN) {
|
|
270
|
+
logger.warn('GH_TOKEN environment variable is missing - update check will be skipped');
|
|
271
|
+
dialog.showMessageBox({
|
|
272
|
+
type: 'warning',
|
|
273
|
+
buttons: ['OK'],
|
|
274
|
+
title: 'Update Check Warning',
|
|
275
|
+
message: 'GitHub Token Missing',
|
|
276
|
+
detail: 'The GH_TOKEN environment variable is not set.\n\nUpdate checks require a GitHub token to access private releases.\n\nPlease set the GH_TOKEN environment variable and restart the application to enable automatic updates.',
|
|
277
|
+
});
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
autoUpdater.logger = log;
|
|
281
|
+
autoUpdater.checkForUpdatesAndNotify();
|
|
282
|
+
autoUpdater.on('update-available', () => {
|
|
283
|
+
logger.log('App update available');
|
|
284
|
+
mainWindow?.webContents.send('update_available');
|
|
285
|
+
});
|
|
286
|
+
autoUpdater.on('update-downloaded', info => {
|
|
287
|
+
const currentVersion = app.getVersion();
|
|
288
|
+
logger.log(`App update downloaded: v${currentVersion} -> v${info.version}`);
|
|
289
|
+
dialog.showMessageBox(mainWindow, {
|
|
290
|
+
type: 'info',
|
|
291
|
+
buttons: ['Restart', 'Later'],
|
|
292
|
+
title: 'SDK App Update Ready',
|
|
293
|
+
message: `Update to v${info.version} is ready to install`,
|
|
294
|
+
detail: `Current version: v${currentVersion}\nNew version: v${info.version}\n\nRestart now to complete the update?`,
|
|
295
|
+
}).then(({ response }) => {
|
|
296
|
+
if (response === 0)
|
|
297
|
+
autoUpdater.quitAndInstall();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
autoUpdater.on('error', (error) => {
|
|
301
|
+
logger.error('Update error:', error);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
let extensionsLoaded = false;
|
|
305
|
+
// Chrome Web Store extension IDs
|
|
306
|
+
const REACT_DEVELOPER_TOOLS_ID = 'fmkadmapgofadopljbjfkapdkoienihi';
|
|
307
|
+
const MOBX_DEVTOOLS_ID = 'pfgnfdagidkfgccljigdamigbcnndkod';
|
|
308
|
+
/** Get the path where Electron stores downloaded extensions */
|
|
309
|
+
function getExtensionsPath() {
|
|
310
|
+
return path.join(app.getPath('userData'), 'extensions');
|
|
311
|
+
}
|
|
312
|
+
/** Check if an extension is already downloaded */
|
|
313
|
+
function isExtensionDownloaded(extensionId) {
|
|
314
|
+
const extensionPath = path.join(getExtensionsPath(), extensionId);
|
|
315
|
+
return fs.existsSync(extensionPath);
|
|
316
|
+
}
|
|
317
|
+
/** Download extension using electron-devtools-installer (uses deprecated API but only for download) */
|
|
318
|
+
async function downloadExtension(extensionId, name) {
|
|
319
|
+
try {
|
|
320
|
+
// Dynamic import to avoid loading the module if not needed
|
|
321
|
+
const { installExtension } = await import('electron-devtools-installer');
|
|
322
|
+
await installExtension(extensionId);
|
|
323
|
+
logger.log(`🔧 Downloaded extension: ${name}`);
|
|
324
|
+
return path.join(getExtensionsPath(), extensionId);
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
logger.log(`❌ Failed to download ${name}:`, err);
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/** Load an extension using the new session.extensions API */
|
|
332
|
+
async function loadExtensionFromPath(extensionPath, name) {
|
|
333
|
+
try {
|
|
334
|
+
const extension = await session.defaultSession.extensions.loadExtension(extensionPath, { allowFileAccess: true });
|
|
335
|
+
logger.log(`🔧 Loaded extension: ${extension.name}`);
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
logger.log(`❌ Failed to load ${name}:`, err);
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/** Load development extensions only once after website loads successfully */
|
|
344
|
+
async function loadDevExtensions() {
|
|
345
|
+
// Only load extensions in dev mode or when explicitly enabled
|
|
346
|
+
if (!isDev && !app.commandLine.hasSwitch('devtoolextensions')) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (app.commandLine.hasSwitch('devtoolextensions') && app.commandLine.getSwitchValue('devtoolextensions') === '0') {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const extensions = [
|
|
353
|
+
{ id: REACT_DEVELOPER_TOOLS_ID, name: 'React Developer Tools' },
|
|
354
|
+
{ id: MOBX_DEVTOOLS_ID, name: 'MobX Developer Tools' },
|
|
355
|
+
];
|
|
356
|
+
for (const ext of extensions) {
|
|
357
|
+
const extensionPath = path.join(getExtensionsPath(), ext.id);
|
|
358
|
+
// If extension is not downloaded, download it first (uses deprecated API internally)
|
|
359
|
+
if (!isExtensionDownloaded(ext.id)) {
|
|
360
|
+
const downloadedPath = await downloadExtension(ext.id, ext.name);
|
|
361
|
+
if (!downloadedPath)
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
// Load using new API
|
|
365
|
+
await loadExtensionFromPath(extensionPath, ext.name);
|
|
366
|
+
}
|
|
367
|
+
extensionsLoaded = true;
|
|
368
|
+
logger.log('🔧 Extension loading completed.');
|
|
369
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { app, Menu } from 'electron';
|
|
2
|
+
import { 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: 'Show in Finder',
|
|
43
|
+
accelerator: 'Cmd+E',
|
|
44
|
+
click: showInExplorer
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: 'Edit',
|
|
50
|
+
submenu: [
|
|
51
|
+
{ label: 'Undo', role: 'undo' },
|
|
52
|
+
{ label: 'Redo', role: 'redo' },
|
|
53
|
+
{ type: 'separator' },
|
|
54
|
+
{ label: 'Cut', role: 'cut' },
|
|
55
|
+
{ label: 'Copy', role: 'copy' },
|
|
56
|
+
{ label: 'Paste', role: 'paste' },
|
|
57
|
+
{ label: 'Paste and Match Style', role: 'pasteAndMatchStyle' },
|
|
58
|
+
{ label: 'Delete', role: 'delete' },
|
|
59
|
+
{ label: 'Select All', role: 'selectAll' }
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
label: 'View',
|
|
64
|
+
submenu: [
|
|
65
|
+
{
|
|
66
|
+
label: 'Reload',
|
|
67
|
+
accelerator: 'Cmd+R',
|
|
68
|
+
click: () => mainWindow?.reload()
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
label: 'Force Reload',
|
|
72
|
+
accelerator: 'Cmd+Shift+R',
|
|
73
|
+
click: () => mainWindow?.webContents.reloadIgnoringCache()
|
|
74
|
+
},
|
|
75
|
+
{ type: 'separator' },
|
|
76
|
+
{ label: 'Actual Size', role: 'resetZoom' },
|
|
77
|
+
{ label: 'Zoom In', role: 'zoomIn' },
|
|
78
|
+
{ label: 'Zoom Out', role: 'zoomOut' },
|
|
79
|
+
{ type: 'separator' },
|
|
80
|
+
{ label: 'Toggle Full Screen', role: 'togglefullscreen' },
|
|
81
|
+
{
|
|
82
|
+
label: 'Toggle Full Screen',
|
|
83
|
+
accelerator: 'F11',
|
|
84
|
+
visible: false,
|
|
85
|
+
click: () => mainWindow?.setFullScreen(!mainWindow.isFullScreen())
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
label: 'Tools',
|
|
91
|
+
submenu: [
|
|
92
|
+
{
|
|
93
|
+
label: 'Toggle Developer Console',
|
|
94
|
+
accelerator: 'F12',
|
|
95
|
+
click: () => mainWindow?.webContents.toggleDevTools()
|
|
96
|
+
},
|
|
97
|
+
{ type: 'separator' },
|
|
98
|
+
{
|
|
99
|
+
label: 'Open App Log',
|
|
100
|
+
click: openAppLog
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
return Menu.buildFromTemplate(menuTemplate);
|
|
106
|
+
}
|
|
107
|
+
function buildWindowsMenu(mainWindow) {
|
|
108
|
+
const menuTemplate = [
|
|
109
|
+
{
|
|
110
|
+
label: 'Project',
|
|
111
|
+
submenu: [
|
|
112
|
+
{
|
|
113
|
+
label: 'Show in Explorer',
|
|
114
|
+
accelerator: 'Ctrl+E',
|
|
115
|
+
click: showInExplorer
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
label: 'Edit',
|
|
121
|
+
submenu: [
|
|
122
|
+
{ label: 'Undo', role: 'undo' },
|
|
123
|
+
{ label: 'Redo', role: 'redo' },
|
|
124
|
+
{ type: 'separator' },
|
|
125
|
+
{ label: 'Cut', role: 'cut' },
|
|
126
|
+
{ label: 'Copy', role: 'copy' },
|
|
127
|
+
{ label: 'Paste', role: 'paste' },
|
|
128
|
+
{ label: 'Paste and Match Style', role: 'pasteAndMatchStyle' },
|
|
129
|
+
{ label: 'Delete', role: 'delete' },
|
|
130
|
+
{ label: 'Select All', role: 'selectAll' }
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
label: 'View',
|
|
135
|
+
submenu: [
|
|
136
|
+
{
|
|
137
|
+
label: 'Reload',
|
|
138
|
+
accelerator: 'Ctrl+R',
|
|
139
|
+
click: () => mainWindow?.reload()
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
label: 'Force Reload',
|
|
143
|
+
accelerator: 'Ctrl+Shift+R',
|
|
144
|
+
click: () => mainWindow?.webContents.reloadIgnoringCache()
|
|
145
|
+
},
|
|
146
|
+
{ type: 'separator' },
|
|
147
|
+
{
|
|
148
|
+
label: 'Toggle Developer Console',
|
|
149
|
+
accelerator: 'F12',
|
|
150
|
+
click: () => mainWindow?.webContents.toggleDevTools()
|
|
151
|
+
},
|
|
152
|
+
{ type: 'separator' },
|
|
153
|
+
{ label: 'Actual Size', role: 'resetZoom' },
|
|
154
|
+
{ label: 'Zoom In', role: 'zoomIn' },
|
|
155
|
+
{ label: 'Zoom Out', role: 'zoomOut' },
|
|
156
|
+
{ type: 'separator' },
|
|
157
|
+
{ label: 'Toggle Full Screen', role: 'togglefullscreen', accelerator: 'F11' }
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
label: 'Tools',
|
|
162
|
+
submenu: [
|
|
163
|
+
{
|
|
164
|
+
label: 'Check for Updates',
|
|
165
|
+
click: checkUpdates
|
|
166
|
+
},
|
|
167
|
+
{ type: 'separator' },
|
|
168
|
+
{
|
|
169
|
+
label: 'Open App Log',
|
|
170
|
+
click: openAppLog
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
label: 'Help',
|
|
176
|
+
submenu: [
|
|
177
|
+
{
|
|
178
|
+
label: `About ${app.name}`,
|
|
179
|
+
click: () => showAbout(mainWindow)
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
label: '',
|
|
185
|
+
submenu: [
|
|
186
|
+
{
|
|
187
|
+
label: `Quit ${app.name}`,
|
|
188
|
+
accelerator: 'Ctrl+Q',
|
|
189
|
+
click: () => app.quit()
|
|
190
|
+
}
|
|
191
|
+
],
|
|
192
|
+
visible: false
|
|
193
|
+
}
|
|
194
|
+
];
|
|
195
|
+
return Menu.buildFromTemplate(menuTemplate);
|
|
196
|
+
}
|