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.
- package/README.md +0 -73
- package/coverage/core-bridge.ts.html +24 -3
- package/coverage/index.html +34 -19
- package/coverage/lcov-report/core-bridge.ts.html +24 -3
- package/coverage/lcov-report/index.html +34 -19
- package/coverage/lcov-report/port-extractor.ts.html +1 -1
- package/coverage/lcov-report/port-scanner.ts.html +3 -3
- package/coverage/lcov-report/port-utils.ts.html +1 -1
- package/coverage/lcov-report/script-runner.ts.html +302 -11
- package/coverage/lcov-report/test-parser.ts.html +799 -0
- package/coverage/lcov.info +270 -49
- package/coverage/port-extractor.ts.html +1 -1
- package/coverage/port-scanner.ts.html +3 -3
- package/coverage/port-utils.ts.html +1 -1
- package/coverage/script-runner.ts.html +302 -11
- package/coverage/test-parser.ts.html +799 -0
- package/dist/__tests__/port-scanner.test.js +17 -7
- package/dist/__tests__/script-runner.test.js +17 -7
- package/dist/api/__tests__/database.test.js +17 -7
- package/dist/api/__tests__/database.test.js.map +1 -1
- package/dist/api/__tests__/routes.test.js +18 -7
- package/dist/api/__tests__/routes.test.js.map +1 -1
- package/dist/api/__tests__/scanner.test.js +18 -7
- package/dist/api/__tests__/scanner.test.js.map +1 -1
- package/dist/api/database.d.ts +0 -8
- package/dist/api/database.d.ts.map +1 -1
- package/dist/api/database.js +24 -57
- package/dist/api/database.js.map +1 -1
- package/dist/api/index.js +19 -9
- package/dist/api/index.js.map +1 -1
- package/dist/api/migrate.js +1 -2
- package/dist/api/migrate.js.map +1 -1
- package/dist/api/package.json +6 -3
- package/dist/api/routes/backup.d.ts +2 -1
- package/dist/api/routes/backup.d.ts.map +1 -1
- package/dist/api/routes/backup.js.map +1 -1
- package/dist/api/routes/index.d.ts +2 -1
- package/dist/api/routes/index.d.ts.map +1 -1
- package/dist/api/routes/index.js +0 -2
- package/dist/api/routes/index.js.map +1 -1
- package/dist/api/routes/projects.d.ts +2 -1
- package/dist/api/routes/projects.d.ts.map +1 -1
- package/dist/api/routes/projects.js +17 -7
- package/dist/api/routes/projects.js.map +1 -1
- package/dist/api/routes/settings.d.ts +2 -1
- package/dist/api/routes/settings.d.ts.map +1 -1
- package/dist/api/routes/settings.js +22 -57
- package/dist/api/routes/settings.js.map +1 -1
- package/dist/api/routes/workspaces.d.ts +2 -1
- package/dist/api/routes/workspaces.d.ts.map +1 -1
- package/dist/api/routes/workspaces.js +21 -96
- package/dist/api/routes/workspaces.js.map +1 -1
- package/dist/api/services/scanner.js +19 -10
- package/dist/api/services/scanner.js.map +1 -1
- package/dist/api/services/test-parser.js +2 -3
- package/dist/api/services/test-parser.js.map +1 -1
- package/dist/api/types.d.ts +0 -5
- package/dist/api/types.d.ts.map +1 -1
- package/dist/core/__tests__/database.test.js +17 -7
- package/dist/core/__tests__/detector.test.js +17 -7
- package/dist/core/__tests__/index.test.js +18 -7
- package/dist/core/__tests__/scanner.test.js +18 -7
- package/dist/core/__tests__/settings.test.js +18 -7
- package/dist/core/backup-utils.js +20 -11
- package/dist/core/database.js +18 -9
- package/dist/core/detector.js +21 -11
- package/dist/core/git-utils.js +19 -10
- package/dist/core/index.js +5 -5
- package/dist/core/scanner.js +2 -3
- package/dist/core/settings.d.ts +0 -85
- package/dist/core/settings.js +9 -306
- package/dist/core/workspace-utils.js +20 -11
- package/dist/core-bridge.js +22 -8
- package/dist/electron/core/__tests__/database.test.js +17 -7
- package/dist/electron/core/__tests__/detector.test.js +17 -7
- package/dist/electron/core/__tests__/index.test.js +18 -7
- package/dist/electron/core/__tests__/scanner.test.js +18 -7
- package/dist/electron/core/__tests__/settings.test.js +18 -7
- package/dist/electron/core/backup-utils.js +20 -11
- package/dist/electron/core/database.js +18 -9
- package/dist/electron/core/detector.js +21 -11
- package/dist/electron/core/git-utils.js +19 -10
- package/dist/electron/core/index.js +5 -5
- package/dist/electron/core/scanner.js +2 -3
- package/dist/electron/core/settings.d.ts +0 -85
- package/dist/electron/core/settings.js +9 -306
- package/dist/electron/core/workspace-utils.js +20 -11
- package/dist/electron/core.js +22 -8
- package/dist/electron/main.js +143 -444
- package/dist/electron/port-extractor.js +18 -9
- package/dist/electron/port-scanner.js +21 -12
- package/dist/electron/port-utils.js +4 -5
- package/dist/electron/preload.d.ts +2 -13
- package/dist/electron/preload.js +2 -9
- package/dist/electron/renderer/assets/index-BjZn_mEF.js +66 -0
- package/dist/electron/renderer/assets/index-CZmDxbJO.js +66 -0
- package/dist/electron/renderer/assets/{index-DWe2TQFv.css → index-DfocdjIj.css} +1 -1
- package/dist/electron/renderer/index.html +2 -2
- package/dist/electron/script-runner.js +29 -20
- package/dist/index.js +37 -134
- package/dist/port-extractor.js +18 -9
- package/dist/port-scanner.js +21 -12
- package/dist/port-utils.js +4 -5
- package/dist/prxi.d.ts +1 -0
- package/dist/prxi.js +1106 -0
- package/dist/prxi.tsx +6 -6
- package/dist/script-runner.js +29 -20
- package/dist/test-parser.js +2 -3
- package/jest.config.js +8 -0
- package/package.json +9 -6
- package/dist/api/routes/mcp.d.ts +0 -3
- package/dist/api/routes/mcp.d.ts.map +0 -1
- package/dist/api/routes/mcp.js +0 -147
- package/dist/api/routes/mcp.js.map +0 -1
- package/dist/electron/renderer/assets/index-59AhiV_K.css +0 -1
- package/dist/electron/renderer/assets/index-A04svynq.js +0 -62
- package/dist/electron/renderer/assets/index-B-etDnj2.js +0 -64
- package/dist/electron/renderer/assets/index-BGodNljq.js +0 -62
- package/dist/electron/renderer/assets/index-Bx18Cyic.js +0 -64
- package/dist/electron/renderer/assets/index-ByBOaxqv.js +0 -62
- package/dist/electron/renderer/assets/index-ByHY-x-j.js +0 -62
- package/dist/electron/renderer/assets/index-C1SRt6Jx.js +0 -62
- package/dist/electron/renderer/assets/index-C8f5yNYe.js +0 -64
- package/dist/electron/renderer/assets/index-C9Fo49a8.js +0 -61
- package/dist/electron/renderer/assets/index-CGx7K7jh.js +0 -62
- package/dist/electron/renderer/assets/index-CIZ3Wl6c.css +0 -1
- package/dist/electron/renderer/assets/index-CJbsU9y8.css +0 -1
- package/dist/electron/renderer/assets/index-CJrLunKK.js +0 -62
- package/dist/electron/renderer/assets/index-CQTleudf.css +0 -1
- package/dist/electron/renderer/assets/index-CQcilqlv.js +0 -62
- package/dist/electron/renderer/assets/index-CS-85xbL.css +0 -1
- package/dist/electron/renderer/assets/index-CYph0WPA.js +0 -62
- package/dist/electron/renderer/assets/index-C_WSLD6y.css +0 -1
- package/dist/electron/renderer/assets/index-CgB-tTpV.js +0 -62
- package/dist/electron/renderer/assets/index-ChoTzPLo.css +0 -1
- package/dist/electron/renderer/assets/index-CopVNRnR.js +0 -64
- package/dist/electron/renderer/assets/index-D1jmaGv5.css +0 -1
- package/dist/electron/renderer/assets/index-D2AOB6Er.js +0 -62
- package/dist/electron/renderer/assets/index-DAfjuYKX.js +0 -61
- package/dist/electron/renderer/assets/index-DEOOHPEi.css +0 -1
- package/dist/electron/renderer/assets/index-DTtg6XrF.css +0 -1
- package/dist/electron/renderer/assets/index-DUvcepWm.js +0 -64
- package/dist/electron/renderer/assets/index-DVWDlM1D.js +0 -62
- package/dist/electron/renderer/assets/index-DZzB20Xf.css +0 -1
- package/dist/electron/renderer/assets/index-Dk0EQt0u.css +0 -1
- package/dist/electron/renderer/assets/index-DknLdADV.js +0 -63
- package/dist/electron/renderer/assets/index-DocuD8Lk.js +0 -64
- package/dist/electron/renderer/assets/index-DwRy5FqP.js +0 -62
- package/dist/electron/renderer/assets/index-DyU-xfd8.css +0 -1
- package/dist/electron/renderer/assets/index-GwC-JVUy.css +0 -1
- package/dist/electron/renderer/assets/index-JXrtTB1F.js +0 -63
- package/dist/electron/renderer/assets/index-Ocrdv8Lb.css +0 -1
- package/dist/electron/renderer/assets/index-R-HsWJ0K.js +0 -62
- package/dist/electron/renderer/assets/index-Ytah0wbZ.js +0 -62
- package/dist/electron/renderer/assets/index-ZVyXUshO.css +0 -1
- package/dist/electron/renderer/assets/index-Z_8dJn3i.js +0 -62
- package/dist/electron/renderer/assets/index-fehviker.js +0 -63
- package/dist/electron/renderer/assets/index-nts9ST-M.js +0 -62
- package/dist/electron/renderer/assets/index-q8NVIH3g.css +0 -1
- package/dist/electron/renderer/assets/index-thUWIXon.js +0 -62
- package/dist/electron/renderer/assets/index-tuQmrwcm.css +0 -1
- package/dist/prxi/src/index.tsx +0 -1370
package/dist/electron/main.js
CHANGED
|
@@ -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 (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
244
|
-
|
|
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
|
-
|
|
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
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const
|
|
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
|
-
|
|
618
|
-
|
|
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
|
-
|
|
653
|
-
|
|
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
|
-
|
|
670
|
-
|
|
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
|
-
|
|
698
|
-
|
|
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
|
-
|
|
714
|
-
|
|
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
|
-
|
|
730
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1086
|
-
const
|
|
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
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
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
|
-
|
|
1215
|
-
return [];
|
|
932
|
+
throw error;
|
|
1216
933
|
}
|
|
1217
934
|
});
|
|
1218
935
|
electron_1.ipcMain.handle('add-workspace', async (_, workspace) => {
|
|
1219
936
|
try {
|
|
1220
|
-
|
|
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),
|