projax 3.3.51 → 3.3.52

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 (162) hide show
  1. package/README.md +0 -73
  2. package/coverage/core-bridge.ts.html +24 -3
  3. package/coverage/index.html +34 -19
  4. package/coverage/lcov-report/core-bridge.ts.html +24 -3
  5. package/coverage/lcov-report/index.html +34 -19
  6. package/coverage/lcov-report/port-extractor.ts.html +1 -1
  7. package/coverage/lcov-report/port-scanner.ts.html +3 -3
  8. package/coverage/lcov-report/port-utils.ts.html +1 -1
  9. package/coverage/lcov-report/script-runner.ts.html +302 -11
  10. package/coverage/lcov-report/test-parser.ts.html +799 -0
  11. package/coverage/lcov.info +270 -49
  12. package/coverage/port-extractor.ts.html +1 -1
  13. package/coverage/port-scanner.ts.html +3 -3
  14. package/coverage/port-utils.ts.html +1 -1
  15. package/coverage/script-runner.ts.html +302 -11
  16. package/coverage/test-parser.ts.html +799 -0
  17. package/dist/__tests__/port-scanner.test.js +17 -7
  18. package/dist/__tests__/script-runner.test.js +17 -7
  19. package/dist/api/__tests__/database.test.js +17 -7
  20. package/dist/api/__tests__/database.test.js.map +1 -1
  21. package/dist/api/__tests__/routes.test.js +18 -7
  22. package/dist/api/__tests__/routes.test.js.map +1 -1
  23. package/dist/api/__tests__/scanner.test.js +18 -7
  24. package/dist/api/__tests__/scanner.test.js.map +1 -1
  25. package/dist/api/database.d.ts +0 -8
  26. package/dist/api/database.d.ts.map +1 -1
  27. package/dist/api/database.js +24 -57
  28. package/dist/api/database.js.map +1 -1
  29. package/dist/api/index.js +19 -9
  30. package/dist/api/index.js.map +1 -1
  31. package/dist/api/migrate.js +1 -2
  32. package/dist/api/migrate.js.map +1 -1
  33. package/dist/api/package.json +6 -3
  34. package/dist/api/routes/backup.d.ts +2 -1
  35. package/dist/api/routes/backup.d.ts.map +1 -1
  36. package/dist/api/routes/backup.js.map +1 -1
  37. package/dist/api/routes/index.d.ts +2 -1
  38. package/dist/api/routes/index.d.ts.map +1 -1
  39. package/dist/api/routes/index.js +0 -2
  40. package/dist/api/routes/index.js.map +1 -1
  41. package/dist/api/routes/projects.d.ts +2 -1
  42. package/dist/api/routes/projects.d.ts.map +1 -1
  43. package/dist/api/routes/projects.js +17 -7
  44. package/dist/api/routes/projects.js.map +1 -1
  45. package/dist/api/routes/settings.d.ts +2 -1
  46. package/dist/api/routes/settings.d.ts.map +1 -1
  47. package/dist/api/routes/settings.js +22 -57
  48. package/dist/api/routes/settings.js.map +1 -1
  49. package/dist/api/routes/workspaces.d.ts +2 -1
  50. package/dist/api/routes/workspaces.d.ts.map +1 -1
  51. package/dist/api/routes/workspaces.js +21 -96
  52. package/dist/api/routes/workspaces.js.map +1 -1
  53. package/dist/api/services/scanner.js +19 -10
  54. package/dist/api/services/scanner.js.map +1 -1
  55. package/dist/api/services/test-parser.js +2 -3
  56. package/dist/api/services/test-parser.js.map +1 -1
  57. package/dist/api/types.d.ts +0 -5
  58. package/dist/api/types.d.ts.map +1 -1
  59. package/dist/core/__tests__/database.test.js +17 -7
  60. package/dist/core/__tests__/detector.test.js +17 -7
  61. package/dist/core/__tests__/index.test.js +18 -7
  62. package/dist/core/__tests__/scanner.test.js +18 -7
  63. package/dist/core/__tests__/settings.test.js +18 -7
  64. package/dist/core/backup-utils.js +20 -11
  65. package/dist/core/database.js +18 -9
  66. package/dist/core/detector.js +21 -11
  67. package/dist/core/git-utils.js +19 -10
  68. package/dist/core/index.js +5 -5
  69. package/dist/core/scanner.js +2 -3
  70. package/dist/core/settings.d.ts +0 -85
  71. package/dist/core/settings.js +9 -306
  72. package/dist/core/workspace-utils.js +20 -11
  73. package/dist/core-bridge.js +22 -8
  74. package/dist/electron/core/__tests__/database.test.js +17 -7
  75. package/dist/electron/core/__tests__/detector.test.js +17 -7
  76. package/dist/electron/core/__tests__/index.test.js +18 -7
  77. package/dist/electron/core/__tests__/scanner.test.js +18 -7
  78. package/dist/electron/core/__tests__/settings.test.js +18 -7
  79. package/dist/electron/core/backup-utils.js +20 -11
  80. package/dist/electron/core/database.js +18 -9
  81. package/dist/electron/core/detector.js +21 -11
  82. package/dist/electron/core/git-utils.js +19 -10
  83. package/dist/electron/core/index.js +5 -5
  84. package/dist/electron/core/scanner.js +2 -3
  85. package/dist/electron/core/settings.d.ts +0 -85
  86. package/dist/electron/core/settings.js +9 -306
  87. package/dist/electron/core/workspace-utils.js +20 -11
  88. package/dist/electron/core.js +22 -8
  89. package/dist/electron/main.js +143 -444
  90. package/dist/electron/port-extractor.js +18 -9
  91. package/dist/electron/port-scanner.js +21 -12
  92. package/dist/electron/port-utils.js +4 -5
  93. package/dist/electron/preload.d.ts +2 -13
  94. package/dist/electron/preload.js +2 -9
  95. package/dist/electron/renderer/assets/index-BjZn_mEF.js +66 -0
  96. package/dist/electron/renderer/assets/index-CZmDxbJO.js +66 -0
  97. package/dist/electron/renderer/assets/{index-DWe2TQFv.css → index-DfocdjIj.css} +1 -1
  98. package/dist/electron/renderer/index.html +2 -2
  99. package/dist/electron/script-runner.js +29 -20
  100. package/dist/index.js +37 -134
  101. package/dist/port-extractor.js +18 -9
  102. package/dist/port-scanner.js +21 -12
  103. package/dist/port-utils.js +4 -5
  104. package/dist/prxi.d.ts +1 -0
  105. package/dist/prxi.js +1106 -0
  106. package/dist/prxi.tsx +6 -6
  107. package/dist/script-runner.js +29 -20
  108. package/dist/test-parser.js +2 -3
  109. package/jest.config.js +8 -0
  110. package/package.json +9 -6
  111. package/dist/api/routes/mcp.d.ts +0 -3
  112. package/dist/api/routes/mcp.d.ts.map +0 -1
  113. package/dist/api/routes/mcp.js +0 -147
  114. package/dist/api/routes/mcp.js.map +0 -1
  115. package/dist/electron/renderer/assets/index-59AhiV_K.css +0 -1
  116. package/dist/electron/renderer/assets/index-A04svynq.js +0 -62
  117. package/dist/electron/renderer/assets/index-B-etDnj2.js +0 -64
  118. package/dist/electron/renderer/assets/index-BGodNljq.js +0 -62
  119. package/dist/electron/renderer/assets/index-Bx18Cyic.js +0 -64
  120. package/dist/electron/renderer/assets/index-ByBOaxqv.js +0 -62
  121. package/dist/electron/renderer/assets/index-ByHY-x-j.js +0 -62
  122. package/dist/electron/renderer/assets/index-C1SRt6Jx.js +0 -62
  123. package/dist/electron/renderer/assets/index-C8f5yNYe.js +0 -64
  124. package/dist/electron/renderer/assets/index-C9Fo49a8.js +0 -61
  125. package/dist/electron/renderer/assets/index-CGx7K7jh.js +0 -62
  126. package/dist/electron/renderer/assets/index-CIZ3Wl6c.css +0 -1
  127. package/dist/electron/renderer/assets/index-CJbsU9y8.css +0 -1
  128. package/dist/electron/renderer/assets/index-CJrLunKK.js +0 -62
  129. package/dist/electron/renderer/assets/index-CQTleudf.css +0 -1
  130. package/dist/electron/renderer/assets/index-CQcilqlv.js +0 -62
  131. package/dist/electron/renderer/assets/index-CS-85xbL.css +0 -1
  132. package/dist/electron/renderer/assets/index-CYph0WPA.js +0 -62
  133. package/dist/electron/renderer/assets/index-C_WSLD6y.css +0 -1
  134. package/dist/electron/renderer/assets/index-CgB-tTpV.js +0 -62
  135. package/dist/electron/renderer/assets/index-ChoTzPLo.css +0 -1
  136. package/dist/electron/renderer/assets/index-CopVNRnR.js +0 -64
  137. package/dist/electron/renderer/assets/index-D1jmaGv5.css +0 -1
  138. package/dist/electron/renderer/assets/index-D2AOB6Er.js +0 -62
  139. package/dist/electron/renderer/assets/index-DAfjuYKX.js +0 -61
  140. package/dist/electron/renderer/assets/index-DEOOHPEi.css +0 -1
  141. package/dist/electron/renderer/assets/index-DTtg6XrF.css +0 -1
  142. package/dist/electron/renderer/assets/index-DUvcepWm.js +0 -64
  143. package/dist/electron/renderer/assets/index-DVWDlM1D.js +0 -62
  144. package/dist/electron/renderer/assets/index-DZzB20Xf.css +0 -1
  145. package/dist/electron/renderer/assets/index-Dk0EQt0u.css +0 -1
  146. package/dist/electron/renderer/assets/index-DknLdADV.js +0 -63
  147. package/dist/electron/renderer/assets/index-DocuD8Lk.js +0 -64
  148. package/dist/electron/renderer/assets/index-DwRy5FqP.js +0 -62
  149. package/dist/electron/renderer/assets/index-DyU-xfd8.css +0 -1
  150. package/dist/electron/renderer/assets/index-GwC-JVUy.css +0 -1
  151. package/dist/electron/renderer/assets/index-JXrtTB1F.js +0 -63
  152. package/dist/electron/renderer/assets/index-Ocrdv8Lb.css +0 -1
  153. package/dist/electron/renderer/assets/index-R-HsWJ0K.js +0 -62
  154. package/dist/electron/renderer/assets/index-Ytah0wbZ.js +0 -62
  155. package/dist/electron/renderer/assets/index-ZVyXUshO.css +0 -1
  156. package/dist/electron/renderer/assets/index-Z_8dJn3i.js +0 -62
  157. package/dist/electron/renderer/assets/index-fehviker.js +0 -63
  158. package/dist/electron/renderer/assets/index-nts9ST-M.js +0 -62
  159. package/dist/electron/renderer/assets/index-q8NVIH3g.css +0 -1
  160. package/dist/electron/renderer/assets/index-thUWIXon.js +0 -62
  161. package/dist/electron/renderer/assets/index-tuQmrwcm.css +0 -1
  162. package/dist/prxi/src/index.tsx +0 -1370
@@ -15,31 +15,75 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  const electron_1 = require("electron");
27
37
  const path = __importStar(require("path"));
28
38
  const fs = __importStar(require("fs"));
29
- const os = __importStar(require("os"));
30
39
  const http = __importStar(require("http"));
31
40
  const child_process_1 = require("child_process");
32
41
  const tail_1 = require("tail");
42
+ const url_1 = require("url");
43
+ // #region agent log
44
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:7', message: 'Importing core modules', data: { __dirname }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'F' }) }).catch(() => { });
45
+ // #endregion
33
46
  const core_1 = require("./core");
47
+ // #region agent log
48
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:16', message: 'Core modules imported successfully', data: {}, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'F' }) }).catch(() => { });
34
49
  let mainWindow = null;
35
50
  let apiProcess = null;
36
51
  const logWatchers = new Map();
52
+ function resolveCliDistModulePath(moduleFileName) {
53
+ const candidates = [
54
+ // When running from CLI bundle: dist/electron/main.js -> dist/...
55
+ path.join(__dirname, '..', moduleFileName),
56
+ path.join(__dirname, '..', 'packages', 'cli', 'src', moduleFileName),
57
+ // When running desktop in dev: packages/desktop/dist/main.js -> packages/cli/dist/...
58
+ path.join(__dirname, '..', '..', 'cli', 'dist', moduleFileName),
59
+ path.join(__dirname, '..', '..', 'cli', 'dist', 'packages', 'cli', 'src', moduleFileName),
60
+ ];
61
+ for (const candidate of candidates) {
62
+ if (fs.existsSync(candidate))
63
+ return candidate;
64
+ }
65
+ throw new Error(`Module not found: ${moduleFileName}. Tried:\n` +
66
+ candidates.map(p => `- ${p}`).join('\n'));
67
+ }
68
+ async function importCliDistModule(modulePath) {
69
+ // Use a file:// URL to avoid platform/path edge-cases in Node's ESM loader.
70
+ return await Promise.resolve(`${(0, url_1.pathToFileURL)(modulePath).href}`).then(s => __importStar(require(s)));
71
+ }
72
+ // #region agent log
73
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:23', message: 'Checking single instance lock', data: {}, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'E' }) }).catch(() => { });
74
+ // #endregion
37
75
  // Prevent multiple instances
38
76
  const gotTheLock = electron_1.app.requestSingleInstanceLock();
39
77
  if (!gotTheLock) {
78
+ // #region agent log
79
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:27', message: 'Single instance lock failed - another instance running', data: {}, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'E' }) }).catch(() => { });
80
+ // #endregion
40
81
  electron_1.app.quit();
41
82
  }
42
83
  else {
84
+ // #region agent log
85
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:30', message: 'Single instance lock acquired', data: {}, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'E' }) }).catch(() => { });
86
+ // #endregion
43
87
  electron_1.app.on('second-instance', () => {
44
88
  // Someone tried to run a second instance, focus our window instead
45
89
  if (mainWindow) {
@@ -49,18 +93,26 @@ else {
49
93
  }
50
94
  });
51
95
  function createWindow() {
96
+ // #region agent log
97
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:36', message: 'createWindow called', data: { hasMainWindow: !!mainWindow }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'B' }) }).catch(() => { });
98
+ // #endregion
52
99
  // Don't create a new window if one already exists
53
100
  if (mainWindow) {
101
+ // #region agent log
102
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:39', message: 'Window already exists, focusing', data: {}, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'B' }) }).catch(() => { });
103
+ // #endregion
54
104
  mainWindow.focus();
55
105
  return;
56
106
  }
57
107
  const isDev = process.env.NODE_ENV === 'development';
108
+ // #region agent log
109
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:45', message: 'Creating BrowserWindow', data: { isDev, __dirname }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'B' }) }).catch(() => { });
110
+ // #endregion
58
111
  mainWindow = new electron_1.BrowserWindow({
59
112
  width: 1200,
60
113
  height: 800,
61
114
  frame: false,
62
115
  titleBarStyle: 'hidden',
63
- trafficLightPosition: { x: -100, y: -100 }, // Hide macOS traffic lights
64
116
  title: 'PROJAX UI',
65
117
  webPreferences: {
66
118
  preload: path.join(__dirname, 'preload.js'),
@@ -72,23 +124,41 @@ else {
72
124
  });
73
125
  // Show window when ready to prevent white screen flash
74
126
  mainWindow.once('ready-to-show', () => {
127
+ // #region agent log
128
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:63', message: 'Window ready-to-show event fired', data: {}, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'B' }) }).catch(() => { });
129
+ // #endregion
75
130
  mainWindow?.show();
76
131
  });
77
132
  // Load the app
78
133
  if (isDev) {
134
+ // #region agent log
135
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:67', message: 'Dev mode: checking Vite server', data: { port: 7898 }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'C' }) }).catch(() => { });
136
+ // #endregion
79
137
  // Wait for Vite dev server to be ready before loading
80
138
  const checkServerAndLoad = (retries = 10) => {
139
+ // #region agent log
140
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:70', message: 'Checking Vite server availability', data: { retries }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'C' }) }).catch(() => { });
141
+ // #endregion
81
142
  const req = http.get('http://localhost:7898', (res) => {
143
+ // #region agent log
144
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:72', message: 'Vite server is ready', data: { statusCode: res.statusCode }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'C' }) }).catch(() => { });
145
+ // #endregion
82
146
  console.log('Vite dev server is ready!');
83
147
  mainWindow?.loadURL('http://localhost:7898');
84
148
  mainWindow?.webContents.openDevTools();
85
149
  });
86
150
  req.on('error', (error) => {
151
+ // #region agent log
152
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:76', message: 'Vite server check error', data: { error: error.message, retries }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'C' }) }).catch(() => { });
153
+ // #endregion
87
154
  if (retries > 0) {
88
155
  console.log(`Vite dev server not ready (${retries} retries left), retrying in 1 second...`);
89
156
  setTimeout(() => checkServerAndLoad(retries - 1), 1000);
90
157
  }
91
158
  else {
159
+ // #region agent log
160
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:82', message: 'Vite server connection failed after all retries', data: { error: error.message }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'C' }) }).catch(() => { });
161
+ // #endregion
92
162
  console.error('Failed to connect to Vite dev server after multiple retries');
93
163
  console.error('Make sure Vite is running on port 7898');
94
164
  mainWindow?.loadURL('http://localhost:7898'); // Try anyway
@@ -126,6 +196,13 @@ else {
126
196
  electron_1.app.quit();
127
197
  }
128
198
  }
199
+ // Prevent navigation on file drops (prevents default file:// protocol navigation)
200
+ mainWindow.webContents.on('will-navigate', (event, url) => {
201
+ // Allow navigation only to localhost (dev server) or file:// (local renderer)
202
+ if (!url.startsWith('http://localhost') && !url.startsWith('file://')) {
203
+ event.preventDefault();
204
+ }
205
+ });
129
206
  // Handle external links securely
130
207
  mainWindow.webContents.setWindowOpenHandler(({ url }) => {
131
208
  // Only allow http/https links to be opened externally for security
@@ -187,6 +264,9 @@ else {
187
264
  }
188
265
  // Start API server
189
266
  function startAPIServer() {
267
+ // #region agent log
268
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:187', message: 'startAPIServer called', data: { __dirname, processCwd: process.cwd() }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'D' }) }).catch(() => { });
269
+ // #endregion
190
270
  try {
191
271
  // Try to find API server in various locations
192
272
  const apiPaths = [
@@ -194,14 +274,24 @@ else {
194
274
  path.join(__dirname, '..', '..', 'api', 'dist', 'index.js'),
195
275
  path.join(process.cwd(), 'packages', 'api', 'dist', 'index.js'),
196
276
  ];
277
+ // #region agent log
278
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:196', message: 'Checking API paths', data: { apiPaths, __dirname }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'D' }) }).catch(() => { });
279
+ // #endregion
197
280
  let apiPath = null;
198
281
  for (const p of apiPaths) {
199
- if (fs.existsSync(p)) {
282
+ const exists = fs.existsSync(p);
283
+ // #region agent log
284
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:199', message: 'Checking API path', data: { path: p, exists }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'D' }) }).catch(() => { });
285
+ // #endregion
286
+ if (exists) {
200
287
  apiPath = p;
201
288
  break;
202
289
  }
203
290
  }
204
291
  if (!apiPath) {
292
+ // #region agent log
293
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:205', message: 'API server not found', data: { checkedPaths: apiPaths }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'D' }) }).catch(() => { });
294
+ // #endregion
205
295
  console.warn('API server not found. Some features may not work.');
206
296
  return;
207
297
  }
@@ -212,12 +302,18 @@ else {
212
302
  apiProcess.kill();
213
303
  apiProcess = null;
214
304
  }
305
+ // #region agent log
306
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:216', message: 'Spawning API server process', data: { apiPath, cwd: path.dirname(apiPath) }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'D' }) }).catch(() => { });
307
+ // #endregion
215
308
  apiProcess = (0, child_process_1.spawn)('node', [apiPath], {
216
309
  detached: false,
217
310
  stdio: 'pipe',
218
311
  env: { ...process.env },
219
312
  cwd: path.dirname(apiPath),
220
313
  });
314
+ // #region agent log
315
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:222', message: 'API server process spawned', data: { pid: apiProcess.pid }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'D' }) }).catch(() => { });
316
+ // #endregion
221
317
  apiProcess.stdout?.on('data', (data) => {
222
318
  console.log(`[API] ${data.toString().trim()}`);
223
319
  });
@@ -237,125 +333,18 @@ else {
237
333
  });
238
334
  }
239
335
  catch (error) {
336
+ // #region agent log
337
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:243', message: 'API server startup error', data: { error: error instanceof Error ? error.message : String(error) }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'D' }) }).catch(() => { });
338
+ // #endregion
240
339
  console.error('Failed to start API server:', error);
241
340
  }
242
341
  }
243
- function createMenu() {
244
- const template = [
245
- {
246
- label: 'PROJAX UI',
247
- submenu: [
248
- { role: 'about', label: 'About PROJAX UI' },
249
- { type: 'separator' },
250
- { role: 'services', label: 'Services' },
251
- { type: 'separator' },
252
- { role: 'hide', label: 'Hide PROJAX UI' },
253
- { role: 'hideOthers', label: 'Hide Others' },
254
- { role: 'unhide', label: 'Show All' },
255
- { type: 'separator' },
256
- { role: 'quit', label: 'Quit PROJAX UI' },
257
- ],
258
- },
259
- {
260
- label: 'File',
261
- submenu: [
262
- {
263
- label: 'New Project',
264
- accelerator: 'CmdOrCtrl+N',
265
- click: () => {
266
- if (mainWindow) {
267
- mainWindow.webContents.send('menu-action', 'new-project');
268
- }
269
- },
270
- },
271
- {
272
- label: 'New Workspace',
273
- accelerator: 'CmdOrCtrl+Shift+N',
274
- click: () => {
275
- if (mainWindow) {
276
- mainWindow.webContents.send('menu-action', 'new-workspace');
277
- }
278
- },
279
- },
280
- { type: 'separator' },
281
- {
282
- label: 'Open Workspace',
283
- accelerator: 'CmdOrCtrl+O',
284
- click: () => {
285
- if (mainWindow) {
286
- mainWindow.webContents.send('menu-action', 'open-workspace');
287
- }
288
- },
289
- },
290
- {
291
- label: 'Open Directory as New Project',
292
- accelerator: 'CmdOrCtrl+Shift+O',
293
- click: async () => {
294
- if (mainWindow) {
295
- const result = await electron_1.dialog.showOpenDialog(mainWindow, {
296
- properties: ['openDirectory'],
297
- });
298
- if (!result.canceled && result.filePaths.length > 0) {
299
- mainWindow.webContents.send('menu-action', 'open-directory-as-project', result.filePaths[0]);
300
- }
301
- }
302
- },
303
- },
304
- { type: 'separator' },
305
- { role: 'close', label: 'Close Window' },
306
- ],
307
- },
308
- {
309
- label: 'Edit',
310
- submenu: [
311
- { role: 'undo', label: 'Undo' },
312
- { role: 'redo', label: 'Redo' },
313
- { type: 'separator' },
314
- { role: 'cut', label: 'Cut' },
315
- { role: 'copy', label: 'Copy' },
316
- { role: 'paste', label: 'Paste' },
317
- { role: 'selectAll', label: 'Select All' },
318
- ],
319
- },
320
- {
321
- label: 'View',
322
- submenu: [
323
- { role: 'reload', label: 'Reload' },
324
- { role: 'forceReload', label: 'Force Reload' },
325
- { role: 'toggleDevTools', label: 'Toggle Developer Tools' },
326
- { type: 'separator' },
327
- { role: 'resetZoom', label: 'Actual Size' },
328
- { role: 'zoomIn', label: 'Zoom In' },
329
- { role: 'zoomOut', label: 'Zoom Out' },
330
- { type: 'separator' },
331
- { role: 'togglefullscreen', label: 'Toggle Full Screen' },
332
- ],
333
- },
334
- {
335
- label: 'Window',
336
- submenu: [
337
- { role: 'minimize', label: 'Minimize' },
338
- { role: 'close', label: 'Close' },
339
- ],
340
- },
341
- ];
342
- // macOS specific menu adjustments
343
- if (process.platform === 'darwin') {
344
- template[0].label = 'PROJAX UI';
345
- }
346
- else {
347
- // Windows/Linux: Remove the app menu and move items to File menu
348
- template.shift();
349
- const fileMenu = template[0];
350
- if (fileMenu.submenu && Array.isArray(fileMenu.submenu)) {
351
- fileMenu.submenu.push({ type: 'separator' }, { role: 'quit', label: 'Exit' });
352
- }
353
- }
354
- const menu = electron_1.Menu.buildFromTemplate(template);
355
- electron_1.Menu.setApplicationMenu(menu);
356
- }
342
+ // Set app name for menu bar (macOS)
343
+ electron_1.app.setName('PROJAX');
357
344
  electron_1.app.whenReady().then(() => {
358
- createMenu();
345
+ // #region agent log
346
+ fetch('http://127.0.0.1:7242/ingest/6c072a46-f01e-4db0-a457-6218bdb7cec6', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'main.ts:247', message: 'App whenReady fired', data: {}, timestamp: Date.now(), sessionId: 'debug-session', runId: 'run1', hypothesisId: 'A' }) }).catch(() => { });
347
+ // #endregion
359
348
  startAPIServer();
360
349
  createWindow();
361
350
  electron_1.app.on('activate', () => {
@@ -395,42 +384,9 @@ electron_1.ipcMain.handle('get-app-version', async () => {
395
384
  electron_1.ipcMain.handle('get-projects', async () => {
396
385
  try {
397
386
  console.log('Getting projects from database...');
398
- // Wait a bit for API server to be ready if it just started
399
- // Try to get projects, with a retry if it fails
400
- let projects = [];
401
- let lastError = null;
402
- for (let attempt = 0; attempt < 3; attempt++) {
403
- try {
404
- projects = (0, core_1.getAllProjects)();
405
- console.log(`Found ${projects.length} project(s)`);
406
- return projects;
407
- }
408
- catch (error) {
409
- lastError = error instanceof Error ? error : new Error(String(error));
410
- if (attempt < 2) {
411
- // Wait a bit before retrying (API server might be starting)
412
- await new Promise(resolve => setTimeout(resolve, 500));
413
- }
414
- }
415
- }
416
- // If all retries failed, try reading directly from database file as fallback
417
- try {
418
- const dataDir = path.join(os.homedir(), '.projax');
419
- const dbPath = path.join(dataDir, 'data.json');
420
- if (fs.existsSync(dbPath)) {
421
- const dbContent = fs.readFileSync(dbPath, 'utf-8');
422
- const db = JSON.parse(dbContent);
423
- if (db.projects && Array.isArray(db.projects)) {
424
- console.log(`Fallback: Found ${db.projects.length} project(s) from database file`);
425
- return db.projects;
426
- }
427
- }
428
- }
429
- catch (fileError) {
430
- console.warn('Could not read projects from database file:', fileError);
431
- }
432
- // If we still don't have projects, throw the original error
433
- throw lastError || new Error('Failed to get projects');
387
+ const projects = (0, core_1.getAllProjects)();
388
+ console.log(`Found ${projects.length} project(s)`);
389
+ return projects;
434
390
  }
435
391
  catch (error) {
436
392
  console.error('Error getting projects:', error);
@@ -525,82 +481,10 @@ electron_1.ipcMain.handle('rename-project', async (_, projectId, newName) => {
525
481
  return db.updateProjectName(projectId, newName);
526
482
  });
527
483
  // Get project scripts
528
- electron_1.ipcMain.handle('get-project-scripts', async (_, projectPath, projectId) => {
529
- // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/script-runner.js)
530
- // Then try local dev path (packages/desktop/dist/main.js -> packages/cli/dist/script-runner.js)
531
- const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
532
- const localScriptRunnerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'script-runner.js');
533
- let scriptRunnerPath;
534
- if (fs.existsSync(bundledScriptRunnerPath)) {
535
- scriptRunnerPath = bundledScriptRunnerPath;
536
- }
537
- else {
538
- scriptRunnerPath = localScriptRunnerPath;
539
- }
540
- const { getProjectScripts } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
541
- // Get project settings if projectId is provided
542
- // Read directly from database file instead of making HTTP requests
543
- let scriptsPath = null;
544
- if (projectId) {
545
- try {
546
- const dataDir = path.join(os.homedir(), '.projax');
547
- const dbPath = path.join(dataDir, 'data.json');
548
- // Try reading the file with a small retry in case it's being written
549
- let db = null;
550
- for (let attempt = 0; attempt < 3; attempt++) {
551
- try {
552
- if (fs.existsSync(dbPath)) {
553
- const dbContent = fs.readFileSync(dbPath, 'utf-8');
554
- db = JSON.parse(dbContent);
555
- break; // Successfully read, exit retry loop
556
- }
557
- }
558
- catch (readError) {
559
- if (attempt < 2) {
560
- // Wait a bit before retrying (only on first two attempts)
561
- await new Promise(resolve => setTimeout(resolve, 100));
562
- continue;
563
- }
564
- throw readError;
565
- }
566
- }
567
- if (db && db.project_settings && Array.isArray(db.project_settings)) {
568
- const settings = db.project_settings.find((ps) => ps.project_id === projectId);
569
- if (settings && settings.scripts_path) {
570
- scriptsPath = settings.scripts_path;
571
- }
572
- }
573
- }
574
- catch (error) {
575
- // Silently fail - will use project root if settings can't be loaded
576
- console.debug('Could not load project settings for scripts, using project root:', error);
577
- }
578
- }
579
- // Use custom scripts path if set, otherwise use project root
580
- let actualScriptsPath = projectPath;
581
- if (scriptsPath) {
582
- const joinedPath = path.join(projectPath, scriptsPath);
583
- // Validate that the path exists
584
- if (fs.existsSync(joinedPath)) {
585
- const stats = fs.statSync(joinedPath);
586
- if (stats.isDirectory()) {
587
- // If it's a directory, use it directly
588
- actualScriptsPath = joinedPath;
589
- }
590
- else if (stats.isFile()) {
591
- // If it's a file, use the directory containing the file
592
- actualScriptsPath = path.dirname(joinedPath);
593
- }
594
- else {
595
- console.warn(`Custom scripts path is not a directory or file: ${joinedPath}, using project root instead`);
596
- }
597
- }
598
- else {
599
- console.warn(`Custom scripts path does not exist: ${joinedPath}, using project root instead`);
600
- // Fall back to project root if custom path doesn't exist
601
- }
602
- }
603
- const result = getProjectScripts(actualScriptsPath);
484
+ electron_1.ipcMain.handle('get-project-scripts', async (_, projectPath) => {
485
+ const scriptRunnerPath = resolveCliDistModulePath('script-runner.js');
486
+ const { getProjectScripts } = await importCliDistModule(scriptRunnerPath);
487
+ const result = getProjectScripts(projectPath);
604
488
  // Convert Map to array for IPC serialization
605
489
  const scriptsArray = Array.from(result.scripts.entries()).map(([name, script]) => ({
606
490
  name,
@@ -614,21 +498,8 @@ electron_1.ipcMain.handle('get-project-scripts', async (_, projectPath, projectI
614
498
  // Run script
615
499
  electron_1.ipcMain.handle('run-script', async (_, projectPath, scriptName, args = [], background = false) => {
616
500
  try {
617
- // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/script-runner.js)
618
- // Then try local dev path (packages/desktop/dist/main.js -> packages/cli/dist/script-runner.js)
619
- const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
620
- const localScriptRunnerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'script-runner.js');
621
- let scriptRunnerPath;
622
- if (fs.existsSync(bundledScriptRunnerPath)) {
623
- scriptRunnerPath = bundledScriptRunnerPath;
624
- }
625
- else if (fs.existsSync(localScriptRunnerPath)) {
626
- scriptRunnerPath = localScriptRunnerPath;
627
- }
628
- else {
629
- throw new Error(`Script runner not found. Tried: ${bundledScriptRunnerPath} and ${localScriptRunnerPath}`);
630
- }
631
- const scriptRunnerModule = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
501
+ const scriptRunnerPath = resolveCliDistModulePath('script-runner.js');
502
+ const scriptRunnerModule = await importCliDistModule(scriptRunnerPath);
632
503
  const { runScriptInBackground } = scriptRunnerModule;
633
504
  if (!runScriptInBackground || typeof runScriptInBackground !== 'function') {
634
505
  throw new Error('runScriptInBackground function not found in script runner module');
@@ -649,35 +520,15 @@ electron_1.ipcMain.handle('run-script', async (_, projectPath, scriptName, args
649
520
  });
650
521
  // Scan ports
651
522
  electron_1.ipcMain.handle('scan-project-ports', async (_, projectId) => {
652
- // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/port-scanner.js)
653
- // Then try local dev path (packages/desktop/dist/main.js -> packages/cli/dist/port-scanner.js)
654
- const bundledPortScannerPath = path.join(__dirname, '..', 'port-scanner.js');
655
- const localPortScannerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'port-scanner.js');
656
- let portScannerPath;
657
- if (fs.existsSync(bundledPortScannerPath)) {
658
- portScannerPath = bundledPortScannerPath;
659
- }
660
- else {
661
- portScannerPath = localPortScannerPath;
662
- }
663
- const { scanProjectPorts } = await Promise.resolve(`${portScannerPath}`).then(s => __importStar(require(s)));
523
+ const portScannerPath = resolveCliDistModulePath('port-scanner.js');
524
+ const { scanProjectPorts } = await importCliDistModule(portScannerPath);
664
525
  await scanProjectPorts(projectId);
665
526
  const db = (0, core_1.getDatabaseManager)();
666
527
  return db.getProjectPorts(projectId);
667
528
  });
668
529
  electron_1.ipcMain.handle('scan-all-ports', async () => {
669
- // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/port-scanner.js)
670
- // Then try local dev path (packages/desktop/dist/main.js -> packages/cli/dist/port-scanner.js)
671
- const bundledPortScannerPath = path.join(__dirname, '..', 'port-scanner.js');
672
- const localPortScannerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'port-scanner.js');
673
- let portScannerPath;
674
- if (fs.existsSync(bundledPortScannerPath)) {
675
- portScannerPath = bundledPortScannerPath;
676
- }
677
- else {
678
- portScannerPath = localPortScannerPath;
679
- }
680
- const { scanAllProjectPorts } = await Promise.resolve(`${portScannerPath}`).then(s => __importStar(require(s)));
530
+ const portScannerPath = resolveCliDistModulePath('port-scanner.js');
531
+ const { scanAllProjectPorts } = await importCliDistModule(portScannerPath);
681
532
  await scanAllProjectPorts();
682
533
  const db = (0, core_1.getDatabaseManager)();
683
534
  const projects = (0, core_1.getAllProjects)();
@@ -694,50 +545,20 @@ electron_1.ipcMain.handle('get-project-ports', async (_, projectId) => {
694
545
  });
695
546
  // Get running processes
696
547
  electron_1.ipcMain.handle('get-running-processes', async () => {
697
- // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/script-runner.js)
698
- // Then try local dev path (packages/desktop/dist/main.js -> packages/cli/dist/script-runner.js)
699
- const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
700
- const localScriptRunnerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'script-runner.js');
701
- let scriptRunnerPath;
702
- if (fs.existsSync(bundledScriptRunnerPath)) {
703
- scriptRunnerPath = bundledScriptRunnerPath;
704
- }
705
- else {
706
- scriptRunnerPath = localScriptRunnerPath;
707
- }
708
- const { getRunningProcessesClean } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
548
+ const scriptRunnerPath = resolveCliDistModulePath('script-runner.js');
549
+ const { getRunningProcessesClean } = await importCliDistModule(scriptRunnerPath);
709
550
  return await getRunningProcessesClean();
710
551
  });
711
552
  // Stop script by PID
712
553
  electron_1.ipcMain.handle('stop-script', async (_, pid) => {
713
- // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/script-runner.js)
714
- // Then try local dev path (packages/desktop/dist/main.js -> packages/cli/dist/script-runner.js)
715
- const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
716
- const localScriptRunnerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'script-runner.js');
717
- let scriptRunnerPath;
718
- if (fs.existsSync(bundledScriptRunnerPath)) {
719
- scriptRunnerPath = bundledScriptRunnerPath;
720
- }
721
- else {
722
- scriptRunnerPath = localScriptRunnerPath;
723
- }
724
- const { stopScript } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
554
+ const scriptRunnerPath = resolveCliDistModulePath('script-runner.js');
555
+ const { stopScript } = await importCliDistModule(scriptRunnerPath);
725
556
  return await stopScript(pid);
726
557
  });
727
558
  // Stop all processes for a project
728
559
  electron_1.ipcMain.handle('stop-project', async (_, projectPath) => {
729
- // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/script-runner.js)
730
- // Then try local dev path (packages/desktop/dist/main.js -> packages/cli/dist/script-runner.js)
731
- const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
732
- const localScriptRunnerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'script-runner.js');
733
- let scriptRunnerPath;
734
- if (fs.existsSync(bundledScriptRunnerPath)) {
735
- scriptRunnerPath = bundledScriptRunnerPath;
736
- }
737
- else {
738
- scriptRunnerPath = localScriptRunnerPath;
739
- }
740
- const { stopProjectProcesses } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
560
+ const scriptRunnerPath = resolveCliDistModulePath('script-runner.js');
561
+ const { stopProjectProcesses } = await importCliDistModule(scriptRunnerPath);
741
562
  return await stopProjectProcesses(projectPath);
742
563
  });
743
564
  // Open URL in browser
@@ -832,7 +653,7 @@ electron_1.ipcMain.handle('open-url', async (_, url) => {
832
653
  }).unref();
833
654
  });
834
655
  // Open project in editor
835
- electron_1.ipcMain.handle('open-in-editor', async (_, projectPath, projectId) => {
656
+ electron_1.ipcMain.handle('open-in-editor', async (_, projectPath) => {
836
657
  // Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/core/settings)
837
658
  // Then try local dev path (packages/desktop/dist/main.js -> packages/core/dist/settings)
838
659
  const bundledSettingsPath = path.join(__dirname, 'core', 'settings');
@@ -845,41 +666,7 @@ electron_1.ipcMain.handle('open-in-editor', async (_, projectPath, projectId) =>
845
666
  settingsPath = localSettingsPath;
846
667
  }
847
668
  const { getEditorSettings } = require(settingsPath);
848
- const globalEditorSettings = getEditorSettings();
849
- // Check for project-specific editor settings
850
- let editorSettings = globalEditorSettings;
851
- if (projectId) {
852
- try {
853
- const ports = [38124, 38125, 38126, 38127, 38128, 3001];
854
- let apiBaseUrl = '';
855
- for (const port of ports) {
856
- try {
857
- const response = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(500) });
858
- if (response.ok) {
859
- apiBaseUrl = `http://localhost:${port}/api`;
860
- break;
861
- }
862
- }
863
- catch {
864
- continue;
865
- }
866
- }
867
- if (apiBaseUrl) {
868
- const settingsResponse = await fetch(`${apiBaseUrl}/projects/${projectId}/settings`);
869
- if (settingsResponse.ok) {
870
- const projectSettings = await settingsResponse.json();
871
- if (projectSettings.editor && projectSettings.editor.type) {
872
- // Use project-specific editor
873
- editorSettings = projectSettings.editor;
874
- }
875
- }
876
- }
877
- }
878
- catch (error) {
879
- console.error('Error loading project editor settings:', error);
880
- // Fall back to global settings
881
- }
882
- }
669
+ const editorSettings = getEditorSettings();
883
670
  let command;
884
671
  let args = [projectPath];
885
672
  if (editorSettings.type === 'custom' && editorSettings.customPath) {
@@ -1009,17 +796,6 @@ electron_1.ipcMain.handle('open-in-files', async (_, projectPath) => {
1009
796
  throw error;
1010
797
  }
1011
798
  });
1012
- // Open file path in file manager (reveals file in finder/explorer)
1013
- electron_1.ipcMain.handle('open-file-path', async (_, filePath) => {
1014
- try {
1015
- // Use shell.showItemInFolder to reveal the file in the file manager
1016
- electron_1.shell.showItemInFolder(filePath);
1017
- }
1018
- catch (error) {
1019
- console.error('Error opening file path:', error);
1020
- throw error;
1021
- }
1022
- });
1023
799
  // Get settings
1024
800
  electron_1.ipcMain.handle('get-settings', async () => {
1025
801
  try {
@@ -1082,17 +858,8 @@ electron_1.ipcMain.on('open-external-url', (event, url) => {
1082
858
  // Watch process output
1083
859
  electron_1.ipcMain.handle('watch-process-output', async (_, pid) => {
1084
860
  try {
1085
- // Try bundled path first
1086
- const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
1087
- const localScriptRunnerPath = path.join(__dirname, '..', '..', 'cli', 'dist', 'script-runner.js');
1088
- let scriptRunnerPath;
1089
- if (fs.existsSync(bundledScriptRunnerPath)) {
1090
- scriptRunnerPath = bundledScriptRunnerPath;
1091
- }
1092
- else {
1093
- scriptRunnerPath = localScriptRunnerPath;
1094
- }
1095
- const { getRunningProcessesClean } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
861
+ const scriptRunnerPath = resolveCliDistModulePath('script-runner.js');
862
+ const { getRunningProcessesClean } = await importCliDistModule(scriptRunnerPath);
1096
863
  const processes = await getRunningProcessesClean();
1097
864
  const process = processes.find((p) => p.pid === pid);
1098
865
  if (!process || !process.logFile) {
@@ -1155,87 +922,19 @@ electron_1.ipcMain.handle('unwatch-process-output', async (_, pid) => {
1155
922
  // Workspace handlers
1156
923
  electron_1.ipcMain.handle('get-workspaces', async () => {
1157
924
  try {
1158
- // Try to find the correct API port
1159
- const ports = [38124, 38125, 38126, 38127, 38128, 3001];
1160
- let apiBaseUrl = '';
1161
- for (const port of ports) {
1162
- try {
1163
- const response = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(500) });
1164
- if (response.ok) {
1165
- apiBaseUrl = `http://localhost:${port}/api`;
1166
- break;
1167
- }
1168
- }
1169
- catch {
1170
- continue;
1171
- }
1172
- }
1173
- // Try fetching from API with retries
1174
- if (apiBaseUrl) {
1175
- for (let i = 0; i < 3; i++) {
1176
- try {
1177
- const response = await fetch(`${apiBaseUrl}/workspaces`);
1178
- if (response.ok) {
1179
- const workspaces = await response.json();
1180
- console.log(`[main] Fetched ${workspaces.length} workspace(s) from API.`);
1181
- return workspaces;
1182
- }
1183
- }
1184
- catch (error) {
1185
- console.debug(`[main] API fetch attempt ${i + 1} failed:`, error);
1186
- if (i < 2) {
1187
- await new Promise(resolve => setTimeout(resolve, 500)); // Wait 500ms before retry
1188
- }
1189
- }
1190
- }
1191
- }
1192
- // Fallback to reading directly from database file if API is not available or failed
1193
- try {
1194
- console.warn('[main] API not available or failed after retries. Reading workspaces directly from database file.');
1195
- const dataDir = path.join(os.homedir(), '.projax');
1196
- const dbPath = path.join(dataDir, 'data.json');
1197
- if (fs.existsSync(dbPath)) {
1198
- const dbContent = fs.readFileSync(dbPath, 'utf-8');
1199
- const db = JSON.parse(dbContent);
1200
- const workspaces = db.workspaces || [];
1201
- console.log(`[main] Found ${workspaces.length} workspace(s) in database file.`);
1202
- return workspaces;
1203
- }
1204
- }
1205
- catch (fileError) {
1206
- console.warn('[main] Could not read workspaces from database file:', fileError);
1207
- }
1208
- // If we still don't have workspaces, return empty array
1209
- console.warn('[main] No workspaces found, returning empty array.');
1210
- return [];
925
+ const response = await fetch('http://localhost:3001/api/workspaces');
926
+ if (!response.ok)
927
+ throw new Error('Failed to fetch workspaces');
928
+ return await response.json();
1211
929
  }
1212
930
  catch (error) {
1213
931
  console.error('Error getting workspaces:', error);
1214
- // Return empty array instead of throwing to prevent app crash
1215
- return [];
932
+ throw error;
1216
933
  }
1217
934
  });
1218
935
  electron_1.ipcMain.handle('add-workspace', async (_, workspace) => {
1219
936
  try {
1220
- // Try to find the correct API port
1221
- const ports = [38124, 38125, 38126, 38127, 38128, 3001];
1222
- let apiBaseUrl = '';
1223
- for (const port of ports) {
1224
- try {
1225
- const response = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(500) });
1226
- if (response.ok) {
1227
- apiBaseUrl = `http://localhost:${port}/api`;
1228
- break;
1229
- }
1230
- }
1231
- catch {
1232
- continue;
1233
- }
1234
- }
1235
- if (!apiBaseUrl) {
1236
- throw new Error('API server not found');
1237
- }
1238
- const response = await fetch(`${apiBaseUrl}/workspaces`, {
937
+ const response = await fetch('http://localhost:3001/api/workspaces', {
1239
938
  method: 'POST',
1240
939
  headers: { 'Content-Type': 'application/json' },
1241
940
  body: JSON.stringify(workspace),