projax 3.3.40 → 3.3.41

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 (70) hide show
  1. package/dist/api/database.d.ts +12 -1
  2. package/dist/api/database.d.ts.map +1 -1
  3. package/dist/api/database.js +139 -1
  4. package/dist/api/database.js.map +1 -1
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api/index.js +8 -0
  7. package/dist/api/index.js.map +1 -1
  8. package/dist/api/routes/backup.d.ts +3 -0
  9. package/dist/api/routes/backup.d.ts.map +1 -0
  10. package/dist/api/routes/backup.js +51 -0
  11. package/dist/api/routes/backup.js.map +1 -0
  12. package/dist/api/routes/index.d.ts.map +1 -1
  13. package/dist/api/routes/index.js +4 -0
  14. package/dist/api/routes/index.js.map +1 -1
  15. package/dist/api/routes/mcp.d.ts +3 -0
  16. package/dist/api/routes/mcp.d.ts.map +1 -0
  17. package/dist/api/routes/mcp.js +147 -0
  18. package/dist/api/routes/mcp.js.map +1 -0
  19. package/dist/api/routes/projects.d.ts.map +1 -1
  20. package/dist/api/routes/projects.js +20 -0
  21. package/dist/api/routes/projects.js.map +1 -1
  22. package/dist/api/routes/settings.d.ts.map +1 -1
  23. package/dist/api/routes/settings.js +64 -11
  24. package/dist/api/routes/settings.js.map +1 -1
  25. package/dist/api/routes/workspaces.d.ts +3 -0
  26. package/dist/api/routes/workspaces.d.ts.map +1 -0
  27. package/dist/api/routes/workspaces.js +429 -0
  28. package/dist/api/routes/workspaces.js.map +1 -0
  29. package/dist/api/types.d.ts +26 -0
  30. package/dist/api/types.d.ts.map +1 -1
  31. package/dist/core/backup-utils.d.ts +17 -0
  32. package/dist/core/backup-utils.js +166 -0
  33. package/dist/core/database.d.ts +1 -0
  34. package/dist/core/git-utils.d.ts +12 -0
  35. package/dist/core/git-utils.js +96 -0
  36. package/dist/core/index.d.ts +3 -0
  37. package/dist/core/index.js +3 -0
  38. package/dist/core/workspace-utils.d.ts +37 -0
  39. package/dist/core/workspace-utils.js +152 -0
  40. package/dist/electron/core/backup-utils.d.ts +17 -0
  41. package/dist/electron/core/backup-utils.js +166 -0
  42. package/dist/electron/core/database.d.ts +1 -0
  43. package/dist/electron/core/git-utils.d.ts +12 -0
  44. package/dist/electron/core/git-utils.js +96 -0
  45. package/dist/electron/core/index.d.ts +3 -0
  46. package/dist/electron/core/index.js +3 -0
  47. package/dist/electron/core/workspace-utils.d.ts +37 -0
  48. package/dist/electron/core/workspace-utils.js +152 -0
  49. package/dist/electron/main.js +324 -9
  50. package/dist/electron/preload.d.ts +14 -0
  51. package/dist/electron/preload.js +9 -0
  52. package/dist/electron/renderer/assets/index-B-etDnj2.js +64 -0
  53. package/dist/electron/renderer/assets/index-Bx18Cyic.js +64 -0
  54. package/dist/electron/renderer/assets/index-C8f5yNYe.js +64 -0
  55. package/dist/electron/renderer/assets/index-CIZ3Wl6c.css +1 -0
  56. package/dist/electron/renderer/assets/index-CJbsU9y8.css +1 -0
  57. package/dist/electron/renderer/assets/index-CWxXs5M7.css +1 -0
  58. package/dist/electron/renderer/assets/index-CopVNRnR.js +64 -0
  59. package/dist/electron/renderer/assets/index-CtXtIMer.js +64 -0
  60. package/dist/electron/renderer/assets/index-DUvcepWm.js +64 -0
  61. package/dist/electron/renderer/assets/index-DWe2TQFv.css +1 -0
  62. package/dist/electron/renderer/assets/index-DZzB20Xf.css +1 -0
  63. package/dist/electron/renderer/assets/index-DknLdADV.js +63 -0
  64. package/dist/electron/renderer/assets/index-DocuD8Lk.js +64 -0
  65. package/dist/electron/renderer/assets/index-DyU-xfd8.css +1 -0
  66. package/dist/electron/renderer/assets/index-GwC-JVUy.css +1 -0
  67. package/dist/electron/renderer/assets/index-fehviker.js +63 -0
  68. package/dist/electron/renderer/index.html +2 -2
  69. package/dist/index.js +281 -4
  70. package/package.json +1 -1
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const electron_1 = require("electron");
37
37
  const path = __importStar(require("path"));
38
38
  const fs = __importStar(require("fs"));
39
+ const http = __importStar(require("http"));
39
40
  const child_process_1 = require("child_process");
40
41
  const tail_1 = require("tail");
41
42
  const core_1 = require("./core");
@@ -73,12 +74,47 @@ else {
73
74
  preload: path.join(__dirname, 'preload.js'),
74
75
  nodeIntegration: false,
75
76
  contextIsolation: true,
77
+ webSecurity: true,
76
78
  },
79
+ show: false, // Don't show until ready
80
+ });
81
+ // Show window when ready to prevent white screen flash
82
+ mainWindow.once('ready-to-show', () => {
83
+ mainWindow?.show();
77
84
  });
78
85
  // Load the app
79
86
  if (isDev) {
80
- mainWindow.loadURL('http://localhost:7898');
81
- mainWindow.webContents.openDevTools();
87
+ // Wait for Vite dev server to be ready before loading
88
+ const checkServerAndLoad = (retries = 10) => {
89
+ const req = http.get('http://localhost:7898', (res) => {
90
+ console.log('Vite dev server is ready!');
91
+ mainWindow?.loadURL('http://localhost:7898');
92
+ mainWindow?.webContents.openDevTools();
93
+ });
94
+ req.on('error', (error) => {
95
+ if (retries > 0) {
96
+ console.log(`Vite dev server not ready (${retries} retries left), retrying in 1 second...`);
97
+ setTimeout(() => checkServerAndLoad(retries - 1), 1000);
98
+ }
99
+ else {
100
+ console.error('Failed to connect to Vite dev server after multiple retries');
101
+ console.error('Make sure Vite is running on port 7898');
102
+ mainWindow?.loadURL('http://localhost:7898'); // Try anyway
103
+ }
104
+ });
105
+ req.setTimeout(2000, () => {
106
+ req.destroy();
107
+ if (retries > 0) {
108
+ console.log(`Vite dev server timeout (${retries} retries left), retrying...`);
109
+ setTimeout(() => checkServerAndLoad(retries - 1), 1000);
110
+ }
111
+ else {
112
+ console.error('Failed to connect to Vite dev server - timeout');
113
+ mainWindow?.loadURL('http://localhost:7898'); // Try anyway
114
+ }
115
+ });
116
+ };
117
+ checkServerAndLoad();
82
118
  }
83
119
  else {
84
120
  // Try bundled renderer path first (when bundled in CLI: dist/electron/renderer/index.html)
@@ -113,6 +149,49 @@ else {
113
149
  mainWindow.on('closed', () => {
114
150
  mainWindow = null;
115
151
  });
152
+ // Handle page load errors
153
+ mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
154
+ console.error('Failed to load:', validatedURL, errorCode, errorDescription);
155
+ if (isDev && validatedURL === 'http://localhost:7898/') {
156
+ console.log('Retrying to load Vite dev server...');
157
+ setTimeout(() => {
158
+ mainWindow?.loadURL('http://localhost:7898');
159
+ }, 2000);
160
+ }
161
+ });
162
+ // Log when page finishes loading
163
+ mainWindow.webContents.on('did-finish-load', () => {
164
+ console.log('Page loaded successfully');
165
+ });
166
+ // Log console messages from renderer
167
+ mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => {
168
+ console.log(`[Renderer ${level}]:`, message, sourceId ? `(${sourceId}:${line})` : '');
169
+ });
170
+ // Log all console output from renderer
171
+ mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
172
+ if (isMainFrame) {
173
+ console.error('Main frame failed to load:', {
174
+ errorCode,
175
+ errorDescription,
176
+ validatedURL,
177
+ });
178
+ }
179
+ });
180
+ // Add keyboard shortcut to reload in dev mode
181
+ if (isDev) {
182
+ mainWindow.webContents.on('before-input-event', (event, input) => {
183
+ // Cmd+R or Ctrl+R to reload
184
+ if ((input.control || input.meta) && input.key.toLowerCase() === 'r') {
185
+ event.preventDefault();
186
+ mainWindow?.reload();
187
+ }
188
+ // Cmd+Shift+R or Ctrl+Shift+R to hard reload
189
+ if ((input.control || input.meta) && input.shift && input.key.toLowerCase() === 'r') {
190
+ event.preventDefault();
191
+ mainWindow?.webContents.reloadIgnoringCache();
192
+ }
193
+ });
194
+ }
116
195
  }
117
196
  // Start API server
118
197
  function startAPIServer() {
@@ -134,11 +213,18 @@ else {
134
213
  console.warn('API server not found. Some features may not work.');
135
214
  return;
136
215
  }
137
- console.log('Starting API server...');
216
+ console.log('Starting API server from:', apiPath);
217
+ // Kill any existing API server on the same port first
218
+ if (apiProcess) {
219
+ console.log('Killing existing API server...');
220
+ apiProcess.kill();
221
+ apiProcess = null;
222
+ }
138
223
  apiProcess = (0, child_process_1.spawn)('node', [apiPath], {
139
224
  detached: false,
140
225
  stdio: 'pipe',
141
226
  env: { ...process.env },
227
+ cwd: path.dirname(apiPath),
142
228
  });
143
229
  apiProcess.stdout?.on('data', (data) => {
144
230
  console.log(`[API] ${data.toString().trim()}`);
@@ -149,6 +235,13 @@ else {
149
235
  apiProcess.on('exit', (code) => {
150
236
  console.log(`API server exited with code ${code}`);
151
237
  apiProcess = null;
238
+ // Restart API server if it crashes (wait 2 seconds)
239
+ if (code !== 0) {
240
+ console.log('API server crashed, restarting in 2 seconds...');
241
+ setTimeout(() => {
242
+ startAPIServer();
243
+ }, 2000);
244
+ }
152
245
  });
153
246
  }
154
247
  catch (error) {
@@ -540,8 +633,8 @@ electron_1.ipcMain.handle('open-url', async (_, url) => {
540
633
  electron_1.ipcMain.handle('open-in-editor', async (_, projectPath) => {
541
634
  // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/core/settings)
542
635
  // Then try local dev path (packages/desktop/dist/main.js -> packages/core/dist/settings)
543
- const bundledSettingsPath = path.join(__dirname, '..', 'core', 'settings');
544
- const localSettingsPath = path.join(__dirname, '..', '..', '..', 'core', 'dist', 'settings');
636
+ const bundledSettingsPath = path.join(__dirname, 'core', 'settings');
637
+ const localSettingsPath = path.join(__dirname, '..', '..', 'core', 'dist', 'settings');
545
638
  let settingsPath;
546
639
  if (fs.existsSync(bundledSettingsPath + '.js')) {
547
640
  settingsPath = bundledSettingsPath;
@@ -580,6 +673,96 @@ electron_1.ipcMain.handle('open-in-editor', async (_, projectPath) => {
580
673
  stdio: 'ignore',
581
674
  }).unref();
582
675
  });
676
+ // Open workspace in editor
677
+ electron_1.ipcMain.handle('open-workspace', async (_, workspaceId) => {
678
+ try {
679
+ // Get workspace file path from API (ensures file exists)
680
+ const ports = [38124, 38125, 38126, 38127, 38128, 3001];
681
+ let apiBaseUrl = '';
682
+ for (const port of ports) {
683
+ try {
684
+ const response = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(500) });
685
+ if (response.ok) {
686
+ apiBaseUrl = `http://localhost:${port}/api`;
687
+ break;
688
+ }
689
+ }
690
+ catch {
691
+ continue;
692
+ }
693
+ }
694
+ if (!apiBaseUrl) {
695
+ throw new Error('API server not found');
696
+ }
697
+ // Get workspace file path (this will generate it if needed)
698
+ const response = await fetch(`${apiBaseUrl}/workspaces/${workspaceId}/file-path`);
699
+ if (!response.ok) {
700
+ throw new Error('Failed to get workspace file path');
701
+ }
702
+ const data = await response.json();
703
+ const workspace_file_path = data.workspace_file_path;
704
+ if (!fs.existsSync(workspace_file_path)) {
705
+ throw new Error('Workspace file does not exist');
706
+ }
707
+ // Open workspace file in editor (workspace files are opened with the workspace flag)
708
+ const bundledSettingsPath = path.join(__dirname, 'core', 'settings');
709
+ const localSettingsPath = path.join(__dirname, '..', '..', 'core', 'dist', 'settings');
710
+ let settingsPath;
711
+ if (fs.existsSync(bundledSettingsPath + '.js')) {
712
+ settingsPath = bundledSettingsPath;
713
+ }
714
+ else {
715
+ settingsPath = localSettingsPath;
716
+ }
717
+ const { getEditorSettings } = require(settingsPath);
718
+ const editorSettings = getEditorSettings();
719
+ let command;
720
+ let args = [];
721
+ if (editorSettings.type === 'custom' && editorSettings.customPath) {
722
+ command = editorSettings.customPath;
723
+ // For custom editors, try workspace file as argument
724
+ args = [workspace_file_path];
725
+ }
726
+ else {
727
+ switch (editorSettings.type) {
728
+ case 'vscode':
729
+ case 'cursor':
730
+ case 'windsurf':
731
+ // VS Code, Cursor, and Windsurf support opening workspace files directly
732
+ command = editorSettings.type === 'vscode' ? 'code' : editorSettings.type === 'cursor' ? 'cursor' : 'windsurf';
733
+ args = [workspace_file_path];
734
+ break;
735
+ case 'zed':
736
+ // Zed doesn't support workspace files, open the first project folder instead
737
+ const workspaceContent = JSON.parse(fs.readFileSync(workspace_file_path, 'utf-8'));
738
+ if (workspaceContent.folders && workspaceContent.folders.length > 0) {
739
+ const firstFolder = workspaceContent.folders[0];
740
+ const folderPath = path.isAbsolute(firstFolder.path)
741
+ ? firstFolder.path
742
+ : path.resolve(path.dirname(workspace_file_path), firstFolder.path);
743
+ command = 'zed';
744
+ args = [folderPath];
745
+ }
746
+ else {
747
+ throw new Error('Workspace has no folders to open');
748
+ }
749
+ break;
750
+ default:
751
+ command = 'code';
752
+ args = [workspace_file_path];
753
+ }
754
+ }
755
+ const { spawn } = require('child_process');
756
+ spawn(command, args, {
757
+ detached: true,
758
+ stdio: 'ignore',
759
+ }).unref();
760
+ }
761
+ catch (error) {
762
+ console.error('Error opening workspace:', error);
763
+ throw error;
764
+ }
765
+ });
583
766
  // Open project directory in file manager
584
767
  electron_1.ipcMain.handle('open-in-files', async (_, projectPath) => {
585
768
  try {
@@ -594,8 +777,8 @@ electron_1.ipcMain.handle('open-in-files', async (_, projectPath) => {
594
777
  electron_1.ipcMain.handle('get-settings', async () => {
595
778
  try {
596
779
  // Load settings module directly
597
- const bundledSettingsPath = path.join(__dirname, '..', 'core', 'settings');
598
- const localSettingsPath = path.join(__dirname, '..', '..', '..', 'core', 'dist', 'settings');
780
+ const bundledSettingsPath = path.join(__dirname, 'core', 'settings');
781
+ const localSettingsPath = path.join(__dirname, '..', '..', 'core', 'dist', 'settings');
599
782
  let settingsPath;
600
783
  if (fs.existsSync(bundledSettingsPath + '.js')) {
601
784
  settingsPath = bundledSettingsPath;
@@ -615,8 +798,8 @@ electron_1.ipcMain.handle('get-settings', async () => {
615
798
  electron_1.ipcMain.handle('save-settings', async (_, settings) => {
616
799
  try {
617
800
  // Load settings module directly
618
- const bundledSettingsPath = path.join(__dirname, '..', 'core', 'settings');
619
- const localSettingsPath = path.join(__dirname, '..', '..', '..', 'core', 'dist', 'settings');
801
+ const bundledSettingsPath = path.join(__dirname, 'core', 'settings');
802
+ const localSettingsPath = path.join(__dirname, '..', '..', 'core', 'dist', 'settings');
620
803
  let settingsPath;
621
804
  if (fs.existsSync(bundledSettingsPath + '.js')) {
622
805
  settingsPath = bundledSettingsPath;
@@ -722,3 +905,135 @@ electron_1.ipcMain.handle('unwatch-process-output', async (_, pid) => {
722
905
  }
723
906
  return { success: false };
724
907
  });
908
+ // Workspace handlers
909
+ electron_1.ipcMain.handle('get-workspaces', async () => {
910
+ try {
911
+ const response = await fetch('http://localhost:3001/api/workspaces');
912
+ if (!response.ok)
913
+ throw new Error('Failed to fetch workspaces');
914
+ return await response.json();
915
+ }
916
+ catch (error) {
917
+ console.error('Error getting workspaces:', error);
918
+ throw error;
919
+ }
920
+ });
921
+ electron_1.ipcMain.handle('add-workspace', async (_, workspace) => {
922
+ try {
923
+ const response = await fetch('http://localhost:3001/api/workspaces', {
924
+ method: 'POST',
925
+ headers: { 'Content-Type': 'application/json' },
926
+ body: JSON.stringify(workspace),
927
+ });
928
+ if (!response.ok) {
929
+ const errorData = await response.json();
930
+ throw new Error(errorData.error || 'Failed to add workspace');
931
+ }
932
+ return await response.json();
933
+ }
934
+ catch (error) {
935
+ console.error('Error adding workspace:', error);
936
+ throw error;
937
+ }
938
+ });
939
+ electron_1.ipcMain.handle('remove-workspace', async (_, workspaceId) => {
940
+ try {
941
+ const response = await fetch(`http://localhost:3001/api/workspaces/${workspaceId}`, {
942
+ method: 'DELETE',
943
+ });
944
+ if (!response.ok)
945
+ throw new Error('Failed to remove workspace');
946
+ }
947
+ catch (error) {
948
+ console.error('Error removing workspace:', error);
949
+ throw error;
950
+ }
951
+ });
952
+ // Backup handlers
953
+ electron_1.ipcMain.handle('create-backup', async (_, outputPath) => {
954
+ try {
955
+ // Try to load from dist first, then src
956
+ const backupUtilsPath = path.join(__dirname, '..', '..', 'core', 'dist', 'backup-utils.js');
957
+ const backupUtilsSrcPath = path.join(__dirname, '..', '..', 'core', 'src', 'backup-utils.ts');
958
+ let backupUtils;
959
+ if (fs.existsSync(backupUtilsPath)) {
960
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
961
+ backupUtils = require(backupUtilsPath);
962
+ }
963
+ else if (fs.existsSync(backupUtilsSrcPath.replace('.ts', '.js'))) {
964
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
965
+ backupUtils = require(backupUtilsSrcPath.replace('.ts', '.js'));
966
+ }
967
+ else {
968
+ throw new Error('Backup utils not found');
969
+ }
970
+ const { createBackup } = backupUtils;
971
+ const backupPath = await createBackup(outputPath);
972
+ return { success: true, backup_path: backupPath };
973
+ }
974
+ catch (error) {
975
+ console.error('Error creating backup:', error);
976
+ throw error;
977
+ }
978
+ });
979
+ electron_1.ipcMain.handle('restore-backup', async (_, backupPath) => {
980
+ try {
981
+ // Try to load from dist first, then src
982
+ const backupUtilsPath = path.join(__dirname, '..', '..', 'core', 'dist', 'backup-utils.js');
983
+ const backupUtilsSrcPath = path.join(__dirname, '..', '..', 'core', 'src', 'backup-utils.ts');
984
+ let backupUtils;
985
+ if (fs.existsSync(backupUtilsPath)) {
986
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
987
+ backupUtils = require(backupUtilsPath);
988
+ }
989
+ else if (fs.existsSync(backupUtilsSrcPath.replace('.ts', '.js'))) {
990
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
991
+ backupUtils = require(backupUtilsSrcPath.replace('.ts', '.js'));
992
+ }
993
+ else {
994
+ throw new Error('Backup utils not found');
995
+ }
996
+ const { restoreBackup } = backupUtils;
997
+ await restoreBackup(backupPath);
998
+ return { success: true };
999
+ }
1000
+ catch (error) {
1001
+ console.error('Error restoring backup:', error);
1002
+ throw error;
1003
+ }
1004
+ });
1005
+ // File dialog handlers
1006
+ electron_1.ipcMain.handle('show-save-dialog', async (_, options) => {
1007
+ if (!mainWindow)
1008
+ return { canceled: true };
1009
+ const result = await electron_1.dialog.showSaveDialog(mainWindow, {
1010
+ title: options.title || 'Save File',
1011
+ defaultPath: options.defaultPath,
1012
+ filters: options.filters || [{ name: 'All Files', extensions: ['*'] }],
1013
+ });
1014
+ return result;
1015
+ });
1016
+ electron_1.ipcMain.handle('show-open-dialog', async (_, options) => {
1017
+ if (!mainWindow)
1018
+ return { canceled: true };
1019
+ const result = await electron_1.dialog.showOpenDialog(mainWindow, {
1020
+ title: options.title || 'Open File',
1021
+ defaultPath: options.defaultPath,
1022
+ filters: options.filters || [{ name: 'All Files', extensions: ['*'] }],
1023
+ properties: options.properties || ['openFile'],
1024
+ });
1025
+ return result;
1026
+ });
1027
+ electron_1.ipcMain.handle('select-file', async (_, options) => {
1028
+ if (!mainWindow)
1029
+ return null;
1030
+ const result = await electron_1.dialog.showOpenDialog(mainWindow, {
1031
+ title: options.title || 'Select File',
1032
+ defaultPath: options.defaultPath,
1033
+ filters: options.filters || [{ name: 'All Files', extensions: ['*'] }],
1034
+ properties: ['openFile'],
1035
+ });
1036
+ if (result.canceled || result.filePaths.length === 0)
1037
+ return null;
1038
+ return result.filePaths[0];
1039
+ });
@@ -115,4 +115,18 @@ export interface ElectronAPI {
115
115
  }) => void) => void;
116
116
  getAppVersion: () => Promise<string>;
117
117
  getLatestTestResult: (projectId: number) => Promise<any | null>;
118
+ getWorkspaces: () => Promise<any[]>;
119
+ addWorkspace: (workspace: any) => Promise<any>;
120
+ removeWorkspace: (workspaceId: number) => Promise<void>;
121
+ createBackup: (outputPath: string) => Promise<{
122
+ success: boolean;
123
+ backup_path: string;
124
+ }>;
125
+ restoreBackup: (backupPath: string) => Promise<{
126
+ success: boolean;
127
+ }>;
128
+ showSaveDialog: (options: any) => Promise<any>;
129
+ showOpenDialog: (options: any) => Promise<any>;
130
+ selectFile: (options: any) => Promise<string | null>;
131
+ openWorkspace: (workspaceId: number) => Promise<void>;
118
132
  }
@@ -36,4 +36,13 @@ electron_1.contextBridge.exposeInMainWorld('electronAPI', {
36
36
  removeProcessExitListener: (callback) => electron_1.ipcRenderer.removeListener('process-exit', callback),
37
37
  getAppVersion: () => electron_1.ipcRenderer.invoke('get-app-version'),
38
38
  getLatestTestResult: (projectId) => electron_1.ipcRenderer.invoke('get-latest-test-result', projectId),
39
+ getWorkspaces: () => electron_1.ipcRenderer.invoke('get-workspaces'),
40
+ addWorkspace: (workspace) => electron_1.ipcRenderer.invoke('add-workspace', workspace),
41
+ removeWorkspace: (workspaceId) => electron_1.ipcRenderer.invoke('remove-workspace', workspaceId),
42
+ createBackup: (outputPath) => electron_1.ipcRenderer.invoke('create-backup', outputPath),
43
+ restoreBackup: (backupPath) => electron_1.ipcRenderer.invoke('restore-backup', backupPath),
44
+ showSaveDialog: (options) => electron_1.ipcRenderer.invoke('show-save-dialog', options),
45
+ showOpenDialog: (options) => electron_1.ipcRenderer.invoke('show-open-dialog', options),
46
+ selectFile: (options) => electron_1.ipcRenderer.invoke('select-file', options),
47
+ openWorkspace: (workspaceId) => electron_1.ipcRenderer.invoke('open-workspace', workspaceId),
39
48
  });