projax 1.0.2 → 1.3.1

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 (73) hide show
  1. package/dist/api/database.d.ts +34 -0
  2. package/dist/api/database.d.ts.map +1 -0
  3. package/dist/api/database.js +318 -0
  4. package/dist/api/database.js.map +1 -0
  5. package/dist/api/index.d.ts +5 -0
  6. package/dist/api/index.d.ts.map +1 -0
  7. package/dist/api/index.js +130 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/migrate.d.ts +2 -0
  10. package/dist/api/migrate.d.ts.map +1 -0
  11. package/dist/api/migrate.js +158 -0
  12. package/dist/api/migrate.js.map +1 -0
  13. package/dist/api/package.json +27 -0
  14. package/dist/api/routes/index.d.ts +3 -0
  15. package/dist/api/routes/index.d.ts.map +1 -0
  16. package/dist/api/routes/index.js +17 -0
  17. package/dist/api/routes/index.js.map +1 -0
  18. package/dist/api/routes/projects.d.ts +3 -0
  19. package/dist/api/routes/projects.d.ts.map +1 -0
  20. package/dist/api/routes/projects.js +198 -0
  21. package/dist/api/routes/projects.js.map +1 -0
  22. package/dist/api/routes/settings.d.ts +3 -0
  23. package/dist/api/routes/settings.d.ts.map +1 -0
  24. package/dist/api/routes/settings.js +33 -0
  25. package/dist/api/routes/settings.js.map +1 -0
  26. package/dist/api/services/scanner.d.ts +9 -0
  27. package/dist/api/services/scanner.d.ts.map +1 -0
  28. package/dist/api/services/scanner.js +172 -0
  29. package/dist/api/services/scanner.js.map +1 -0
  30. package/dist/api/types.d.ts +48 -0
  31. package/dist/api/types.d.ts.map +1 -0
  32. package/dist/api/types.js +3 -0
  33. package/dist/api/types.js.map +1 -0
  34. package/dist/core/database.d.ts +15 -5
  35. package/dist/core/database.js +136 -208
  36. package/dist/core/detector.d.ts +5 -0
  37. package/dist/core/detector.js +135 -0
  38. package/dist/core/index.d.ts +1 -2
  39. package/dist/core/index.js +2 -4
  40. package/dist/core/scanner.js +2 -105
  41. package/dist/core/settings.d.ts +50 -0
  42. package/dist/core/settings.js +102 -0
  43. package/dist/core-bridge.d.ts +2 -0
  44. package/dist/core-bridge.js +73 -0
  45. package/dist/core.d.ts +2 -0
  46. package/dist/core.js +76 -0
  47. package/dist/electron/core/database.d.ts +76 -0
  48. package/dist/electron/core/database.js +240 -0
  49. package/dist/electron/core/detector.d.ts +14 -0
  50. package/dist/electron/core/detector.js +284 -0
  51. package/dist/electron/core/index.d.ts +10 -0
  52. package/dist/electron/core/index.js +41 -0
  53. package/dist/electron/core/scanner.d.ts +8 -0
  54. package/dist/electron/core/scanner.js +11 -0
  55. package/dist/electron/core/settings.d.ts +50 -0
  56. package/dist/electron/core/settings.js +102 -0
  57. package/dist/electron/core.d.ts +2 -0
  58. package/dist/electron/core.js +76 -0
  59. package/dist/electron/main.js +93 -51
  60. package/dist/electron/port-scanner.js +4 -4
  61. package/dist/electron/preload.d.ts +1 -1
  62. package/dist/electron/renderer/assets/index-7KIJIiIM.js +42 -0
  63. package/dist/electron/renderer/assets/{index-DohAcUCg.css → index-ezVMxZrM.css} +1 -1
  64. package/dist/electron/renderer/index.html +2 -2
  65. package/dist/electron/script-runner.js +4 -4
  66. package/dist/index.js +240 -75
  67. package/dist/port-scanner.js +4 -4
  68. package/dist/script-runner.js +4 -4
  69. package/package.json +12 -11
  70. package/dist/electron/renderer/assets/index-BZ6USRnW.js +0 -42
  71. package/dist/electron/renderer/assets/index-CdMlFqhB.js +0 -42
  72. package/dist/electron/renderer/assets/index-DNtxfrZe.js +0 -42
  73. package/dist/electron/renderer/assets/index-khk3K-qG.css +0 -1
@@ -32,274 +32,202 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.getDatabaseManager = getDatabaseManager;
40
- const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
41
37
  const path = __importStar(require("path"));
42
38
  const os = __importStar(require("os"));
43
39
  const fs = __importStar(require("fs"));
40
+ const child_process_1 = require("child_process");
44
41
  class DatabaseManager {
45
- db = null;
46
- dbPath;
42
+ apiBaseUrl;
43
+ defaultPort = 3001;
47
44
  constructor() {
45
+ // Read API port from file, or use default
48
46
  const dataDir = path.join(os.homedir(), '.projax');
49
- const oldDataDir = path.join(os.homedir(), '.vids-dashboard');
50
- const oldDbPath = path.join(oldDataDir, 'dashboard.db');
51
- // Migrate data from old directory if it exists
52
- const newDbPath = path.join(dataDir, 'dashboard.db');
53
- if (fs.existsSync(oldDataDir) && fs.existsSync(oldDbPath) && !fs.existsSync(newDbPath)) {
54
- console.log('Migrating data from ~/.vids-dashboard to ~/.projax...');
47
+ const portFile = path.join(dataDir, 'api-port.txt');
48
+ let port = this.defaultPort;
49
+ if (fs.existsSync(portFile)) {
55
50
  try {
56
- // Create new directory
57
- fs.mkdirSync(dataDir, { recursive: true });
58
- // Copy database file
59
- fs.copyFileSync(oldDbPath, newDbPath);
60
- console.log('✓ Database migrated successfully');
61
- // Copy other files (processes.json, logs directory)
62
- const oldProcessesFile = path.join(oldDataDir, 'processes.json');
63
- if (fs.existsSync(oldProcessesFile)) {
64
- const newProcessesFile = path.join(dataDir, 'processes.json');
65
- fs.copyFileSync(oldProcessesFile, newProcessesFile);
51
+ const portStr = fs.readFileSync(portFile, 'utf-8').trim();
52
+ port = parseInt(portStr, 10) || this.defaultPort;
53
+ }
54
+ catch {
55
+ // Use default if file read fails
56
+ }
57
+ }
58
+ this.apiBaseUrl = `http://localhost:${port}/api`;
59
+ }
60
+ request(endpoint, options = {}) {
61
+ const url = `${this.apiBaseUrl}${endpoint}`;
62
+ const method = options.method || 'GET';
63
+ const body = options.body;
64
+ try {
65
+ let curlCmd;
66
+ if (method === 'GET') {
67
+ curlCmd = `curl -s -f "${url}"`;
68
+ }
69
+ else if (method === 'DELETE') {
70
+ curlCmd = `curl -s -f -X DELETE "${url}"`;
71
+ }
72
+ else {
73
+ // POST, PUT, PATCH
74
+ const tempFile = path.join(os.tmpdir(), `prx-${Date.now()}.json`);
75
+ if (body) {
76
+ fs.writeFileSync(tempFile, body);
77
+ }
78
+ curlCmd = `curl -s -f -X ${method} -H "Content-Type: application/json" ${body ? `-d @${tempFile}` : ''} "${url}"`;
79
+ }
80
+ const result = (0, child_process_1.execSync)(curlCmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
81
+ // Clean up temp file if created
82
+ if (method !== 'GET' && method !== 'DELETE' && body) {
83
+ const tempFile = path.join(os.tmpdir(), `prx-${Date.now()}.json`);
84
+ try {
85
+ fs.unlinkSync(tempFile);
66
86
  }
67
- const oldLogsDir = path.join(oldDataDir, 'logs');
68
- if (fs.existsSync(oldLogsDir)) {
69
- const newLogsDir = path.join(dataDir, 'logs');
70
- fs.mkdirSync(newLogsDir, { recursive: true });
71
- // Copy all log files
72
- const logFiles = fs.readdirSync(oldLogsDir);
73
- for (const file of logFiles) {
74
- const oldLogPath = path.join(oldLogsDir, file);
75
- const newLogPath = path.join(newLogsDir, file);
76
- if (fs.statSync(oldLogPath).isFile()) {
77
- fs.copyFileSync(oldLogPath, newLogPath);
78
- }
79
- }
87
+ catch {
88
+ // Ignore cleanup errors
80
89
  }
81
- console.log('✓ Migration complete. You can safely remove ~/.vids-dashboard if desired.');
82
90
  }
83
- catch (error) {
84
- console.error('⚠️ Migration failed:', error);
85
- console.error(' Continuing with new directory. Old data remains in ~/.vids-dashboard');
91
+ if (!result || result.trim() === '') {
92
+ return undefined;
86
93
  }
94
+ return JSON.parse(result);
87
95
  }
88
- else if (!fs.existsSync(dataDir)) {
89
- fs.mkdirSync(dataDir, { recursive: true });
90
- }
91
- this.dbPath = path.join(dataDir, 'dashboard.db');
92
- }
93
- getDatabase() {
94
- if (!this.db) {
95
- this.db = new better_sqlite3_1.default(this.dbPath);
96
- this.db.pragma('journal_mode = WAL');
97
- this.initializeSchema();
96
+ catch (error) {
97
+ // Check if it's a 404 or other HTTP error
98
+ if (error instanceof Error && error.message.includes('404')) {
99
+ throw new Error('Resource not found');
100
+ }
101
+ throw new Error(`API request failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
98
102
  }
99
- return this.db;
100
- }
101
- initializeSchema() {
102
- if (!this.db)
103
- return;
104
- // Projects table
105
- this.db.exec(`
106
- CREATE TABLE IF NOT EXISTS projects (
107
- id INTEGER PRIMARY KEY AUTOINCREMENT,
108
- name TEXT NOT NULL,
109
- path TEXT NOT NULL UNIQUE,
110
- last_scanned INTEGER,
111
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
112
- )
113
- `);
114
- // Tests table
115
- this.db.exec(`
116
- CREATE TABLE IF NOT EXISTS tests (
117
- id INTEGER PRIMARY KEY AUTOINCREMENT,
118
- project_id INTEGER NOT NULL,
119
- file_path TEXT NOT NULL,
120
- framework TEXT,
121
- status TEXT,
122
- last_run INTEGER,
123
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
124
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
125
- UNIQUE(project_id, file_path)
126
- )
127
- `);
128
- // Jenkins jobs table (for future integration)
129
- this.db.exec(`
130
- CREATE TABLE IF NOT EXISTS jenkins_jobs (
131
- id INTEGER PRIMARY KEY AUTOINCREMENT,
132
- project_id INTEGER NOT NULL,
133
- job_name TEXT NOT NULL,
134
- job_url TEXT NOT NULL,
135
- last_build_status TEXT,
136
- last_build_number INTEGER,
137
- last_updated INTEGER,
138
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
139
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
140
- UNIQUE(project_id, job_name)
141
- )
142
- `);
143
- // Project ports table
144
- this.db.exec(`
145
- CREATE TABLE IF NOT EXISTS project_ports (
146
- id INTEGER PRIMARY KEY AUTOINCREMENT,
147
- project_id INTEGER NOT NULL,
148
- port INTEGER NOT NULL,
149
- script_name TEXT,
150
- config_source TEXT NOT NULL,
151
- last_detected INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
152
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
153
- FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
154
- UNIQUE(project_id, port, script_name)
155
- )
156
- `);
157
- // Create indexes
158
- this.db.exec(`
159
- CREATE INDEX IF NOT EXISTS idx_tests_project_id ON tests(project_id);
160
- CREATE INDEX IF NOT EXISTS idx_jenkins_jobs_project_id ON jenkins_jobs(project_id);
161
- CREATE INDEX IF NOT EXISTS idx_project_ports_project_id ON project_ports(project_id);
162
- CREATE INDEX IF NOT EXISTS idx_project_ports_port ON project_ports(port);
163
- `);
164
103
  }
165
104
  // Project operations
166
105
  addProject(name, projectPath) {
167
- const db = this.getDatabase();
168
- const stmt = db.prepare(`
169
- INSERT INTO projects (name, path)
170
- VALUES (?, ?)
171
- `);
172
- const result = stmt.run(name, projectPath);
173
- return this.getProject(result.lastInsertRowid);
106
+ return this.request('/projects', {
107
+ method: 'POST',
108
+ body: JSON.stringify({ name, path: projectPath }),
109
+ });
174
110
  }
175
111
  getProject(id) {
176
- const db = this.getDatabase();
177
- const stmt = db.prepare('SELECT * FROM projects WHERE id = ?');
178
- return stmt.get(id);
112
+ try {
113
+ return this.request(`/projects/${id}`);
114
+ }
115
+ catch (error) {
116
+ if (error instanceof Error && error.message.includes('404')) {
117
+ return null;
118
+ }
119
+ throw error;
120
+ }
179
121
  }
180
122
  getProjectByPath(projectPath) {
181
- const db = this.getDatabase();
182
- const stmt = db.prepare('SELECT * FROM projects WHERE path = ?');
183
- return stmt.get(projectPath);
123
+ const projects = this.getAllProjects();
124
+ return projects.find(p => p.path === projectPath) || null;
184
125
  }
185
126
  getAllProjects() {
186
- const db = this.getDatabase();
187
- const stmt = db.prepare('SELECT * FROM projects ORDER BY id');
188
- return stmt.all();
127
+ return this.request('/projects');
189
128
  }
190
129
  updateProjectLastScanned(id) {
191
- const db = this.getDatabase();
192
- const stmt = db.prepare('UPDATE projects SET last_scanned = strftime("%s", "now") WHERE id = ?');
193
- stmt.run(id);
130
+ // Fire and forget - this is handled by the scan endpoint
131
+ // No need to explicitly update last_scanned
132
+ }
133
+ updateProjectFramework(id, framework) {
134
+ // This will be called during scan to update the detected framework
135
+ this.request(`/projects/${id}`, {
136
+ method: 'PUT',
137
+ body: JSON.stringify({ framework }),
138
+ });
194
139
  }
195
140
  updateProjectName(id, newName) {
196
- const db = this.getDatabase();
197
- const stmt = db.prepare('UPDATE projects SET name = ? WHERE id = ?');
198
- stmt.run(newName, id);
199
- const updated = this.getProject(id);
200
- if (!updated) {
201
- throw new Error('Failed to update project name');
202
- }
203
- return updated;
141
+ return this.request(`/projects/${id}`, {
142
+ method: 'PUT',
143
+ body: JSON.stringify({ name: newName }),
144
+ });
204
145
  }
205
146
  removeProject(id) {
206
- const db = this.getDatabase();
207
- const stmt = db.prepare('DELETE FROM projects WHERE id = ?');
208
- stmt.run(id);
147
+ this.request(`/projects/${id}`, {
148
+ method: 'DELETE',
149
+ });
150
+ }
151
+ scanProject(id) {
152
+ return this.request(`/projects/${id}/scan`, {
153
+ method: 'POST',
154
+ });
155
+ }
156
+ scanAllProjects() {
157
+ return this.request('/projects/scan/all', {
158
+ method: 'POST',
159
+ });
209
160
  }
210
161
  // Test operations
211
162
  addTest(projectId, filePath, framework = null) {
212
- const db = this.getDatabase();
213
- const stmt = db.prepare(`
214
- INSERT OR REPLACE INTO tests (project_id, file_path, framework)
215
- VALUES (?, ?, ?)
216
- `);
217
- const result = stmt.run(projectId, filePath, framework);
218
- return this.getTest(result.lastInsertRowid);
163
+ // Tests are added via scan endpoint, not directly
164
+ throw new Error('addTest should not be called directly. Use scan endpoint instead.');
219
165
  }
220
166
  getTest(id) {
221
- const db = this.getDatabase();
222
- const stmt = db.prepare('SELECT * FROM tests WHERE id = ?');
223
- return stmt.get(id);
167
+ // This endpoint doesn't exist yet
168
+ throw new Error('getTest endpoint not yet implemented in API');
224
169
  }
225
170
  getTestsByProject(projectId) {
226
- const db = this.getDatabase();
227
- const stmt = db.prepare('SELECT * FROM tests WHERE project_id = ? ORDER BY file_path');
228
- return stmt.all(projectId);
171
+ return this.request(`/projects/${projectId}/tests`);
229
172
  }
230
173
  removeTestsByProject(projectId) {
231
- const db = this.getDatabase();
232
- const stmt = db.prepare('DELETE FROM tests WHERE project_id = ?');
233
- stmt.run(projectId);
174
+ // This is handled by the scan endpoint
175
+ // For now, we'll just call scan which removes and re-adds
176
+ throw new Error('removeTestsByProject should not be called directly. Use scan endpoint instead.');
234
177
  }
235
- // Jenkins operations (for future use)
178
+ // Jenkins operations
236
179
  addJenkinsJob(projectId, jobName, jobUrl) {
237
- const db = this.getDatabase();
238
- const stmt = db.prepare(`
239
- INSERT OR REPLACE INTO jenkins_jobs (project_id, job_name, job_url)
240
- VALUES (?, ?, ?)
241
- `);
242
- const result = stmt.run(projectId, jobName, jobUrl);
243
- return this.getJenkinsJob(result.lastInsertRowid);
180
+ // This endpoint doesn't exist yet
181
+ throw new Error('addJenkinsJob endpoint not yet implemented in API');
244
182
  }
245
183
  getJenkinsJob(id) {
246
- const db = this.getDatabase();
247
- const stmt = db.prepare('SELECT * FROM jenkins_jobs WHERE id = ?');
248
- return stmt.get(id);
184
+ // This endpoint doesn't exist yet
185
+ throw new Error('getJenkinsJob endpoint not yet implemented in API');
249
186
  }
250
187
  getJenkinsJobsByProject(projectId) {
251
- const db = this.getDatabase();
252
- const stmt = db.prepare('SELECT * FROM jenkins_jobs WHERE project_id = ? ORDER BY job_name');
253
- return stmt.all(projectId);
188
+ // This endpoint doesn't exist yet
189
+ throw new Error('getJenkinsJobsByProject endpoint not yet implemented in API');
254
190
  }
255
191
  // Project port operations
256
192
  addProjectPort(projectId, port, configSource, scriptName = null) {
257
- const db = this.getDatabase();
258
- const stmt = db.prepare(`
259
- INSERT OR REPLACE INTO project_ports (project_id, port, script_name, config_source, last_detected)
260
- VALUES (?, ?, ?, ?, strftime('%s', 'now'))
261
- `);
262
- const result = stmt.run(projectId, port, scriptName, configSource);
263
- const portRecord = this.getProjectPort(result.lastInsertRowid);
264
- if (!portRecord) {
265
- throw new Error('Failed to create project port record');
266
- }
267
- return portRecord;
193
+ // This endpoint doesn't exist yet
194
+ throw new Error('addProjectPort endpoint not yet implemented in API');
268
195
  }
269
196
  getProjectPort(id) {
270
- const db = this.getDatabase();
271
- const stmt = db.prepare('SELECT * FROM project_ports WHERE id = ?');
272
- return stmt.get(id);
197
+ // This endpoint doesn't exist yet
198
+ throw new Error('getProjectPort endpoint not yet implemented in API');
273
199
  }
274
200
  getProjectPorts(projectId) {
275
- const db = this.getDatabase();
276
- const stmt = db.prepare('SELECT * FROM project_ports WHERE project_id = ? ORDER BY port');
277
- return stmt.all(projectId);
201
+ return this.request(`/projects/${projectId}/ports`);
278
202
  }
279
203
  getProjectPortsByScript(projectId, scriptName) {
280
- const db = this.getDatabase();
281
- const stmt = db.prepare('SELECT * FROM project_ports WHERE project_id = ? AND script_name = ? ORDER BY port');
282
- return stmt.all(projectId, scriptName);
204
+ const ports = this.getProjectPorts(projectId);
205
+ return ports.filter(p => p.script_name === scriptName);
283
206
  }
284
207
  removeProjectPorts(projectId) {
285
- const db = this.getDatabase();
286
- const stmt = db.prepare('DELETE FROM project_ports WHERE project_id = ?');
287
- stmt.run(projectId);
208
+ // This endpoint doesn't exist yet
209
+ throw new Error('removeProjectPorts endpoint not yet implemented in API');
288
210
  }
289
211
  updateProjectPortLastDetected(projectId, port, scriptName) {
290
- const db = this.getDatabase();
291
- const stmt = db.prepare(`
292
- UPDATE project_ports
293
- SET last_detected = strftime('%s', 'now')
294
- WHERE project_id = ? AND port = ? AND (script_name = ? OR (script_name IS NULL AND ? IS NULL))
295
- `);
296
- stmt.run(projectId, port, scriptName, scriptName);
212
+ // This endpoint doesn't exist yet - no-op for now
213
+ // Ports are updated via the scan endpoint
214
+ }
215
+ // Settings operations
216
+ getSetting(key) {
217
+ const settings = this.getAllSettings();
218
+ return settings[key] || null;
219
+ }
220
+ setSetting(key, value) {
221
+ this.request(`/settings/${encodeURIComponent(key)}`, {
222
+ method: 'PUT',
223
+ body: JSON.stringify({ value }),
224
+ });
225
+ }
226
+ getAllSettings() {
227
+ return this.request('/settings');
297
228
  }
298
229
  close() {
299
- if (this.db) {
300
- this.db.close();
301
- this.db = null;
302
- }
230
+ // No-op for API client
303
231
  }
304
232
  }
305
233
  // Singleton instance
@@ -7,3 +7,8 @@ export interface TestFramework {
7
7
  export declare const FRAMEWORKS: TestFramework[];
8
8
  export declare function detectTestFramework(projectPath: string): string | null;
9
9
  export declare function isTestFile(filePath: string, detectedFramework?: string | null): boolean;
10
+ /**
11
+ * Detect the main framework/library used in a project
12
+ * Returns null if no framework is detected
13
+ */
14
+ export declare function detectProjectFramework(projectPath: string): string | null;
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.FRAMEWORKS = void 0;
37
37
  exports.detectTestFramework = detectTestFramework;
38
38
  exports.isTestFile = isTestFile;
39
+ exports.detectProjectFramework = detectProjectFramework;
39
40
  const fs = __importStar(require("fs"));
40
41
  const path = __importStar(require("path"));
41
42
  exports.FRAMEWORKS = [
@@ -147,3 +148,137 @@ function isTestFile(filePath, detectedFramework = null) {
147
148
  }
148
149
  return false;
149
150
  }
151
+ /**
152
+ * Detect the main framework/library used in a project
153
+ * Returns null if no framework is detected
154
+ */
155
+ function detectProjectFramework(projectPath) {
156
+ const packageJsonPath = path.join(projectPath, 'package.json');
157
+ if (!fs.existsSync(packageJsonPath)) {
158
+ // Check for non-JS projects
159
+ if (fs.existsSync(path.join(projectPath, 'Cargo.toml')))
160
+ return 'rust';
161
+ if (fs.existsSync(path.join(projectPath, 'go.mod')))
162
+ return 'go';
163
+ if (fs.existsSync(path.join(projectPath, 'requirements.txt')) ||
164
+ fs.existsSync(path.join(projectPath, 'setup.py')) ||
165
+ fs.existsSync(path.join(projectPath, 'pyproject.toml'))) {
166
+ return 'python';
167
+ }
168
+ return null;
169
+ }
170
+ try {
171
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
172
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
173
+ // Meta-frameworks (check these first as they often include the base frameworks)
174
+ if (deps['next'] || deps['next.js'])
175
+ return 'next.js';
176
+ if (deps['@nuxt/kit'] || deps['nuxt'] || deps['nuxt3'])
177
+ return 'nuxt.js';
178
+ if (deps['gatsby'])
179
+ return 'gatsby';
180
+ if (deps['@remix-run/react'] || deps['remix'])
181
+ return 'remix';
182
+ if (deps['@astro'] || deps['astro'])
183
+ return 'astro';
184
+ if (deps['@angular/core'])
185
+ return 'angular';
186
+ if (deps['expo'] || deps['expo-cli'])
187
+ return 'expo';
188
+ // React Native (check before React)
189
+ if (deps['react-native'])
190
+ return 'react-native';
191
+ // Frontend frameworks
192
+ if (deps['react'] || deps['react-dom'])
193
+ return 'react';
194
+ if (deps['vue']) {
195
+ // Check Vue version
196
+ const vueVersion = deps['vue']?.match(/\d+/)?.[0];
197
+ return vueVersion === '3' ? 'vue 3' : 'vue';
198
+ }
199
+ if (deps['svelte'])
200
+ return 'svelte';
201
+ if (deps['solid-js'])
202
+ return 'solid';
203
+ if (deps['preact'])
204
+ return 'preact';
205
+ if (deps['alpine'] || deps['alpinejs'])
206
+ return 'alpine.js';
207
+ if (deps['lit'] || deps['lit-element'])
208
+ return 'lit';
209
+ if (deps['hyperapp'])
210
+ return 'hyperapp';
211
+ if (deps['mithril'])
212
+ return 'mithril';
213
+ if (deps['inferno'])
214
+ return 'inferno';
215
+ if (deps['marko'])
216
+ return 'marko';
217
+ // Backend frameworks
218
+ if (deps['express'])
219
+ return 'express';
220
+ if (deps['@nestjs/core'])
221
+ return 'nest.js';
222
+ if (deps['fastify'])
223
+ return 'fastify';
224
+ if (deps['koa'])
225
+ return 'koa';
226
+ if (deps['hapi'] || deps['@hapi/hapi'])
227
+ return 'hapi';
228
+ if (deps['@apollo/server'] || deps['apollo-server'])
229
+ return 'apollo';
230
+ if (deps['graphql'] && (deps['@graphql-yoga/node'] || deps['graphql-yoga']))
231
+ return 'graphql-yoga';
232
+ if (deps['@trpc/server'])
233
+ return 'trpc';
234
+ if (deps['@redwoodjs/core'])
235
+ return 'redwood.js';
236
+ if (deps['@blitzjs/core'])
237
+ return 'blitz.js';
238
+ // Electron
239
+ if (deps['electron'])
240
+ return 'electron';
241
+ // Static site generators
242
+ if (deps['@11ty/eleventy'])
243
+ return '11ty';
244
+ if (deps['hexo'])
245
+ return 'hexo';
246
+ if (deps['jekyll'])
247
+ return 'jekyll';
248
+ if (deps['hugo'])
249
+ return 'hugo';
250
+ // Mobile development
251
+ if (deps['@ionic/core'] || deps['@ionic/angular'] || deps['@ionic/react'])
252
+ return 'ionic';
253
+ if (deps['@nativescript/core'])
254
+ return 'nativescript';
255
+ if (deps['@capacitor/core'])
256
+ return 'capacitor';
257
+ if (deps['cordova'])
258
+ return 'cordova';
259
+ // Desktop development
260
+ if (deps['tauri'])
261
+ return 'tauri';
262
+ if (deps['nw.js'] || deps['nw'])
263
+ return 'nw.js';
264
+ // Build tools / bundlers (as last resort)
265
+ if (deps['vite'])
266
+ return 'vite';
267
+ if (deps['webpack'])
268
+ return 'webpack';
269
+ if (deps['parcel'])
270
+ return 'parcel';
271
+ if (deps['rollup'])
272
+ return 'rollup';
273
+ if (deps['esbuild'])
274
+ return 'esbuild';
275
+ if (deps['turbopack'])
276
+ return 'turbopack';
277
+ // Generic Node.js if no specific framework found but package.json exists
278
+ return 'node.js';
279
+ }
280
+ catch (error) {
281
+ // Invalid JSON or read error
282
+ return null;
283
+ }
284
+ }
@@ -1,11 +1,10 @@
1
1
  export * from './database';
2
2
  export * from './detector';
3
3
  export * from './scanner';
4
+ export * from './settings';
4
5
  export { getDatabaseManager } from './database';
5
6
  import { Project, Test } from './database';
6
- import { scanProject, scanAllProjects } from './scanner';
7
7
  export declare function getAllProjects(): Project[];
8
8
  export declare function addProject(name: string, projectPath: string): Project;
9
9
  export declare function removeProject(id: number): void;
10
10
  export declare function getTestsByProject(projectId: number): Test[];
11
- export { scanProject, scanAllProjects };
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.scanAllProjects = exports.scanProject = exports.getDatabaseManager = void 0;
17
+ exports.getDatabaseManager = void 0;
18
18
  exports.getAllProjects = getAllProjects;
19
19
  exports.addProject = addProject;
20
20
  exports.removeProject = removeProject;
@@ -22,13 +22,11 @@ exports.getTestsByProject = getTestsByProject;
22
22
  __exportStar(require("./database"), exports);
23
23
  __exportStar(require("./detector"), exports);
24
24
  __exportStar(require("./scanner"), exports);
25
+ __exportStar(require("./settings"), exports);
25
26
  var database_1 = require("./database");
26
27
  Object.defineProperty(exports, "getDatabaseManager", { enumerable: true, get: function () { return database_1.getDatabaseManager; } });
27
28
  // Convenience functions for common operations
28
29
  const database_2 = require("./database");
29
- const scanner_1 = require("./scanner");
30
- Object.defineProperty(exports, "scanProject", { enumerable: true, get: function () { return scanner_1.scanProject; } });
31
- Object.defineProperty(exports, "scanAllProjects", { enumerable: true, get: function () { return scanner_1.scanAllProjects; } });
32
30
  function getAllProjects() {
33
31
  return (0, database_2.getDatabaseManager)().getAllProjects();
34
32
  }