projax 3.3.39 → 3.3.51

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 (115) hide show
  1. package/README.md +73 -0
  2. package/dist/__tests__/port-scanner.test.js +7 -17
  3. package/dist/__tests__/script-runner.test.js +7 -17
  4. package/dist/api/__tests__/database.test.js +7 -17
  5. package/dist/api/__tests__/database.test.js.map +1 -1
  6. package/dist/api/__tests__/routes.test.js +7 -17
  7. package/dist/api/__tests__/routes.test.js.map +1 -1
  8. package/dist/api/__tests__/scanner.test.js +7 -17
  9. package/dist/api/__tests__/scanner.test.js.map +1 -1
  10. package/dist/api/database.d.ts +20 -1
  11. package/dist/api/database.d.ts.map +1 -1
  12. package/dist/api/database.js +192 -21
  13. package/dist/api/database.js.map +1 -1
  14. package/dist/api/index.d.ts.map +1 -1
  15. package/dist/api/index.js +17 -19
  16. package/dist/api/index.js.map +1 -1
  17. package/dist/api/migrate.js +2 -1
  18. package/dist/api/migrate.js.map +1 -1
  19. package/dist/api/package.json +3 -2
  20. package/dist/api/routes/backup.d.ts +3 -0
  21. package/dist/api/routes/backup.d.ts.map +1 -0
  22. package/dist/api/routes/backup.js +51 -0
  23. package/dist/api/routes/backup.js.map +1 -0
  24. package/dist/api/routes/index.d.ts.map +1 -1
  25. package/dist/api/routes/index.js +6 -0
  26. package/dist/api/routes/index.js.map +1 -1
  27. package/dist/api/routes/mcp.d.ts +3 -0
  28. package/dist/api/routes/mcp.d.ts.map +1 -0
  29. package/dist/api/routes/mcp.js +147 -0
  30. package/dist/api/routes/mcp.js.map +1 -0
  31. package/dist/api/routes/projects.d.ts.map +1 -1
  32. package/dist/api/routes/projects.js +27 -17
  33. package/dist/api/routes/projects.js.map +1 -1
  34. package/dist/api/routes/settings.d.ts.map +1 -1
  35. package/dist/api/routes/settings.js +119 -11
  36. package/dist/api/routes/settings.js.map +1 -1
  37. package/dist/api/routes/workspaces.d.ts +3 -0
  38. package/dist/api/routes/workspaces.d.ts.map +1 -0
  39. package/dist/api/routes/workspaces.js +504 -0
  40. package/dist/api/routes/workspaces.js.map +1 -0
  41. package/dist/api/services/scanner.js +10 -19
  42. package/dist/api/services/scanner.js.map +1 -1
  43. package/dist/api/services/test-parser.js +3 -2
  44. package/dist/api/services/test-parser.js.map +1 -1
  45. package/dist/api/types.d.ts +31 -0
  46. package/dist/api/types.d.ts.map +1 -1
  47. package/dist/core/__tests__/database.test.js +7 -17
  48. package/dist/core/__tests__/detector.test.js +7 -17
  49. package/dist/core/__tests__/index.test.js +7 -17
  50. package/dist/core/__tests__/scanner.test.js +7 -17
  51. package/dist/core/__tests__/settings.test.js +7 -17
  52. package/dist/core/backup-utils.d.ts +17 -0
  53. package/dist/core/backup-utils.js +157 -0
  54. package/dist/core/database.d.ts +1 -0
  55. package/dist/core/database.js +9 -18
  56. package/dist/core/detector.js +11 -21
  57. package/dist/core/git-utils.d.ts +12 -0
  58. package/dist/core/git-utils.js +87 -0
  59. package/dist/core/index.d.ts +3 -0
  60. package/dist/core/index.js +8 -5
  61. package/dist/core/scanner.js +3 -2
  62. package/dist/core/settings.d.ts +85 -0
  63. package/dist/core/settings.js +306 -9
  64. package/dist/core/workspace-utils.d.ts +37 -0
  65. package/dist/core/workspace-utils.js +143 -0
  66. package/dist/core-bridge.js +7 -17
  67. package/dist/electron/core/__tests__/database.test.js +7 -17
  68. package/dist/electron/core/__tests__/detector.test.js +7 -17
  69. package/dist/electron/core/__tests__/index.test.js +7 -17
  70. package/dist/electron/core/__tests__/scanner.test.js +7 -17
  71. package/dist/electron/core/__tests__/settings.test.js +7 -17
  72. package/dist/electron/core/backup-utils.d.ts +17 -0
  73. package/dist/electron/core/backup-utils.js +157 -0
  74. package/dist/electron/core/database.d.ts +1 -0
  75. package/dist/electron/core/database.js +9 -18
  76. package/dist/electron/core/detector.js +11 -21
  77. package/dist/electron/core/git-utils.d.ts +12 -0
  78. package/dist/electron/core/git-utils.js +87 -0
  79. package/dist/electron/core/index.d.ts +3 -0
  80. package/dist/electron/core/index.js +8 -5
  81. package/dist/electron/core/scanner.js +3 -2
  82. package/dist/electron/core/settings.d.ts +85 -0
  83. package/dist/electron/core/settings.js +306 -9
  84. package/dist/electron/core/workspace-utils.d.ts +37 -0
  85. package/dist/electron/core/workspace-utils.js +143 -0
  86. package/dist/electron/core.js +7 -17
  87. package/dist/electron/main.js +663 -33
  88. package/dist/electron/port-extractor.js +9 -18
  89. package/dist/electron/port-scanner.js +11 -20
  90. package/dist/electron/port-utils.js +5 -4
  91. package/dist/electron/preload.d.ts +27 -2
  92. package/dist/electron/preload.js +18 -2
  93. package/dist/electron/renderer/assets/index-B-etDnj2.js +64 -0
  94. package/dist/electron/renderer/assets/index-Bx18Cyic.js +64 -0
  95. package/dist/electron/renderer/assets/index-C8f5yNYe.js +64 -0
  96. package/dist/electron/renderer/assets/index-CIZ3Wl6c.css +1 -0
  97. package/dist/electron/renderer/assets/index-CJbsU9y8.css +1 -0
  98. package/dist/electron/renderer/assets/index-CopVNRnR.js +64 -0
  99. package/dist/electron/renderer/assets/index-DUvcepWm.js +64 -0
  100. package/dist/electron/renderer/assets/index-DWe2TQFv.css +1 -0
  101. package/dist/electron/renderer/assets/index-DZzB20Xf.css +1 -0
  102. package/dist/electron/renderer/assets/index-DknLdADV.js +63 -0
  103. package/dist/electron/renderer/assets/index-DocuD8Lk.js +64 -0
  104. package/dist/electron/renderer/assets/index-DyU-xfd8.css +1 -0
  105. package/dist/electron/renderer/assets/index-GwC-JVUy.css +1 -0
  106. package/dist/electron/renderer/assets/index-fehviker.js +63 -0
  107. package/dist/electron/renderer/index.html +2 -2
  108. package/dist/electron/script-runner.js +20 -29
  109. package/dist/index.js +395 -21
  110. package/dist/port-extractor.js +9 -18
  111. package/dist/port-scanner.js +11 -20
  112. package/dist/port-utils.js +5 -4
  113. package/dist/script-runner.js +20 -29
  114. package/dist/test-parser.js +3 -2
  115. package/package.json +3 -2
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' http://localhost:* ws://localhost:*;" />
7
7
  <title>projax</title>
8
- <script type="module" crossorigin src="./assets/index-JXrtTB1F.js"></script>
9
- <link rel="stylesheet" crossorigin href="./assets/index-Dk0EQt0u.css">
8
+ <script type="module" crossorigin src="./assets/index-B-etDnj2.js"></script>
9
+ <link rel="stylesheet" crossorigin href="./assets/index-DyU-xfd8.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -15,36 +15,15 @@ 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
- 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
- })();
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
+ };
35
25
  Object.defineProperty(exports, "__esModule", { value: true });
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;
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;
48
27
  const fs = __importStar(require("fs"));
49
28
  const path = __importStar(require("path"));
50
29
  const os = __importStar(require("os"));
@@ -72,6 +51,7 @@ function detectProjectType(projectPath) {
72
51
  }
73
52
  return 'unknown';
74
53
  }
54
+ exports.detectProjectType = detectProjectType;
75
55
  /**
76
56
  * Parse scripts from package.json (Node.js)
77
57
  */
@@ -272,6 +252,7 @@ function getProjectScripts(projectPath) {
272
252
  scripts,
273
253
  };
274
254
  }
255
+ exports.getProjectScripts = getProjectScripts;
275
256
  /**
276
257
  * Handle port conflict - prompt user or auto-kill based on force flag
277
258
  */
@@ -476,6 +457,7 @@ function runScript(projectPath, scriptName, args = [], force = false) {
476
457
  });
477
458
  });
478
459
  }
460
+ exports.runScript = runScript;
479
461
  /**
480
462
  * Get the path to the processes file
481
463
  */
@@ -502,6 +484,7 @@ function loadProcesses() {
502
484
  return [];
503
485
  }
504
486
  }
487
+ exports.loadProcesses = loadProcesses;
505
488
  /**
506
489
  * Save running processes to disk
507
490
  */
@@ -525,6 +508,7 @@ function removeProcess(pid) {
525
508
  const filtered = processes.filter(p => p.pid !== pid);
526
509
  saveProcesses(filtered);
527
510
  }
511
+ exports.removeProcess = removeProcess;
528
512
  /**
529
513
  * Get all running processes for a project
530
514
  */
@@ -532,6 +516,7 @@ function getProjectProcesses(projectPath) {
532
516
  const processes = loadProcesses();
533
517
  return processes.filter(p => p.projectPath === projectPath);
534
518
  }
519
+ exports.getProjectProcesses = getProjectProcesses;
535
520
  /**
536
521
  * Check if a process is still running
537
522
  */
@@ -581,6 +566,7 @@ async function cleanupDeadProcesses() {
581
566
  function getRunningProcesses() {
582
567
  return loadProcesses();
583
568
  }
569
+ exports.getRunningProcesses = getRunningProcesses;
584
570
  /**
585
571
  * Get all running processes with cleanup (async version)
586
572
  */
@@ -588,6 +574,7 @@ async function getRunningProcessesClean() {
588
574
  await cleanupDeadProcesses();
589
575
  return loadProcesses();
590
576
  }
577
+ exports.getRunningProcessesClean = getRunningProcessesClean;
591
578
  /**
592
579
  * Extract URLs from text output
593
580
  */
@@ -693,6 +680,7 @@ async function stopScript(pid) {
693
680
  return false;
694
681
  }
695
682
  }
683
+ exports.stopScript = stopScript;
696
684
  /**
697
685
  * Stop a script by port (finds process using port and kills it)
698
686
  */
@@ -719,6 +707,7 @@ async function stopScriptByPort(port) {
719
707
  return false;
720
708
  }
721
709
  }
710
+ exports.stopScriptByPort = stopScriptByPort;
722
711
  /**
723
712
  * Stop all processes for a project
724
713
  */
@@ -732,6 +721,7 @@ async function stopProjectProcesses(projectPath) {
732
721
  }
733
722
  return stopped;
734
723
  }
724
+ exports.stopProjectProcesses = stopProjectProcesses;
735
725
  /**
736
726
  * Execute a script in the background (minimal logging)
737
727
  */
@@ -945,6 +935,7 @@ function runScriptInBackground(projectPath, projectName, scriptName, args = [],
945
935
  resolve(child.pid);
946
936
  });
947
937
  }
938
+ exports.runScriptInBackground = runScriptInBackground;
948
939
  /**
949
940
  * Check log file for test output and parse results
950
941
  */
package/dist/index.js CHANGED
@@ -16,23 +16,13 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
16
16
  }) : function(o, v) {
17
17
  o["default"] = v;
18
18
  });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
36
26
  Object.defineProperty(exports, "__esModule", { value: true });
37
27
  const commander_1 = require("commander");
38
28
  const path = __importStar(require("path"));
@@ -708,10 +698,23 @@ program
708
698
  else {
709
699
  // Table format
710
700
  console.log(`\nTracked Projects (${projects.length}):\n`);
701
+ // Fetch git branches for all projects
702
+ const { getCurrentBranch } = await Promise.resolve().then(() => __importStar(require('../../core/src/git-utils')));
703
+ const branchMap = new Map();
704
+ for (const project of projects) {
705
+ try {
706
+ const branch = getCurrentBranch(project.path);
707
+ branchMap.set(project.id, branch);
708
+ }
709
+ catch {
710
+ branchMap.set(project.id, null);
711
+ }
712
+ }
711
713
  // Calculate column widths
712
714
  const idWidth = Math.max(3, projects.length.toString().length);
713
715
  const nameWidth = Math.max(4, ...projects.map(p => p.name.length));
714
- const pathWidth = Math.max(4, Math.min(40, ...projects.map(p => p.path.length)));
716
+ const pathWidth = Math.max(4, Math.min(35, ...projects.map(p => p.path.length)));
717
+ const branchWidth = 15;
715
718
  const portsWidth = 12;
716
719
  const testsWidth = 6;
717
720
  const scannedWidth = 20;
@@ -720,6 +723,7 @@ program
720
723
  'ID'.padEnd(idWidth),
721
724
  'Name'.padEnd(nameWidth),
722
725
  'Path'.padEnd(pathWidth),
726
+ 'Branch'.padEnd(branchWidth),
723
727
  'Ports'.padEnd(portsWidth),
724
728
  'Tests'.padEnd(testsWidth),
725
729
  'Last Scanned'.padEnd(scannedWidth),
@@ -736,13 +740,16 @@ program
736
740
  const portStr = ports.length > 0
737
741
  ? ports.map(p => p.port).sort((a, b) => a - b).join(', ')
738
742
  : 'N/A';
739
- const pathDisplay = project.path.length > 40
740
- ? '...' + project.path.slice(-37)
743
+ const pathDisplay = project.path.length > 35
744
+ ? '...' + project.path.slice(-32)
741
745
  : project.path;
746
+ const branch = branchMap.get(project.id) || 'N/A';
747
+ const branchDisplay = branch.length > 15 ? branch.slice(0, 12) + '...' : branch;
742
748
  const row = [
743
749
  project.id.toString().padEnd(idWidth),
744
750
  project.name.padEnd(nameWidth),
745
751
  pathDisplay.padEnd(pathWidth),
752
+ branchDisplay.padEnd(branchWidth),
746
753
  portStr.padEnd(portsWidth),
747
754
  tests.length.toString().padEnd(testsWidth),
748
755
  lastScanned.padEnd(scannedWidth),
@@ -1860,11 +1867,378 @@ program
1860
1867
  process.exit(1);
1861
1868
  }
1862
1869
  });
1870
+ // Workspace commands
1871
+ const workspaceCmd = program
1872
+ .command('workspace')
1873
+ .alias('ws')
1874
+ .description('Manage workspaces');
1875
+ workspaceCmd
1876
+ .command('list')
1877
+ .description('List all workspaces')
1878
+ .action(async () => {
1879
+ try {
1880
+ await ensureAPIServerRunning(true);
1881
+ const response = await fetch('http://localhost:3001/api/workspaces');
1882
+ if (!response.ok)
1883
+ throw new Error('Failed to fetch workspaces');
1884
+ const workspaces = await response.json();
1885
+ if (workspaces.length === 0) {
1886
+ console.log('No workspaces tracked yet.');
1887
+ return;
1888
+ }
1889
+ console.log(`\nWorkspaces (${workspaces.length}):\n`);
1890
+ workspaces.forEach((ws) => {
1891
+ console.log(`${ws.id}. ${ws.name}`);
1892
+ console.log(` File: ${ws.workspace_file_path}`);
1893
+ if (ws.description)
1894
+ console.log(` Description: ${ws.description}`);
1895
+ console.log('');
1896
+ });
1897
+ }
1898
+ catch (error) {
1899
+ console.error('Error listing workspaces:', error instanceof Error ? error.message : error);
1900
+ process.exit(1);
1901
+ }
1902
+ });
1903
+ workspaceCmd
1904
+ .command('add')
1905
+ .description('Import workspace from .code-workspace file')
1906
+ .argument('<path>', 'Path to .code-workspace file')
1907
+ .action(async (filePath) => {
1908
+ try {
1909
+ await ensureAPIServerRunning(true);
1910
+ const resolvedPath = path.resolve(filePath);
1911
+ if (!fs.existsSync(resolvedPath)) {
1912
+ console.error(`Error: Workspace file not found: ${resolvedPath}`);
1913
+ process.exit(1);
1914
+ }
1915
+ const response = await fetch('http://localhost:3001/api/workspaces/import', {
1916
+ method: 'POST',
1917
+ headers: { 'Content-Type': 'application/json' },
1918
+ body: JSON.stringify({ workspace_file_path: resolvedPath }),
1919
+ });
1920
+ if (!response.ok) {
1921
+ const error = await response.json();
1922
+ throw new Error(error.error || 'Failed to import workspace');
1923
+ }
1924
+ const workspace = await response.json();
1925
+ console.log(`✓ Imported workspace: ${workspace.name}`);
1926
+ }
1927
+ catch (error) {
1928
+ console.error('Error importing workspace:', error instanceof Error ? error.message : error);
1929
+ process.exit(1);
1930
+ }
1931
+ });
1932
+ workspaceCmd
1933
+ .command('create')
1934
+ .description('Create a new workspace')
1935
+ .argument('<name>', 'Workspace name')
1936
+ .option('-o, --output <path>', 'Output directory for workspace file', process.cwd())
1937
+ .option('-p, --projects <paths>', 'Comma-separated project paths to include')
1938
+ .action(async (name, options) => {
1939
+ try {
1940
+ await ensureAPIServerRunning(true);
1941
+ const outputPath = options.output || process.cwd();
1942
+ const projectPaths = options.projects ? options.projects.split(',').map(p => p.trim()) : [];
1943
+ const response = await fetch('http://localhost:3001/api/workspaces/create', {
1944
+ method: 'POST',
1945
+ headers: { 'Content-Type': 'application/json' },
1946
+ body: JSON.stringify({
1947
+ name,
1948
+ output_path: outputPath,
1949
+ projects: projectPaths,
1950
+ }),
1951
+ });
1952
+ if (!response.ok) {
1953
+ const error = await response.json();
1954
+ throw new Error(error.error || 'Failed to create workspace');
1955
+ }
1956
+ const workspace = await response.json();
1957
+ console.log(`✓ Created workspace: ${workspace.name}`);
1958
+ console.log(` File: ${workspace.workspace_file_path}`);
1959
+ }
1960
+ catch (error) {
1961
+ console.error('Error creating workspace:', error instanceof Error ? error.message : error);
1962
+ process.exit(1);
1963
+ }
1964
+ });
1965
+ workspaceCmd
1966
+ .command('remove')
1967
+ .description('Remove a workspace')
1968
+ .argument('<id|name>', 'Workspace ID or name')
1969
+ .option('-f, --force', 'Skip confirmation')
1970
+ .action(async (identifier, options) => {
1971
+ try {
1972
+ await ensureAPIServerRunning(true);
1973
+ const response = await fetch('http://localhost:3001/api/workspaces');
1974
+ if (!response.ok)
1975
+ throw new Error('Failed to fetch workspaces');
1976
+ const workspaces = await response.json();
1977
+ const workspace = workspaces.find((w) => w.id.toString() === identifier || w.name === identifier);
1978
+ if (!workspace) {
1979
+ console.error(`Error: Workspace not found: ${identifier}`);
1980
+ process.exit(1);
1981
+ }
1982
+ if (!options.force) {
1983
+ const inquirer = (await Promise.resolve().then(() => __importStar(require('inquirer')))).default;
1984
+ const answer = await inquirer.prompt([{
1985
+ type: 'confirm',
1986
+ name: 'confirm',
1987
+ message: `Remove workspace "${workspace.name}"?`,
1988
+ default: false,
1989
+ }]);
1990
+ if (!answer.confirm) {
1991
+ console.log('Cancelled.');
1992
+ return;
1993
+ }
1994
+ }
1995
+ const deleteResponse = await fetch(`http://localhost:3001/api/workspaces/${workspace.id}`, {
1996
+ method: 'DELETE',
1997
+ });
1998
+ if (!deleteResponse.ok)
1999
+ throw new Error('Failed to remove workspace');
2000
+ console.log(`✓ Removed workspace: ${workspace.name}`);
2001
+ }
2002
+ catch (error) {
2003
+ console.error('Error removing workspace:', error instanceof Error ? error.message : error);
2004
+ process.exit(1);
2005
+ }
2006
+ });
2007
+ workspaceCmd
2008
+ .command('open')
2009
+ .description('Open workspace in editor')
2010
+ .argument('<id|name>', 'Workspace ID or name')
2011
+ .action(async (identifier) => {
2012
+ try {
2013
+ await ensureAPIServerRunning(true);
2014
+ const response = await fetch('http://localhost:3001/api/workspaces');
2015
+ if (!response.ok)
2016
+ throw new Error('Failed to fetch workspaces');
2017
+ const workspaces = await response.json();
2018
+ const workspace = workspaces.find((w) => w.id.toString() === identifier || w.name === identifier);
2019
+ if (!workspace) {
2020
+ console.error(`Error: Workspace not found: ${identifier}`);
2021
+ process.exit(1);
2022
+ }
2023
+ if (!fs.existsSync(workspace.workspace_file_path)) {
2024
+ console.error(`Error: Workspace file not found: ${workspace.workspace_file_path}`);
2025
+ process.exit(1);
2026
+ }
2027
+ const { spawn } = require('child_process');
2028
+ const corePath = path.join(__dirname, '..', '..', 'core', 'dist', 'settings');
2029
+ const localCorePath = path.join(__dirname, '..', '..', '..', 'core', 'dist', 'settings');
2030
+ let settings;
2031
+ try {
2032
+ settings = require(corePath);
2033
+ }
2034
+ catch {
2035
+ try {
2036
+ settings = require(localCorePath);
2037
+ }
2038
+ catch {
2039
+ console.error('Error: Could not load settings');
2040
+ process.exit(1);
2041
+ }
2042
+ }
2043
+ const editorSettings = settings.getEditorSettings();
2044
+ let command;
2045
+ if (editorSettings.type === 'custom' && editorSettings.customPath) {
2046
+ command = editorSettings.customPath;
2047
+ }
2048
+ else {
2049
+ command = editorSettings.type === 'cursor' ? 'cursor' : editorSettings.type === 'windsurf' ? 'windsurf' : 'code';
2050
+ }
2051
+ spawn(command, [workspace.workspace_file_path], {
2052
+ detached: true,
2053
+ stdio: 'ignore',
2054
+ }).unref();
2055
+ console.log(`✓ Opening workspace "${workspace.name}" in ${editorSettings.type || 'editor'}...`);
2056
+ }
2057
+ catch (error) {
2058
+ console.error('Error opening workspace:', error instanceof Error ? error.message : error);
2059
+ process.exit(1);
2060
+ }
2061
+ });
2062
+ // Backup commands
2063
+ program
2064
+ .command('backup')
2065
+ .description('Create a backup of PROJAX data')
2066
+ .argument('[path]', 'Output directory (default: current directory)')
2067
+ .action(async (outputPath) => {
2068
+ try {
2069
+ await ensureAPIServerRunning(true);
2070
+ const targetPath = outputPath ? path.resolve(outputPath) : process.cwd();
2071
+ const response = await fetch('http://localhost:3001/api/backup/create', {
2072
+ method: 'POST',
2073
+ headers: { 'Content-Type': 'application/json' },
2074
+ body: JSON.stringify({ output_path: targetPath }),
2075
+ });
2076
+ if (!response.ok) {
2077
+ const error = await response.json();
2078
+ throw new Error(error.error || 'Failed to create backup');
2079
+ }
2080
+ const result = await response.json();
2081
+ console.log(`✓ Backup created: ${result.backup_path}`);
2082
+ }
2083
+ catch (error) {
2084
+ console.error('Error creating backup:', error instanceof Error ? error.message : error);
2085
+ process.exit(1);
2086
+ }
2087
+ });
2088
+ program
2089
+ .command('restore')
2090
+ .description('Restore PROJAX data from backup')
2091
+ .argument('<file>', 'Path to .pbz backup file')
2092
+ .option('-f, --force', 'Skip confirmation')
2093
+ .action(async (backupPath, options) => {
2094
+ try {
2095
+ await ensureAPIServerRunning(true);
2096
+ const resolvedPath = path.resolve(backupPath);
2097
+ if (!fs.existsSync(resolvedPath)) {
2098
+ console.error(`Error: Backup file not found: ${resolvedPath}`);
2099
+ process.exit(1);
2100
+ }
2101
+ if (!options.force) {
2102
+ const inquirer = (await Promise.resolve().then(() => __importStar(require('inquirer')))).default;
2103
+ const answer = await inquirer.prompt([{
2104
+ type: 'confirm',
2105
+ name: 'confirm',
2106
+ message: 'This will overwrite your current PROJAX data. Continue?',
2107
+ default: false,
2108
+ }]);
2109
+ if (!answer.confirm) {
2110
+ console.log('Cancelled.');
2111
+ return;
2112
+ }
2113
+ }
2114
+ const response = await fetch('http://localhost:3001/api/backup/restore', {
2115
+ method: 'POST',
2116
+ headers: { 'Content-Type': 'application/json' },
2117
+ body: JSON.stringify({ backup_path: resolvedPath }),
2118
+ });
2119
+ if (!response.ok) {
2120
+ const error = await response.json();
2121
+ throw new Error(error.error || 'Failed to restore backup');
2122
+ }
2123
+ console.log('✓ Backup restored successfully');
2124
+ }
2125
+ catch (error) {
2126
+ console.error('Error restoring backup:', error instanceof Error ? error.message : error);
2127
+ process.exit(1);
2128
+ }
2129
+ });
2130
+ // MCP Server command
2131
+ program
2132
+ .command('mcp')
2133
+ .description('Start Projax MCP (Model Context Protocol) server for AI tools')
2134
+ .action(async () => {
2135
+ try {
2136
+ // Check if MCP server package is available
2137
+ const mcpServerPath = path.join(__dirname, '..', '..', 'mcp-server', 'dist', 'index.js');
2138
+ const isLocalDev = fs.existsSync(mcpServerPath);
2139
+ if (!isLocalDev) {
2140
+ // Try to find in node_modules (for global install)
2141
+ try {
2142
+ require.resolve('@projax/mcp-server');
2143
+ const { spawn } = require('child_process');
2144
+ const mcpServer = spawn('projax-mcp', [], {
2145
+ stdio: 'inherit',
2146
+ env: process.env,
2147
+ });
2148
+ mcpServer.on('exit', (code) => {
2149
+ process.exit(code || 0);
2150
+ });
2151
+ return;
2152
+ }
2153
+ catch (error) {
2154
+ console.error('Error: MCP server not found.');
2155
+ console.error('\nThe MCP server is not built or installed.');
2156
+ console.error('Please run: npm run build:mcp-server');
2157
+ process.exit(1);
2158
+ }
2159
+ }
2160
+ // Local development mode
2161
+ const { spawn } = require('child_process');
2162
+ const mcpServer = spawn('node', [mcpServerPath], {
2163
+ stdio: 'inherit',
2164
+ env: process.env,
2165
+ });
2166
+ mcpServer.on('exit', (code) => {
2167
+ process.exit(code || 0);
2168
+ });
2169
+ }
2170
+ catch (error) {
2171
+ console.error('Error starting MCP server:', error instanceof Error ? error.message : error);
2172
+ process.exit(1);
2173
+ }
2174
+ });
2175
+ // MCP Config command
2176
+ program
2177
+ .command('mcp-config')
2178
+ .description('Display MCP server configuration for Cursor or VS Code')
2179
+ .option('--cursor', 'Show Cursor-specific configuration')
2180
+ .option('--vscode', 'Show VS Code-specific configuration')
2181
+ .action(async (options) => {
2182
+ try {
2183
+ // Find prx command path
2184
+ let prxPath = 'prx';
2185
+ try {
2186
+ prxPath = (0, child_process_1.execSync)('which prx', { encoding: 'utf-8' }).trim();
2187
+ }
2188
+ catch {
2189
+ // If which fails, use 'prx' as default
2190
+ }
2191
+ const cursorConfig = {
2192
+ mcpServers: {
2193
+ projax: {
2194
+ command: prxPath,
2195
+ args: ['mcp'],
2196
+ },
2197
+ },
2198
+ };
2199
+ const vscodeConfig = {
2200
+ "mcp.servers": {
2201
+ projax: {
2202
+ command: prxPath,
2203
+ args: ['mcp'],
2204
+ },
2205
+ },
2206
+ };
2207
+ console.log('\n╔═══════════════════════════════════════════════════════╗');
2208
+ console.log('║ Projax MCP Server Configuration ║');
2209
+ console.log('╚═══════════════════════════════════════════════════════╝\n');
2210
+ if (options.vscode) {
2211
+ console.log('VS Code Configuration (settings.json):');
2212
+ console.log(JSON.stringify(vscodeConfig, null, 2));
2213
+ }
2214
+ else if (options.cursor) {
2215
+ console.log('Cursor Configuration (~/.cursor/mcp.json):');
2216
+ console.log(JSON.stringify(cursorConfig, null, 2));
2217
+ }
2218
+ else {
2219
+ // Show both
2220
+ console.log('Cursor Configuration (~/.cursor/mcp.json):');
2221
+ console.log(JSON.stringify(cursorConfig, null, 2));
2222
+ console.log('\nVS Code Configuration (settings.json):');
2223
+ console.log(JSON.stringify(vscodeConfig, null, 2));
2224
+ }
2225
+ console.log('\n📝 Instructions:');
2226
+ console.log('1. Copy the configuration above');
2227
+ console.log('2. For Cursor: Paste into ~/.cursor/mcp.json (or use Cursor Settings > MCP)');
2228
+ console.log('3. For VS Code: Paste into settings.json (or use MCP extension)');
2229
+ console.log('4. Restart your editor');
2230
+ console.log('\n💡 Test with: Ask your AI assistant about your current project context');
2231
+ }
2232
+ catch (error) {
2233
+ console.error('Error displaying configuration:', error instanceof Error ? error.message : error);
2234
+ process.exit(1);
2235
+ }
2236
+ });
1863
2237
  // Handle script execution before parsing
1864
2238
  // Check if first argument is not a known command
1865
2239
  (async () => {
1866
2240
  const args = process.argv.slice(2);
1867
- const knownCommands = ['prxi', 'i', 'add', 'list', 'scan', 'remove', 'rn', 'rename', 'cd', 'pwd', 'run', 'ps', 'stop', 'web', 'desktop', 'ui', 'scripts', 'scan-ports', 'api', 'docs', 'vscode-extension', 'extension', 'ext', 'desc', 'description', 'tags', 'open', 'files', 'urls', '--help', '-h', '--version', '-V'];
2241
+ const knownCommands = ['prxi', 'i', 'add', 'list', 'scan', 'remove', 'rn', 'rename', 'cd', 'pwd', 'run', 'ps', 'stop', 'web', 'desktop', 'ui', 'scripts', 'scan-ports', 'api', 'docs', 'vscode-extension', 'extension', 'ext', 'desc', 'description', 'tags', 'open', 'files', 'urls', 'workspace', 'ws', 'backup', 'restore', 'mcp', 'mcp-config', '--help', '-h', '--version', '-V'];
1868
2242
  // If we have at least 1 argument and first is not a known command, treat as project identifier
1869
2243
  if (args.length >= 1 && !knownCommands.includes(args[0])) {
1870
2244
  const projectIdentifier = args[0];
@@ -15,25 +15,15 @@ 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
- 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
- })();
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
+ };
35
25
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.extractPortsFromProject = extractPortsFromProject;
26
+ exports.extractPortsFromProject = void 0;
37
27
  const fs = __importStar(require("fs"));
38
28
  const path = __importStar(require("path"));
39
29
  /**
@@ -66,6 +56,7 @@ async function extractPortsFromProject(projectPath) {
66
56
  const uniquePorts = Array.from(new Map(ports.map(p => [`${p.port}-${p.script || ''}`, p])).values());
67
57
  return uniquePorts;
68
58
  }
59
+ exports.extractPortsFromProject = extractPortsFromProject;
69
60
  /**
70
61
  * Extract ports from package.json scripts
71
62
  */