projax 0.1.29 → 1.0.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.
- package/dist/electron/main.js +237 -0
- package/dist/electron/preload.d.ts +34 -0
- package/dist/electron/preload.js +7 -0
- package/dist/electron/renderer/assets/index-CdMlFqhB.js +42 -0
- package/dist/electron/renderer/assets/index-DohAcUCg.css +1 -0
- package/dist/electron/renderer/index.html +2 -2
- package/dist/electron/script-runner.d.ts +25 -0
- package/dist/electron/script-runner.js +176 -1
- package/dist/index.js +21 -2
- package/dist/script-runner.d.ts +25 -0
- package/dist/script-runner.js +176 -1
- package/package.json +1 -1
|
@@ -36,7 +36,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.detectProjectType = detectProjectType;
|
|
37
37
|
exports.getProjectScripts = getProjectScripts;
|
|
38
38
|
exports.runScript = runScript;
|
|
39
|
+
exports.loadProcesses = loadProcesses;
|
|
40
|
+
exports.removeProcess = removeProcess;
|
|
39
41
|
exports.getProjectProcesses = getProjectProcesses;
|
|
42
|
+
exports.getRunningProcesses = getRunningProcesses;
|
|
43
|
+
exports.stopScript = stopScript;
|
|
44
|
+
exports.stopScriptByPort = stopScriptByPort;
|
|
45
|
+
exports.stopProjectProcesses = stopProjectProcesses;
|
|
40
46
|
exports.runScriptInBackground = runScriptInBackground;
|
|
41
47
|
const fs = __importStar(require("fs"));
|
|
42
48
|
const path = __importStar(require("path"));
|
|
@@ -525,6 +531,147 @@ function getProjectProcesses(projectPath) {
|
|
|
525
531
|
const processes = loadProcesses();
|
|
526
532
|
return processes.filter(p => p.projectPath === projectPath);
|
|
527
533
|
}
|
|
534
|
+
/**
|
|
535
|
+
* Get all running processes
|
|
536
|
+
*/
|
|
537
|
+
function getRunningProcesses() {
|
|
538
|
+
return loadProcesses();
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Extract URLs from text output
|
|
542
|
+
*/
|
|
543
|
+
function extractUrlsFromOutput(output) {
|
|
544
|
+
const urls = [];
|
|
545
|
+
const urlPatterns = [
|
|
546
|
+
/(?:Local|Network):\s*(https?:\/\/[^\s]+)/gi,
|
|
547
|
+
/(?:https?:\/\/localhost:\d+)/gi,
|
|
548
|
+
/(?:https?:\/\/127\.0\.0\.1:\d+)/gi,
|
|
549
|
+
/(?:https?:\/\/0\.0\.0\.0:\d+)/gi,
|
|
550
|
+
/(?:https?:\/\/[^\s:]+:\d+)/gi,
|
|
551
|
+
];
|
|
552
|
+
for (const pattern of urlPatterns) {
|
|
553
|
+
const matches = output.matchAll(pattern);
|
|
554
|
+
for (const match of matches) {
|
|
555
|
+
const url = match[0] || match[1];
|
|
556
|
+
if (url && !urls.includes(url)) {
|
|
557
|
+
urls.push(url);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return urls;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Update process with detected URLs
|
|
565
|
+
*/
|
|
566
|
+
function updateProcessUrls(pid, urls) {
|
|
567
|
+
const processes = loadProcesses();
|
|
568
|
+
const process = processes.find(p => p.pid === pid);
|
|
569
|
+
if (process) {
|
|
570
|
+
process.detectedUrls = urls;
|
|
571
|
+
saveProcesses(processes);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Stop a script by PID
|
|
576
|
+
*/
|
|
577
|
+
async function stopScript(pid) {
|
|
578
|
+
try {
|
|
579
|
+
const processes = loadProcesses();
|
|
580
|
+
const processInfo = processes.find(p => p.pid === pid);
|
|
581
|
+
if (!processInfo) {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
// Check if process is still running before trying to kill it
|
|
585
|
+
let processExists = false;
|
|
586
|
+
try {
|
|
587
|
+
if (os.platform() === 'win32') {
|
|
588
|
+
const { exec } = require('child_process');
|
|
589
|
+
const { promisify } = require('util');
|
|
590
|
+
const execAsync = promisify(exec);
|
|
591
|
+
await execAsync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`);
|
|
592
|
+
processExists = true;
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
const { exec } = require('child_process');
|
|
596
|
+
const { promisify } = require('util');
|
|
597
|
+
const execAsync = promisify(exec);
|
|
598
|
+
await execAsync(`ps -p ${pid} -o pid=`);
|
|
599
|
+
processExists = true;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
catch {
|
|
603
|
+
// Process doesn't exist anymore
|
|
604
|
+
processExists = false;
|
|
605
|
+
}
|
|
606
|
+
// Try to kill the process (cross-platform)
|
|
607
|
+
if (processExists) {
|
|
608
|
+
try {
|
|
609
|
+
if (os.platform() === 'win32') {
|
|
610
|
+
const { exec } = require('child_process');
|
|
611
|
+
const { promisify } = require('util');
|
|
612
|
+
const execAsync = promisify(exec);
|
|
613
|
+
await execAsync(`taskkill /F /PID ${pid}`);
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
const { exec } = require('child_process');
|
|
617
|
+
const { promisify } = require('util');
|
|
618
|
+
const execAsync = promisify(exec);
|
|
619
|
+
await execAsync(`kill -9 ${pid}`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
// Process may have already exited
|
|
624
|
+
console.error(`Error killing process ${pid}:`, error);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
// Remove from tracking regardless of whether kill succeeded
|
|
628
|
+
removeProcess(pid);
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
catch (error) {
|
|
632
|
+
console.error(`Error stopping script ${pid}:`, error);
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Stop a script by port (finds process using port and kills it)
|
|
638
|
+
*/
|
|
639
|
+
async function stopScriptByPort(port) {
|
|
640
|
+
try {
|
|
641
|
+
const processInfo = await (0, port_utils_1.getProcessOnPort)(port);
|
|
642
|
+
if (!processInfo) {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
// Check if this is a tracked process
|
|
646
|
+
const processes = loadProcesses();
|
|
647
|
+
const trackedProcess = processes.find(p => p.pid === processInfo.pid);
|
|
648
|
+
if (trackedProcess) {
|
|
649
|
+
// Use the tracked process removal
|
|
650
|
+
return await stopScript(processInfo.pid);
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
// Kill the process directly
|
|
654
|
+
const killed = await (0, port_utils_1.killProcessOnPort)(port);
|
|
655
|
+
return killed;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Stop all processes for a project
|
|
664
|
+
*/
|
|
665
|
+
async function stopProjectProcesses(projectPath) {
|
|
666
|
+
const processes = getProjectProcesses(projectPath);
|
|
667
|
+
let stopped = 0;
|
|
668
|
+
for (const process of processes) {
|
|
669
|
+
if (await stopScript(process.pid)) {
|
|
670
|
+
stopped++;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return stopped;
|
|
674
|
+
}
|
|
528
675
|
/**
|
|
529
676
|
* Execute a script in the background (minimal logging)
|
|
530
677
|
*/
|
|
@@ -626,25 +773,53 @@ function runScriptInBackground(projectPath, projectName, scriptName, args = [],
|
|
|
626
773
|
console.log(` Logs: ${logFile}`);
|
|
627
774
|
console.log(` Command: ${command} ${commandArgs.join(' ')}\n`);
|
|
628
775
|
// For background processes, we can't easily do reactive detection
|
|
629
|
-
// But we can check the log file after a short delay for port conflicts
|
|
776
|
+
// But we can check the log file after a short delay for port conflicts and URLs
|
|
630
777
|
setTimeout(async () => {
|
|
631
778
|
try {
|
|
632
779
|
// Wait a bit for process to start and potentially fail
|
|
633
780
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
634
781
|
if (fs.existsSync(logFile)) {
|
|
635
782
|
const logContent = fs.readFileSync(logFile, 'utf-8');
|
|
783
|
+
// Check for port conflicts
|
|
636
784
|
const port = (0, port_utils_1.extractPortFromError)(logContent);
|
|
637
785
|
if (port) {
|
|
638
786
|
console.error(`\n⚠️ Port conflict detected in background process: port ${port} is in use`);
|
|
639
787
|
console.error(` Check log file: ${logFile}`);
|
|
640
788
|
console.error(` Use: prx <project> <script> --force to auto-resolve port conflicts\n`);
|
|
641
789
|
}
|
|
790
|
+
// Extract URLs from output
|
|
791
|
+
const urls = extractUrlsFromOutput(logContent);
|
|
792
|
+
if (urls.length > 0) {
|
|
793
|
+
updateProcessUrls(child.pid, urls);
|
|
794
|
+
}
|
|
642
795
|
}
|
|
643
796
|
}
|
|
644
797
|
catch {
|
|
645
798
|
// Ignore errors checking log file
|
|
646
799
|
}
|
|
647
800
|
}, 3000);
|
|
801
|
+
// Also check for URLs from detected ports
|
|
802
|
+
setTimeout(async () => {
|
|
803
|
+
try {
|
|
804
|
+
const db = (0, core_1.getDatabaseManager)();
|
|
805
|
+
const project = db.getProjectByPath(projectPath);
|
|
806
|
+
if (project) {
|
|
807
|
+
const ports = db.getProjectPorts(project.id);
|
|
808
|
+
const urls = [];
|
|
809
|
+
for (const portInfo of ports) {
|
|
810
|
+
if (portInfo.script_name === scriptName) {
|
|
811
|
+
urls.push(`http://localhost:${portInfo.port}`);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (urls.length > 0) {
|
|
815
|
+
updateProcessUrls(child.pid, urls);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
catch {
|
|
820
|
+
// Ignore errors
|
|
821
|
+
}
|
|
822
|
+
}, 5000);
|
|
648
823
|
// Resolve immediately since process is running in background
|
|
649
824
|
resolve(0);
|
|
650
825
|
});
|
package/dist/index.js
CHANGED
|
@@ -42,11 +42,29 @@ const script_runner_1 = require("./script-runner");
|
|
|
42
42
|
const port_scanner_1 = require("./port-scanner");
|
|
43
43
|
// Read version from package.json
|
|
44
44
|
const packageJson = require('../package.json');
|
|
45
|
+
// ASCII logo for projax
|
|
46
|
+
function displayLogo() {
|
|
47
|
+
return `
|
|
48
|
+
╔═══════════════════════════════════════╗
|
|
49
|
+
║ ║
|
|
50
|
+
║ ██████╗ ██████╗ ██████╗ ██╗ ║
|
|
51
|
+
║ ██╔══██╗██╔══██╗██╔═══██╗ ██║ ║
|
|
52
|
+
║ ██████╔╝██████╔╝██║ ██║ ██║ ║
|
|
53
|
+
║ ██╔═══╝ ██╔══██╗██║ ██║██ ██║ ║
|
|
54
|
+
║ ██║ ██║ ██║╚██████╔╝╚█████╔╝ ║
|
|
55
|
+
║ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚════╝ ║
|
|
56
|
+
║ ║
|
|
57
|
+
║ Project Management CLI ║
|
|
58
|
+
║ ║
|
|
59
|
+
╚═══════════════════════════════════════╝
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
45
62
|
const program = new commander_1.Command();
|
|
46
63
|
program
|
|
47
64
|
.name('prx')
|
|
48
65
|
.description('Project management dashboard CLI')
|
|
49
|
-
.version(packageJson.version)
|
|
66
|
+
.version(packageJson.version)
|
|
67
|
+
.addHelpText('beforeAll', displayLogo());
|
|
50
68
|
// Add project command
|
|
51
69
|
program
|
|
52
70
|
.command('add')
|
|
@@ -832,7 +850,7 @@ program
|
|
|
832
850
|
// Check if first argument is not a known command
|
|
833
851
|
(async () => {
|
|
834
852
|
const args = process.argv.slice(2);
|
|
835
|
-
const knownCommands = ['add', 'list', 'scan', 'remove', 'rn', 'rename', 'cd', 'pwd', 'web', 'scripts', 'scan-ports', '--help', '-h', '--version', '-
|
|
853
|
+
const knownCommands = ['add', 'list', 'scan', 'remove', 'rn', 'rename', 'cd', 'pwd', 'web', 'scripts', 'scan-ports', '--help', '-h', '--version', '-V'];
|
|
836
854
|
// If we have at least 1 argument and first is not a known command, treat as project identifier
|
|
837
855
|
if (args.length >= 1 && !knownCommands.includes(args[0])) {
|
|
838
856
|
const projectIdentifier = args[0];
|
|
@@ -967,5 +985,6 @@ program
|
|
|
967
985
|
}
|
|
968
986
|
}
|
|
969
987
|
// If we get here, proceed with normal command parsing
|
|
988
|
+
// Don't show logo twice - it's already in addHelpText
|
|
970
989
|
program.parse();
|
|
971
990
|
})();
|
package/dist/script-runner.d.ts
CHANGED
|
@@ -29,11 +29,36 @@ export interface BackgroundProcess {
|
|
|
29
29
|
command: string;
|
|
30
30
|
startedAt: number;
|
|
31
31
|
logFile: string;
|
|
32
|
+
detectedUrls?: string[];
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Load running processes from disk
|
|
36
|
+
*/
|
|
37
|
+
export declare function loadProcesses(): BackgroundProcess[];
|
|
38
|
+
/**
|
|
39
|
+
* Remove a process from tracking by PID
|
|
40
|
+
*/
|
|
41
|
+
export declare function removeProcess(pid: number): void;
|
|
33
42
|
/**
|
|
34
43
|
* Get all running processes for a project
|
|
35
44
|
*/
|
|
36
45
|
export declare function getProjectProcesses(projectPath: string): BackgroundProcess[];
|
|
46
|
+
/**
|
|
47
|
+
* Get all running processes
|
|
48
|
+
*/
|
|
49
|
+
export declare function getRunningProcesses(): BackgroundProcess[];
|
|
50
|
+
/**
|
|
51
|
+
* Stop a script by PID
|
|
52
|
+
*/
|
|
53
|
+
export declare function stopScript(pid: number): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Stop a script by port (finds process using port and kills it)
|
|
56
|
+
*/
|
|
57
|
+
export declare function stopScriptByPort(port: number): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Stop all processes for a project
|
|
60
|
+
*/
|
|
61
|
+
export declare function stopProjectProcesses(projectPath: string): Promise<number>;
|
|
37
62
|
/**
|
|
38
63
|
* Execute a script in the background (minimal logging)
|
|
39
64
|
*/
|
package/dist/script-runner.js
CHANGED
|
@@ -36,7 +36,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.detectProjectType = detectProjectType;
|
|
37
37
|
exports.getProjectScripts = getProjectScripts;
|
|
38
38
|
exports.runScript = runScript;
|
|
39
|
+
exports.loadProcesses = loadProcesses;
|
|
40
|
+
exports.removeProcess = removeProcess;
|
|
39
41
|
exports.getProjectProcesses = getProjectProcesses;
|
|
42
|
+
exports.getRunningProcesses = getRunningProcesses;
|
|
43
|
+
exports.stopScript = stopScript;
|
|
44
|
+
exports.stopScriptByPort = stopScriptByPort;
|
|
45
|
+
exports.stopProjectProcesses = stopProjectProcesses;
|
|
40
46
|
exports.runScriptInBackground = runScriptInBackground;
|
|
41
47
|
const fs = __importStar(require("fs"));
|
|
42
48
|
const path = __importStar(require("path"));
|
|
@@ -525,6 +531,147 @@ function getProjectProcesses(projectPath) {
|
|
|
525
531
|
const processes = loadProcesses();
|
|
526
532
|
return processes.filter(p => p.projectPath === projectPath);
|
|
527
533
|
}
|
|
534
|
+
/**
|
|
535
|
+
* Get all running processes
|
|
536
|
+
*/
|
|
537
|
+
function getRunningProcesses() {
|
|
538
|
+
return loadProcesses();
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Extract URLs from text output
|
|
542
|
+
*/
|
|
543
|
+
function extractUrlsFromOutput(output) {
|
|
544
|
+
const urls = [];
|
|
545
|
+
const urlPatterns = [
|
|
546
|
+
/(?:Local|Network):\s*(https?:\/\/[^\s]+)/gi,
|
|
547
|
+
/(?:https?:\/\/localhost:\d+)/gi,
|
|
548
|
+
/(?:https?:\/\/127\.0\.0\.1:\d+)/gi,
|
|
549
|
+
/(?:https?:\/\/0\.0\.0\.0:\d+)/gi,
|
|
550
|
+
/(?:https?:\/\/[^\s:]+:\d+)/gi,
|
|
551
|
+
];
|
|
552
|
+
for (const pattern of urlPatterns) {
|
|
553
|
+
const matches = output.matchAll(pattern);
|
|
554
|
+
for (const match of matches) {
|
|
555
|
+
const url = match[0] || match[1];
|
|
556
|
+
if (url && !urls.includes(url)) {
|
|
557
|
+
urls.push(url);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return urls;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Update process with detected URLs
|
|
565
|
+
*/
|
|
566
|
+
function updateProcessUrls(pid, urls) {
|
|
567
|
+
const processes = loadProcesses();
|
|
568
|
+
const process = processes.find(p => p.pid === pid);
|
|
569
|
+
if (process) {
|
|
570
|
+
process.detectedUrls = urls;
|
|
571
|
+
saveProcesses(processes);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Stop a script by PID
|
|
576
|
+
*/
|
|
577
|
+
async function stopScript(pid) {
|
|
578
|
+
try {
|
|
579
|
+
const processes = loadProcesses();
|
|
580
|
+
const processInfo = processes.find(p => p.pid === pid);
|
|
581
|
+
if (!processInfo) {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
// Check if process is still running before trying to kill it
|
|
585
|
+
let processExists = false;
|
|
586
|
+
try {
|
|
587
|
+
if (os.platform() === 'win32') {
|
|
588
|
+
const { exec } = require('child_process');
|
|
589
|
+
const { promisify } = require('util');
|
|
590
|
+
const execAsync = promisify(exec);
|
|
591
|
+
await execAsync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`);
|
|
592
|
+
processExists = true;
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
const { exec } = require('child_process');
|
|
596
|
+
const { promisify } = require('util');
|
|
597
|
+
const execAsync = promisify(exec);
|
|
598
|
+
await execAsync(`ps -p ${pid} -o pid=`);
|
|
599
|
+
processExists = true;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
catch {
|
|
603
|
+
// Process doesn't exist anymore
|
|
604
|
+
processExists = false;
|
|
605
|
+
}
|
|
606
|
+
// Try to kill the process (cross-platform)
|
|
607
|
+
if (processExists) {
|
|
608
|
+
try {
|
|
609
|
+
if (os.platform() === 'win32') {
|
|
610
|
+
const { exec } = require('child_process');
|
|
611
|
+
const { promisify } = require('util');
|
|
612
|
+
const execAsync = promisify(exec);
|
|
613
|
+
await execAsync(`taskkill /F /PID ${pid}`);
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
const { exec } = require('child_process');
|
|
617
|
+
const { promisify } = require('util');
|
|
618
|
+
const execAsync = promisify(exec);
|
|
619
|
+
await execAsync(`kill -9 ${pid}`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
// Process may have already exited
|
|
624
|
+
console.error(`Error killing process ${pid}:`, error);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
// Remove from tracking regardless of whether kill succeeded
|
|
628
|
+
removeProcess(pid);
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
catch (error) {
|
|
632
|
+
console.error(`Error stopping script ${pid}:`, error);
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Stop a script by port (finds process using port and kills it)
|
|
638
|
+
*/
|
|
639
|
+
async function stopScriptByPort(port) {
|
|
640
|
+
try {
|
|
641
|
+
const processInfo = await (0, port_utils_1.getProcessOnPort)(port);
|
|
642
|
+
if (!processInfo) {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
// Check if this is a tracked process
|
|
646
|
+
const processes = loadProcesses();
|
|
647
|
+
const trackedProcess = processes.find(p => p.pid === processInfo.pid);
|
|
648
|
+
if (trackedProcess) {
|
|
649
|
+
// Use the tracked process removal
|
|
650
|
+
return await stopScript(processInfo.pid);
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
// Kill the process directly
|
|
654
|
+
const killed = await (0, port_utils_1.killProcessOnPort)(port);
|
|
655
|
+
return killed;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Stop all processes for a project
|
|
664
|
+
*/
|
|
665
|
+
async function stopProjectProcesses(projectPath) {
|
|
666
|
+
const processes = getProjectProcesses(projectPath);
|
|
667
|
+
let stopped = 0;
|
|
668
|
+
for (const process of processes) {
|
|
669
|
+
if (await stopScript(process.pid)) {
|
|
670
|
+
stopped++;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return stopped;
|
|
674
|
+
}
|
|
528
675
|
/**
|
|
529
676
|
* Execute a script in the background (minimal logging)
|
|
530
677
|
*/
|
|
@@ -626,25 +773,53 @@ function runScriptInBackground(projectPath, projectName, scriptName, args = [],
|
|
|
626
773
|
console.log(` Logs: ${logFile}`);
|
|
627
774
|
console.log(` Command: ${command} ${commandArgs.join(' ')}\n`);
|
|
628
775
|
// For background processes, we can't easily do reactive detection
|
|
629
|
-
// But we can check the log file after a short delay for port conflicts
|
|
776
|
+
// But we can check the log file after a short delay for port conflicts and URLs
|
|
630
777
|
setTimeout(async () => {
|
|
631
778
|
try {
|
|
632
779
|
// Wait a bit for process to start and potentially fail
|
|
633
780
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
634
781
|
if (fs.existsSync(logFile)) {
|
|
635
782
|
const logContent = fs.readFileSync(logFile, 'utf-8');
|
|
783
|
+
// Check for port conflicts
|
|
636
784
|
const port = (0, port_utils_1.extractPortFromError)(logContent);
|
|
637
785
|
if (port) {
|
|
638
786
|
console.error(`\n⚠️ Port conflict detected in background process: port ${port} is in use`);
|
|
639
787
|
console.error(` Check log file: ${logFile}`);
|
|
640
788
|
console.error(` Use: prx <project> <script> --force to auto-resolve port conflicts\n`);
|
|
641
789
|
}
|
|
790
|
+
// Extract URLs from output
|
|
791
|
+
const urls = extractUrlsFromOutput(logContent);
|
|
792
|
+
if (urls.length > 0) {
|
|
793
|
+
updateProcessUrls(child.pid, urls);
|
|
794
|
+
}
|
|
642
795
|
}
|
|
643
796
|
}
|
|
644
797
|
catch {
|
|
645
798
|
// Ignore errors checking log file
|
|
646
799
|
}
|
|
647
800
|
}, 3000);
|
|
801
|
+
// Also check for URLs from detected ports
|
|
802
|
+
setTimeout(async () => {
|
|
803
|
+
try {
|
|
804
|
+
const db = (0, core_1.getDatabaseManager)();
|
|
805
|
+
const project = db.getProjectByPath(projectPath);
|
|
806
|
+
if (project) {
|
|
807
|
+
const ports = db.getProjectPorts(project.id);
|
|
808
|
+
const urls = [];
|
|
809
|
+
for (const portInfo of ports) {
|
|
810
|
+
if (portInfo.script_name === scriptName) {
|
|
811
|
+
urls.push(`http://localhost:${portInfo.port}`);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (urls.length > 0) {
|
|
815
|
+
updateProcessUrls(child.pid, urls);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
catch {
|
|
820
|
+
// Ignore errors
|
|
821
|
+
}
|
|
822
|
+
}, 5000);
|
|
648
823
|
// Resolve immediately since process is running in background
|
|
649
824
|
resolve(0);
|
|
650
825
|
});
|