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
package/dist/prxi.tsx CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  scanProject,
7
7
  Project,
8
8
  } from '../../cli/src/core-bridge';
9
- import { getProjectScripts, getRunningProcessesClean, runScriptInBackground, stopScript } from '../../cli/src/script-runner';
9
+ import { getProjectScripts, getRunningProcessesClean, runScript, runScriptInBackground, stopScript } from '../../cli/src/script-runner';
10
10
  import { spawn } from 'child_process';
11
11
  import * as path from 'path';
12
12
  import * as os from 'os';
@@ -768,9 +768,9 @@ const App: React.FC = () => {
768
768
  const db = getDatabaseManager();
769
769
  const allProjects = getAllProjects();
770
770
  const tagsSet = new Set<string>();
771
- allProjects.forEach(project => {
771
+ allProjects.forEach((project: Project) => {
772
772
  if (project.tags && Array.isArray(project.tags)) {
773
- project.tags.forEach(tag => tagsSet.add(tag));
773
+ project.tags.forEach((tag: string) => tagsSet.add(tag));
774
774
  }
775
775
  });
776
776
  setAllTags(Array.from(tagsSet));
@@ -795,7 +795,7 @@ const App: React.FC = () => {
795
795
  const nameMatch = fuzzyMatch(query, project.name);
796
796
  const descMatch = project.description ? fuzzyMatch(query, project.description) : false;
797
797
  const pathMatch = fuzzyMatch(query, project.path);
798
- const tagsMatch = project.tags?.some(tag => fuzzyMatch(query, tag)) || false;
798
+ const tagsMatch = project.tags?.some((tag: string) => fuzzyMatch(query, tag)) || false;
799
799
 
800
800
  return nameMatch || descMatch || pathMatch || tagsMatch;
801
801
  });
@@ -1394,7 +1394,7 @@ const App: React.FC = () => {
1394
1394
  try {
1395
1395
  const db = getDatabaseManager();
1396
1396
  const currentTags = selectedProject.tags || [];
1397
- db.updateProject(selectedProject.id, { tags: currentTags.filter(t => t !== tag) });
1397
+ db.updateProject(selectedProject.id, { tags: currentTags.filter((t: string) => t !== tag) });
1398
1398
  loadProjects();
1399
1399
  loadAllTags();
1400
1400
  } catch (err) {
@@ -1416,7 +1416,7 @@ const App: React.FC = () => {
1416
1416
  />
1417
1417
  <Box width={1} />
1418
1418
  <ProjectDetailsComponent
1419
- project={selectedProject}
1419
+ project={selectedProject}
1420
1420
  runningProcesses={runningProcesses}
1421
1421
  isFocused={focusedPanel === 'details'}
1422
1422
  editingName={editingName}
@@ -15,15 +15,36 @@ 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
- exports.runScriptInBackground = exports.stopProjectProcesses = exports.stopScriptByPort = exports.stopScript = exports.getRunningProcessesClean = exports.getRunningProcesses = exports.getProjectProcesses = exports.removeProcess = exports.loadProcesses = exports.runScript = exports.getProjectScripts = exports.detectProjectType = void 0;
36
+ exports.detectProjectType = detectProjectType;
37
+ exports.getProjectScripts = getProjectScripts;
38
+ exports.runScript = runScript;
39
+ exports.loadProcesses = loadProcesses;
40
+ exports.removeProcess = removeProcess;
41
+ exports.getProjectProcesses = getProjectProcesses;
42
+ exports.getRunningProcesses = getRunningProcesses;
43
+ exports.getRunningProcessesClean = getRunningProcessesClean;
44
+ exports.stopScript = stopScript;
45
+ exports.stopScriptByPort = stopScriptByPort;
46
+ exports.stopProjectProcesses = stopProjectProcesses;
47
+ exports.runScriptInBackground = runScriptInBackground;
27
48
  const fs = __importStar(require("fs"));
28
49
  const path = __importStar(require("path"));
29
50
  const os = __importStar(require("os"));
@@ -51,7 +72,6 @@ function detectProjectType(projectPath) {
51
72
  }
52
73
  return 'unknown';
53
74
  }
54
- exports.detectProjectType = detectProjectType;
55
75
  /**
56
76
  * Parse scripts from package.json (Node.js)
57
77
  */
@@ -252,7 +272,6 @@ function getProjectScripts(projectPath) {
252
272
  scripts,
253
273
  };
254
274
  }
255
- exports.getProjectScripts = getProjectScripts;
256
275
  /**
257
276
  * Handle port conflict - prompt user or auto-kill based on force flag
258
277
  */
@@ -457,7 +476,6 @@ function runScript(projectPath, scriptName, args = [], force = false) {
457
476
  });
458
477
  });
459
478
  }
460
- exports.runScript = runScript;
461
479
  /**
462
480
  * Get the path to the processes file
463
481
  */
@@ -484,7 +502,6 @@ function loadProcesses() {
484
502
  return [];
485
503
  }
486
504
  }
487
- exports.loadProcesses = loadProcesses;
488
505
  /**
489
506
  * Save running processes to disk
490
507
  */
@@ -508,7 +525,6 @@ function removeProcess(pid) {
508
525
  const filtered = processes.filter(p => p.pid !== pid);
509
526
  saveProcesses(filtered);
510
527
  }
511
- exports.removeProcess = removeProcess;
512
528
  /**
513
529
  * Get all running processes for a project
514
530
  */
@@ -516,7 +532,6 @@ function getProjectProcesses(projectPath) {
516
532
  const processes = loadProcesses();
517
533
  return processes.filter(p => p.projectPath === projectPath);
518
534
  }
519
- exports.getProjectProcesses = getProjectProcesses;
520
535
  /**
521
536
  * Check if a process is still running
522
537
  */
@@ -566,7 +581,6 @@ async function cleanupDeadProcesses() {
566
581
  function getRunningProcesses() {
567
582
  return loadProcesses();
568
583
  }
569
- exports.getRunningProcesses = getRunningProcesses;
570
584
  /**
571
585
  * Get all running processes with cleanup (async version)
572
586
  */
@@ -574,7 +588,6 @@ async function getRunningProcessesClean() {
574
588
  await cleanupDeadProcesses();
575
589
  return loadProcesses();
576
590
  }
577
- exports.getRunningProcessesClean = getRunningProcessesClean;
578
591
  /**
579
592
  * Extract URLs from text output
580
593
  */
@@ -680,7 +693,6 @@ async function stopScript(pid) {
680
693
  return false;
681
694
  }
682
695
  }
683
- exports.stopScript = stopScript;
684
696
  /**
685
697
  * Stop a script by port (finds process using port and kills it)
686
698
  */
@@ -707,7 +719,6 @@ async function stopScriptByPort(port) {
707
719
  return false;
708
720
  }
709
721
  }
710
- exports.stopScriptByPort = stopScriptByPort;
711
722
  /**
712
723
  * Stop all processes for a project
713
724
  */
@@ -721,7 +732,6 @@ async function stopProjectProcesses(projectPath) {
721
732
  }
722
733
  return stopped;
723
734
  }
724
- exports.stopProjectProcesses = stopProjectProcesses;
725
735
  /**
726
736
  * Execute a script in the background (minimal logging)
727
737
  */
@@ -935,7 +945,6 @@ function runScriptInBackground(projectPath, projectName, scriptName, args = [],
935
945
  resolve(child.pid);
936
946
  });
937
947
  }
938
- exports.runScriptInBackground = runScriptInBackground;
939
948
  /**
940
949
  * Check log file for test output and parse results
941
950
  */
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  // Test output parser for extracting test statistics from common test runners
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.isTestOutput = exports.parseTestOutput = void 0;
4
+ exports.parseTestOutput = parseTestOutput;
5
+ exports.isTestOutput = isTestOutput;
5
6
  /**
6
7
  * Parse test output from various frameworks and extract statistics
7
8
  */
@@ -42,7 +43,6 @@ function parseTestOutput(output) {
42
43
  }
43
44
  return result.total > 0 ? result : null;
44
45
  }
45
- exports.parseTestOutput = parseTestOutput;
46
46
  /**
47
47
  * Parse Jest/Vitest output
48
48
  */
@@ -197,4 +197,3 @@ function isTestOutput(output) {
197
197
  ];
198
198
  return testIndicators.some(indicator => output.includes(indicator));
199
199
  }
200
- exports.isTestOutput = isTestOutput;
package/jest.config.js CHANGED
@@ -12,6 +12,14 @@ module.exports = {
12
12
  ],
13
13
  coverageDirectory: 'coverage',
14
14
  coverageReporters: ['text', 'lcov', 'html'],
15
+ coverageThreshold: {
16
+ global: {
17
+ branches: 75,
18
+ functions: 80,
19
+ lines: 80,
20
+ statements: 80,
21
+ },
22
+ },
15
23
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
16
24
  verbose: true,
17
25
  };
package/package.json CHANGED
@@ -1,26 +1,30 @@
1
1
  {
2
2
  "name": "projax",
3
- "version": "3.3.51",
3
+ "version": "3.3.52",
4
4
  "description": "Cross-platform project management dashboard for tracking local development projects. Features CLI, Terminal UI, Desktop app, REST API, and built-in tools for test detection, port management, and script execution.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "prx": "./dist/index.js"
8
8
  },
9
9
  "scripts": {
10
- "build": "pnpm exec tsc",
11
- "build:electron": "cd ../desktop && npm run build",
10
+ "build": "tsc",
11
+ "typecheck": "echo \"Skipping cli typecheck (legacy)\"",
12
+ "lint": "echo \"Skipping cli lint (not configured)\"",
13
+ "lint:fix": "echo \"Skipping cli lint (not configured)\"",
14
+ "build:electron": "cd ../desktop && pnpm run build",
12
15
  "copy:electron": "mkdir -p dist/electron && cp -r ../desktop/dist/* dist/electron/ && cp dist/script-runner.* dist/electron/ && cp dist/port-*.* dist/electron/ && cp -R dist/core dist/electron/",
13
16
  "copy:api": "mkdir -p dist/api && cp -r ../api/dist/* dist/api/ && cp ../api/package.json dist/api/",
14
17
  "copy:core": "mkdir -p dist/core && cp -r ../core/dist/* dist/core/",
15
18
  "copy:prxi": "cp src/prxi.tsx dist/prxi.tsx",
16
- "build:all": "npm run build && npm run copy:core && npm run build:electron && npm run copy:electron && npm run copy:api && npm run copy:prxi",
19
+ "build:all": "pnpm run build && pnpm run copy:core && pnpm run build:electron && pnpm run copy:electron && pnpm run copy:api && pnpm run copy:prxi",
17
20
  "clean": "rm -rf dist",
18
21
  "test": "jest",
19
22
  "test:watch": "jest --watch",
20
23
  "test:coverage": "jest --coverage",
21
- "prepublishOnly": "npm run build:all"
24
+ "prepublishOnly": "pnpm run build:all"
22
25
  },
23
26
  "dependencies": {
27
+ "projax-core": "workspace:*",
24
28
  "chokidar": "^3.6.0",
25
29
  "commander": "^11.1.0",
26
30
  "cors": "^2.8.5",
@@ -28,7 +32,6 @@
28
32
  "express": "^4.18.2",
29
33
  "ink": "^3.2.0",
30
34
  "inquirer": "^9.2.12",
31
- "projax-core": "workspace:*",
32
35
  "react": "^17.0.2",
33
36
  "tail": "^2.2.6",
34
37
  "tsx": "^4.20.6"
@@ -1,3 +0,0 @@
1
- declare const router: import("express-serve-static-core").Router;
2
- export default router;
3
- //# sourceMappingURL=mcp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/routes/mcp.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAuHxB,eAAe,MAAM,CAAC"}
@@ -1,147 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
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
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- const express_1 = require("express");
27
- const child_process_1 = require("child_process");
28
- const fs = __importStar(require("fs"));
29
- const path = __importStar(require("path"));
30
- const router = (0, express_1.Router)();
31
- /**
32
- * Get MCP server status and configuration
33
- */
34
- router.get('/status', (req, res) => {
35
- try {
36
- // Check if prx command is available
37
- let prxPath = 'prx';
38
- let isPrxAvailable = false;
39
- try {
40
- prxPath = (0, child_process_1.execSync)('which prx', { encoding: 'utf-8' }).trim();
41
- isPrxAvailable = !!prxPath;
42
- }
43
- catch {
44
- isPrxAvailable = false;
45
- }
46
- // Check if MCP server package exists
47
- let isMcpServerBuilt = false;
48
- try {
49
- const mcpServerPath = path.join(__dirname, '..', '..', '..', 'mcp-server', 'dist', 'index.js');
50
- isMcpServerBuilt = fs.existsSync(mcpServerPath);
51
- }
52
- catch {
53
- isMcpServerBuilt = false;
54
- }
55
- const cursorConfig = {
56
- mcpServers: {
57
- projax: {
58
- command: prxPath,
59
- args: ['mcp'],
60
- },
61
- },
62
- };
63
- const vscodeConfig = {
64
- 'mcp.servers': {
65
- projax: {
66
- command: prxPath,
67
- args: ['mcp'],
68
- },
69
- },
70
- };
71
- res.json({
72
- available: isPrxAvailable && isMcpServerBuilt,
73
- prxPath,
74
- isPrxAvailable,
75
- isMcpServerBuilt,
76
- cursorConfig,
77
- vscodeConfig,
78
- resources: [
79
- {
80
- uri: 'projax://current-workspace',
81
- description: 'Information about the current project and its linked projects in the workspace',
82
- },
83
- {
84
- uri: 'projax://project/{projectPath}',
85
- description: 'Context for a specific project by path',
86
- },
87
- {
88
- uri: 'projax://workspace/{workspaceFilePath}',
89
- description: 'All projects in a specific workspace',
90
- },
91
- ],
92
- });
93
- }
94
- catch (error) {
95
- res.status(500).json({
96
- error: error instanceof Error ? error.message : 'Unknown error',
97
- available: false,
98
- });
99
- }
100
- });
101
- /**
102
- * Get MCP configuration for a specific editor
103
- */
104
- router.get('/config/:editor', (req, res) => {
105
- try {
106
- const editor = req.params.editor.toLowerCase();
107
- let prxPath = 'prx';
108
- try {
109
- prxPath = (0, child_process_1.execSync)('which prx', { encoding: 'utf-8' }).trim();
110
- }
111
- catch {
112
- // Use 'prx' as default
113
- }
114
- if (editor === 'cursor') {
115
- const config = {
116
- mcpServers: {
117
- projax: {
118
- command: prxPath,
119
- args: ['mcp'],
120
- },
121
- },
122
- };
123
- res.json(config);
124
- }
125
- else if (editor === 'vscode') {
126
- const config = {
127
- 'mcp.servers': {
128
- projax: {
129
- command: prxPath,
130
- args: ['mcp'],
131
- },
132
- },
133
- };
134
- res.json(config);
135
- }
136
- else {
137
- res.status(400).json({ error: 'Unknown editor. Use "cursor" or "vscode"' });
138
- }
139
- }
140
- catch (error) {
141
- res.status(500).json({
142
- error: error instanceof Error ? error.message : 'Unknown error',
143
- });
144
- }
145
- });
146
- exports.default = router;
147
- //# sourceMappingURL=mcp.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/routes/mcp.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- .project-list{flex:1;overflow-y:auto;overflow-x:hidden;min-height:0;padding:.75rem}.project-list::-webkit-scrollbar{width:6px}.project-list::-webkit-scrollbar-track{background:var(--bg-primary)}.project-list::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:3px}.project-list::-webkit-scrollbar-thumb:hover{background:var(--border-hover)}.project-list-loading,.project-list-empty{padding:2rem;text-align:center;color:var(--text-secondary)}.project-list-empty .hint{font-size:12px;color:var(--text-tertiary);margin-top:.5rem}.project-item{padding:.875rem;margin-bottom:.5rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;cursor:pointer;transition:all .15s ease;position:relative}.project-item:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:transparent;transition:background .15s ease}.project-item:hover{background:var(--bg-hover);border-color:var(--border-hover);transform:translate(2px)}.project-item:hover:before{background:var(--accent-cyan)}.project-item.selected{background:var(--bg-hover);border-color:var(--accent-cyan);box-shadow:var(--shadow-sm)}.project-item.keyboard-focused{outline:2px solid var(--accent-cyan);outline-offset:-2px;background:var(--bg-hover)}.project-item.selected:before{background:var(--accent-cyan)}.project-item-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:.5rem;gap:.5rem}.project-name{font-size:13px;font-weight:600;color:var(--text-primary);margin:0;flex:1;font-family:inherit;letter-spacing:.2px}.project-remove-btn{background:transparent;border:1px solid transparent;font-size:18px;color:var(--text-tertiary);cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:3px;transition:all .15s ease;flex-shrink:0;line-height:1}.project-remove-btn:hover{background:#ff52521a;color:#ff5252;border-color:#ff52524d}.project-path{font-size:11px;color:var(--text-tertiary);margin:.25rem 0;word-break:break-all;font-family:SF Mono,Monaco,monospace;opacity:.8}.project-meta{display:flex;justify-content:space-between;align-items:center;margin-top:.5rem;font-size:11px;color:var(--text-tertiary);gap:.5rem}.project-tags{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.5rem}.project-tag{background:var(--bg-hover);border:1px solid var(--border-color);padding:.125rem .5rem;border-radius:3px;font-size:10px;font-weight:500;color:var(--accent-cyan);font-family:SF Mono,Monaco,monospace;text-transform:uppercase;letter-spacing:.3px}.project-scanned{flex:1;font-family:SF Mono,Monaco,monospace}.project-scan-btn{background:transparent;border:1px solid var(--border-color);font-size:12px;cursor:pointer;padding:.25rem .5rem;border-radius:3px;transition:all .15s ease;color:var(--text-secondary);font-family:inherit}.project-scan-btn:hover:not(:disabled){background:var(--bg-hover);border-color:var(--accent-green);color:var(--accent-green)}.project-scan-btn:disabled{opacity:.3;cursor:not-allowed}.running-indicator-dot{color:var(--accent-green);margin-right:.5rem;font-size:10px;animation:pulse 2s infinite}.project-item.running:before{background:var(--accent-green)}.running-count{background:var(--accent-green);color:var(--bg-primary);padding:.125rem .5rem;border-radius:10px;font-size:10px;font-weight:600;font-family:SF Mono,Monaco,monospace}.running-ports{display:flex;gap:.25rem;flex-wrap:wrap}.port-badge{background:var(--accent-blue);color:var(--bg-primary);padding:.125rem .5rem;border-radius:3px;font-size:10px;font-weight:600;font-family:SF Mono,Monaco,monospace}.project-urls-section{background:var(--bg-secondary);padding:1.25rem;border-radius:4px;border:1px solid var(--border-color);margin-bottom:1.5rem}.urls-list{display:flex;flex-direction:column;gap:.5rem}.url-item{padding:.875rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;transition:all .15s ease;display:flex;justify-content:space-between;align-items:center;gap:1rem}.url-item:hover{background:var(--bg-hover);border-color:var(--border-hover)}.url-text{font-family:SF Mono,Monaco,monospace;font-size:12px;color:var(--accent-cyan);flex:1;word-break:break-all;cursor:pointer;text-decoration:underline}.url-text:hover{color:var(--accent-blue)}.project-details{max-width:1000px}.project-details-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:1px solid var(--border-color);gap:1rem}.project-details-header h2{font-size:18px;color:var(--text-primary);margin-bottom:.5rem;font-weight:600;font-family:inherit;letter-spacing:.3px}.project-name-editable{cursor:pointer;transition:color .15s ease}.project-name-editable:hover{color:var(--accent-cyan)}.project-name-edit{margin-bottom:.5rem}.project-name-input{background:var(--bg-tertiary);border:1px solid var(--accent-cyan);border-radius:4px;padding:.5rem;font-size:18px;font-weight:600;color:var(--text-primary);font-family:inherit;width:100%;max-width:400px}.project-name-input:focus{outline:none;box-shadow:0 0 0 2px #39c5cf33}.project-description-edit{margin-bottom:.5rem}.project-description-input{background:var(--bg-tertiary);border:1px solid var(--accent-cyan);border-radius:4px;padding:.5rem;font-size:13px;color:var(--text-primary);font-family:inherit;width:100%;max-width:600px;resize:vertical;min-height:60px}.project-description-input:focus{outline:none;box-shadow:0 0 0 2px #39c5cf33}.project-description{cursor:pointer;color:var(--text-secondary);font-size:13px;transition:color .15s ease;margin-bottom:.5rem}.project-description:hover{color:var(--text-primary)}.header-actions-group{display:flex;gap:.5rem;align-items:center}.project-path{color:var(--text-tertiary);font-size:11px;word-break:break-all;font-family:SF Mono,Monaco,monospace;opacity:.8}.project-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;margin-bottom:1.5rem}.stat-card{background:var(--bg-secondary);padding:1rem;border-radius:4px;border:1px solid var(--border-color);text-align:left;transition:all .15s ease}.stat-card:hover{border-color:var(--border-hover);background:var(--bg-tertiary)}.stat-value{font-size:24px;font-weight:600;color:var(--accent-cyan);margin-bottom:.25rem;font-family:SF Mono,Monaco,monospace;line-height:1.2}.stat-label{font-size:11px;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.5px;font-weight:500}.framework-breakdown{background:var(--bg-secondary);padding:1.25rem;border-radius:4px;border:1px solid var(--border-color);margin-bottom:1.5rem}.framework-breakdown h3{font-size:13px;color:var(--text-primary);margin-bottom:1rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;font-family:inherit}.framework-list{display:flex;flex-wrap:wrap;gap:.5rem}.framework-item{display:flex;align-items:center;gap:.5rem;padding:.375rem .75rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:3px;transition:all .15s ease}.framework-item:hover{border-color:var(--accent-purple);background:var(--bg-hover)}.framework-name{font-weight:500;color:var(--text-primary);font-size:12px;font-family:SF Mono,Monaco,monospace}.framework-count{background:var(--accent-purple);color:var(--bg-primary);padding:.125rem .5rem;border-radius:2px;font-size:11px;font-weight:600;font-family:SF Mono,Monaco,monospace}.tests-section{background:var(--bg-secondary);padding:1.25rem;border-radius:4px;border:1px solid var(--border-color);margin-bottom:1.5rem}.tests-section h3{font-size:13px;color:var(--text-primary);margin-bottom:1rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;font-family:inherit}.no-tests{padding:2rem;text-align:center;color:var(--text-tertiary);font-size:12px}.tests-list{display:flex;flex-direction:column;gap:.5rem}.test-item{padding:.875rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;transition:all .15s ease}.test-item:hover{background:var(--bg-hover);border-color:var(--border-hover);transform:translate(2px)}.test-file{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem;gap:.75rem}.test-path{font-family:SF Mono,Monaco,monospace;font-size:12px;color:var(--text-primary);flex:1;word-break:break-all}.test-framework{background:var(--accent-blue);color:var(--bg-primary);padding:.25rem .5rem;border-radius:3px;font-size:10px;font-weight:600;font-family:SF Mono,Monaco,monospace;text-transform:uppercase;letter-spacing:.3px;flex-shrink:0}.test-status{font-size:11px;color:var(--text-tertiary);font-family:SF Mono,Monaco,monospace}.jenkins-placeholder{background:var(--bg-secondary);padding:1.25rem;border-radius:4px;border:1px dashed var(--border-color);opacity:.6}.jenkins-placeholder h3{font-size:13px;color:var(--text-secondary);margin-bottom:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;font-family:inherit}.placeholder-text{color:var(--text-tertiary);font-style:italic;font-size:12px;line-height:1.6}.danger-zone{background:#f851490d;padding:1.25rem;border-radius:4px;border:1px solid rgba(248,81,73,.3);margin-top:1.5rem}.danger-zone h3{font-size:13px;color:#f85149;margin-bottom:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;font-family:inherit}.danger-zone-text{color:var(--text-secondary);font-size:12px;line-height:1.6;margin-bottom:1rem}.danger-zone .btn-danger{background:transparent;border:1px solid #f85149;color:#f85149}.danger-zone .btn-danger:hover:not(:disabled){background:#f85149;color:var(--bg-primary)}.btn-small{padding:.375rem .75rem;font-size:11px}.tags-section{background:var(--bg-secondary);padding:1.25rem;border-radius:4px;border:1px solid var(--border-color);margin-bottom:1.5rem}.tags-content{margin-top:.75rem}.tags-list{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center}.tag-item{background:var(--bg-tertiary);border:1px solid var(--border-color);padding:.375rem .375rem .375rem .625rem;border-radius:4px;font-size:11px;font-weight:500;color:var(--accent-cyan);font-family:SF Mono,Monaco,monospace;text-transform:uppercase;letter-spacing:.3px;display:flex;align-items:center;gap:.375rem;transition:all .15s ease}.tag-item:hover{border-color:var(--accent-cyan)}.tag-remove{background:none;border:none;color:var(--text-tertiary);cursor:pointer;padding:0 4px;font-size:16px;line-height:1;transition:color .15s ease}.tag-remove:hover{color:#f85149}.tag-add-btn{background:transparent;border:1px dashed var(--border-color);padding:.375rem .75rem;border-radius:4px;font-size:11px;font-weight:500;color:var(--text-secondary);cursor:pointer;transition:all .15s ease;text-transform:uppercase;letter-spacing:.3px}.tag-add-btn:hover{border-color:var(--accent-cyan);color:var(--accent-cyan);background:var(--bg-tertiary)}.tag-input-wrapper{position:relative;display:inline-block}.tag-input{background:var(--bg-tertiary);border:1px solid var(--accent-cyan);border-radius:4px;padding:.375rem .625rem;font-size:11px;font-family:SF Mono,Monaco,monospace;color:var(--text-primary);min-width:120px;outline:none}.tag-input:focus{box-shadow:0 0 0 2px #39c5cf33}.tag-suggestions{position:absolute;top:calc(100% + 4px);left:0;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;box-shadow:var(--shadow-md);z-index:100;min-width:100%;max-width:200px}.tag-suggestion{padding:.5rem .75rem;cursor:pointer;font-size:11px;color:var(--text-primary);font-family:SF Mono,Monaco,monospace;transition:all .15s ease}.tag-suggestion:first-child{border-radius:4px 4px 0 0}.tag-suggestion:last-child{border-radius:0 0 4px 4px}.tag-suggestion:hover{background:var(--bg-hover);color:var(--accent-cyan)}.ports-section,.scripts-section,.running-processes-section{background:var(--bg-secondary);padding:1.25rem;border-radius:4px;border:1px solid var(--border-color);margin-bottom:1.5rem}.section-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}.section-header h3{font-size:13px;color:var(--text-primary);font-weight:600;text-transform:uppercase;letter-spacing:.5px;font-family:inherit;margin:0}.project-type-badge{background:var(--bg-tertiary);border:1px solid var(--border-color);padding:.25rem .5rem;border-radius:3px;font-size:10px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.3px;font-family:SF Mono,Monaco,monospace}.ports-list,.scripts-list,.processes-list{display:flex;flex-direction:column;gap:.5rem}.port-item{padding:.875rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;transition:all .15s ease}.port-item:hover{background:var(--bg-hover);border-color:var(--border-hover)}.port-info{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.port-number{font-family:SF Mono,Monaco,monospace;font-size:13px;font-weight:600;color:var(--accent-cyan)}.port-script{font-family:SF Mono,Monaco,monospace;font-size:11px;color:var(--text-secondary)}.port-source{font-family:SF Mono,Monaco,monospace;font-size:11px;color:var(--text-tertiary);flex:1}.script-item{padding:.875rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;transition:all .15s ease;display:flex;justify-content:space-between;align-items:center;gap:1rem}.script-item:hover{background:var(--bg-hover);border-color:var(--border-hover)}.script-item.running{border-left:3px solid var(--accent-cyan)}.script-info{display:flex;flex-direction:column;gap:.5rem;flex:1}.script-header{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.script-process-info{display:flex;flex-direction:column;gap:.375rem;margin-top:.5rem;padding-top:.5rem;border-top:1px solid var(--border-color)}.process-badge{display:flex;align-items:center;gap:.5rem;font-size:11px;font-family:SF Mono,Monaco,monospace;color:var(--text-secondary)}.process-indicator{color:var(--accent-cyan);font-size:8px}.process-pid{color:var(--text-secondary)}.process-uptime{color:var(--text-tertiary)}.process-port{color:var(--accent-cyan);font-weight:600}.script-name{font-family:SF Mono,Monaco,monospace;font-size:13px;font-weight:600;color:var(--text-primary);min-width:80px}.script-command{font-family:SF Mono,Monaco,monospace;font-size:11px;color:var(--text-secondary);flex:1;word-break:break-all}.script-runner{background:var(--bg-hover);border:1px solid var(--border-color);padding:.25rem .5rem;border-radius:3px;font-size:10px;font-weight:600;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.3px;font-family:SF Mono,Monaco,monospace;flex-shrink:0}.script-actions{display:flex;gap:.5rem;flex-shrink:0}.loading-state,.no-scripts{padding:2rem;text-align:center;color:var(--text-tertiary);font-size:12px}.running-indicator{color:var(--accent-green);font-size:12px;margin-right:.5rem;animation:pulse 2s infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.process-item{padding:.875rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;transition:all .15s ease;display:flex;justify-content:space-between;align-items:center;gap:1rem}.process-item:hover{background:var(--bg-hover);border-color:var(--border-hover)}.process-info{display:flex;align-items:center;gap:.75rem;flex:1;flex-wrap:wrap}.process-name{font-family:SF Mono,Monaco,monospace;font-size:13px;font-weight:600;color:var(--text-primary);min-width:100px}.process-pid{font-family:SF Mono,Monaco,monospace;font-size:11px;color:var(--text-secondary)}.process-uptime{font-family:SF Mono,Monaco,monospace;font-size:11px;color:var(--text-tertiary)}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#000000b3;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:1000}.modal-content{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:4px;width:90%;max-width:500px;box-shadow:var(--shadow-lg);animation:modalSlideIn .2s ease}@keyframes modalSlideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:1.25rem;border-bottom:1px solid var(--border-color)}.modal-header h2{font-size:14px;color:var(--text-primary);margin:0;font-weight:600;text-transform:uppercase;letter-spacing:.5px;font-family:inherit}.modal-close{background:transparent;border:1px solid transparent;font-size:20px;color:var(--text-tertiary);cursor:pointer;padding:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border-radius:3px;transition:all .15s ease;line-height:1}.modal-close:hover{background:var(--bg-hover);color:var(--text-primary);border-color:var(--border-color)}.modal-content form{padding:1.25rem}.form-group{margin-bottom:1.25rem}.form-group label{display:block;margin-bottom:.5rem;font-weight:500;color:var(--text-primary);font-size:12px;text-transform:uppercase;letter-spacing:.3px;font-family:inherit}.path-input-group{display:flex;gap:.5rem}.path-input-group input{flex:1;padding:.625rem;border:1px solid var(--border-color);border-radius:4px;font-size:12px;font-family:SF Mono,Monaco,monospace;background:var(--bg-tertiary);color:var(--text-primary);transition:all .15s ease}.path-input-group input::placeholder{color:var(--text-tertiary);opacity:.6}.path-input-group input:focus{outline:none;border-color:var(--accent-cyan);box-shadow:0 0 0 2px #39c5cf1a;background:var(--bg-hover)}.path-input-group input:disabled{background:var(--bg-primary);cursor:not-allowed;opacity:.5}.modal-actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:1.25rem}.project-search{padding:12px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0;z-index:10}.search-input-group{display:flex;gap:8px;position:relative}.search-input-wrapper{flex:1;position:relative;display:flex;align-items:center}.search-input{flex:1;padding:8px 36px 8px 12px;border:1px solid var(--border-color);border-radius:4px;font-size:14px;outline:none;transition:border-color .2s;background:var(--bg-tertiary);color:var(--text-primary)}.sort-icon-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text-tertiary);cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:3px;transition:all .15s ease}.sort-icon-btn:hover{color:var(--text-primary);background:var(--bg-hover)}.sort-menu{position:absolute;top:calc(100% + 4px);right:0;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;box-shadow:var(--shadow-md);z-index:100;min-width:180px;padding:4px}.sort-menu-item{padding:8px 12px;cursor:pointer;border-radius:3px;font-size:13px;color:var(--text-primary);display:flex;justify-content:space-between;align-items:center;transition:all .15s ease}.sort-menu-item:hover{background:var(--bg-hover)}.sort-menu-item.active{background:var(--bg-hover);color:var(--accent-cyan)}.sort-menu-item .checkmark{color:var(--accent-green);font-size:12px;margin-left:8px}.search-input:focus{border-color:var(--accent-cyan)}.search-input::placeholder{color:var(--text-tertiary)}.search-filter{padding:8px 12px;border:1px solid var(--border-color);border-radius:4px;font-size:14px;background:var(--bg-tertiary);color:var(--text-primary);cursor:pointer;outline:none;transition:border-color .2s}.search-filter:focus{border-color:var(--accent-cyan)}.search-filter:hover{border-color:var(--border-hover);background:var(--bg-hover)}.settings-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.settings-modal{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:8px;width:90%;max-width:600px;max-height:90vh;display:flex;flex-direction:column;box-shadow:var(--shadow-lg)}.settings-header{display:flex;justify-content:space-between;align-items:center;padding:1.5rem;border-bottom:1px solid var(--border-color)}.settings-header h2{font-size:18px;font-weight:600;color:var(--text-primary);margin:0}.settings-close-btn{background:none;border:none;color:var(--text-secondary);font-size:24px;cursor:pointer;padding:0;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .15s ease}.settings-close-btn:hover{background:var(--bg-tertiary);color:var(--text-primary)}.settings-content{padding:1.5rem;overflow-y:auto;flex:1}.settings-section{margin-bottom:2rem}.settings-section:last-child{margin-bottom:0}.settings-section h3{font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:1rem;text-transform:uppercase;letter-spacing:.5px}.settings-field{margin-bottom:1rem}.settings-field:last-child{margin-bottom:0}.settings-field label{display:block;font-size:12px;color:var(--text-secondary);margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.3px}.settings-select,.settings-input{width:100%;padding:.75rem;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;color:var(--text-primary);font-size:13px;font-family:inherit;outline:none;transition:border-color .15s ease}.settings-select:focus,.settings-input:focus{border-color:var(--accent-cyan)}.settings-input{font-family:SF Mono,Monaco,monospace}.settings-footer{display:flex;justify-content:flex-end;gap:.75rem;padding:1.5rem;border-top:1px solid var(--border-color)}.loading-state{padding:3rem;text-align:center;color:var(--text-tertiary);font-size:13px}.app-header{-webkit-app-region:drag;-webkit-user-select:none;user-select:none;display:flex;align-items:center;gap:1rem}.app-header button,.app-header .btn,.app-header .btn-link,.app-header .header-actions{-webkit-app-region:no-drag}.status-bar{background:var(--bg-secondary);border-top:1px solid var(--border-color);padding:.5rem 1.5rem;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;font-size:11px;font-family:SF Mono,Monaco,monospace}.status-bar-content{display:flex;align-items:center;gap:1rem;width:100%;justify-content:space-between}.status-indicator{display:flex;align-items:center;gap:.5rem}.status-dot{width:6px;height:6px;border-radius:50%;display:inline-block}.status-dot.connected{background:var(--accent-green);box-shadow:0 0 4px var(--accent-green)}.status-dot.disconnected{background:#f85149;box-shadow:0 0 4px #f85149}.status-text{color:var(--text-secondary);font-size:11px;text-transform:uppercase;letter-spacing:.5px}.api-port{color:var(--text-tertiary);font-size:11px;font-family:SF Mono,Monaco,monospace}.app{display:flex;flex-direction:column;height:100vh;overflow:hidden;background:var(--bg-primary)}.app-header{background:var(--bg-secondary);border-bottom:1px solid var(--border-color);padding:.5rem 1.5rem;display:flex;align-items:center;justify-content:center;gap:1rem;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);position:relative;z-index:10;flex-shrink:0}.app-header:after{content:"";position:absolute;bottom:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent 0%,var(--accent-cyan) 50%,transparent 100%);opacity:.3}.app-logo{margin:0;font-size:12px;font-weight:600;letter-spacing:1.5px;color:var(--accent-cyan);position:absolute;left:50%;transform:translate(-50%)}.header-actions{display:flex;gap:1.5rem;margin-left:auto}.btn-link{padding:0;border:none;background:none;font-size:11px;font-weight:500;cursor:pointer;transition:color .15s ease;font-family:inherit;letter-spacing:.3px;text-transform:uppercase;color:var(--text-secondary);-webkit-app-region:no-drag}.btn-link:hover:not(:disabled){color:var(--text-primary)}.btn-link:disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.btn-link-primary{color:var(--accent-cyan)}.btn-link-primary:hover:not(:disabled){color:var(--accent-blue)}.btn{padding:.5rem 1rem;border:1px solid var(--border-color);border-radius:4px;font-size:12px;font-weight:500;cursor:pointer;transition:all .15s ease;font-family:inherit;letter-spacing:.3px;text-transform:uppercase;background:var(--bg-tertiary);color:var(--text-primary)}.btn:disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.btn-primary{background:var(--accent-cyan);color:var(--bg-primary);border-color:var(--accent-cyan);font-weight:600}.btn-primary:hover:not(:disabled){background:var(--accent-blue);border-color:var(--accent-blue);transform:translateY(-1px);box-shadow:var(--shadow-sm)}.btn-secondary{background:transparent;color:var(--text-secondary);border-color:var(--border-color)}.btn-secondary:hover:not(:disabled){background:var(--bg-hover);border-color:var(--border-hover);color:var(--text-primary)}.btn-danger{background:transparent;color:#f85149;border-color:#f85149}.btn-danger:hover:not(:disabled){background:#f851491a;border-color:#f85149;color:#f85149}.app-content{display:flex;flex:1;overflow:hidden;position:relative}.react-resizable-handle{position:absolute;width:4px;right:-2px;top:0;bottom:0;cursor:col-resize;background:transparent;z-index:10}.react-resizable-handle:hover{background:var(--accent-cyan);opacity:.3}.react-resizable-handle:active{background:var(--accent-cyan);opacity:.6}.sidebar{width:100%;height:100%;background:var(--bg-secondary);border-right:1px solid var(--border-color);overflow:hidden;display:flex;flex-direction:column}.sidebar::-webkit-scrollbar{width:6px}.sidebar::-webkit-scrollbar-track{background:var(--bg-primary)}.sidebar::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:3px}.sidebar::-webkit-scrollbar-thumb:hover{background:var(--border-hover)}.main-content{flex:1;overflow-y:auto;padding:1.5rem;background:var(--bg-primary)}.main-content::-webkit-scrollbar{width:6px}.main-content::-webkit-scrollbar-track{background:var(--bg-primary)}.main-content::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:3px}.main-content::-webkit-scrollbar-thumb:hover{background:var(--border-hover)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--text-secondary);text-align:center;padding:2rem}.empty-state h2{margin-bottom:.5rem;color:var(--text-primary);font-size:16px;font-weight:500}.empty-state p{color:var(--text-tertiary);font-size:13px}.app-footer{background:var(--bg-secondary);border-top:1px solid var(--border-color);padding:.5rem 1.5rem;flex-shrink:0}*{margin:0;padding:0;box-sizing:border-box}:root{--bg-primary: #0d1117;--bg-secondary: #161b22;--bg-tertiary: #1c2128;--bg-hover: #21262d;--border-color: #30363d;--border-hover: #484f58;--text-primary: #c9d1d9;--text-secondary: #8b949e;--text-tertiary: #6e7681;--accent-cyan: #39c5cf;--accent-blue: #58a6ff;--accent-green: #3fb950;--accent-purple: #bc8cff;--accent-orange: #ffa657;--shadow-sm: 0 1px 3px rgba(0, 0, 0, .3);--shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--shadow-lg: 0 8px 24px rgba(0, 0, 0, .5)}body{font-family:SF Mono,Monaco,Inconsolata,Fira Code,Fira Mono,Droid Sans Mono,Source Code Pro,Menlo,Consolas,Courier New,monospace;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:var(--bg-primary);color:var(--text-primary);font-size:13px;line-height:1.5;-webkit-user-select:none;user-select:none}input,textarea,[contenteditable=true],[contenteditable=""]{-webkit-user-select:text;user-select:text}code{font-family:SF Mono,Monaco,Inconsolata,Fira Code,Fira Mono,Droid Sans Mono,Source Code Pro,Menlo,Consolas,Courier New,monospace}#root{width:100%;height:100vh}