projax 1.3.8 → 1.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,26 +48,93 @@ prx remove my-project
48
48
  prx remove my-project --force # Skip confirmation
49
49
  ```
50
50
 
51
+ ### `prx pwd [project]`
52
+
53
+ Get the path to a project directory (outputs just the path).
54
+
55
+ ```bash
56
+ cd $(prx pwd 1) # Change to project with ID 1
57
+ cd $(prx pwd my-project) # Change to project named "my-project"
58
+ prx pwd # Interactive selection
59
+ ```
60
+
51
61
  ### `prx cd [project]`
52
62
 
53
- Get the path to a project directory for quick navigation. Use with command substitution to change directories.
63
+ Change to a project directory. Outputs a shell command to change directory.
54
64
 
55
65
  ```bash
56
- cd $(prx cd 1) # Change to project with ID 1
57
- cd $(prx cd my-project) # Change to project named "my-project"
58
- prx cd # Interactive selection
66
+ eval "$(prx cd 1)" # Change to project with ID 1
67
+ eval "$(prx cd my-project)" # Change to project named "my-project"
68
+ prx cd # Interactive selection
59
69
  ```
60
70
 
61
71
  **Tip:** For even easier navigation, add this to your shell config (`~/.zshrc` or `~/.bashrc`):
62
72
 
63
73
  ```bash
64
74
  prxcd() {
65
- cd $(prx cd "$@")
75
+ eval "$(prx cd $@)"
66
76
  }
67
77
  ```
68
78
 
69
79
  Then you can simply use: `prxcd 1` or `prxcd my-project`
70
80
 
81
+ ### `prx run <project> <script>`
82
+
83
+ Run a script from a project.
84
+
85
+ **Options:**
86
+ - `-b, --background`: Run script in background mode
87
+ - `-f, --force`: Auto-resolve port conflicts
88
+
89
+ ```bash
90
+ # Run in foreground
91
+ prx run 1 dev
92
+ prx run projax build
93
+
94
+ # Run in background
95
+ prx run 1 dev --background
96
+ prx run projax dev -b
97
+
98
+ # With force flag
99
+ prx run 1 dev -f -b
100
+ ```
101
+
102
+ ### `prx ps`
103
+
104
+ List all running background processes.
105
+
106
+ ```bash
107
+ prx ps
108
+ ```
109
+
110
+ ### `prx stop <pid>`
111
+
112
+ Stop a running background process by PID.
113
+
114
+ ```bash
115
+ prx stop 12345
116
+ ```
117
+
118
+ ### `prx prxi` / `prx i`
119
+
120
+ Launch the interactive terminal UI.
121
+
122
+ ```bash
123
+ prx i # Short alias
124
+ prx prxi # Full command
125
+ ```
126
+
127
+ **Keyboard shortcuts:**
128
+ - `↑/k` - Navigate up
129
+ - `↓/j` - Navigate down
130
+ - `Tab/←/→` - Switch panels
131
+ - `s` - Scan project
132
+ - `p` - Scan ports
133
+ - `r` - Show scripts
134
+ - `x` - Stop all project scripts
135
+ - `?` - Help
136
+ - `q/Esc` - Quit
137
+
71
138
  ### `prx <project> <script> [args...]`
72
139
 
73
140
  Run a script from a project's configuration file. Supports multiple project types:
@@ -65,7 +65,7 @@ else {
65
65
  width: 1200,
66
66
  height: 800,
67
67
  frame: false,
68
- titleBarStyle: process.platform === 'darwin' ? 'hidden' : 'hidden',
68
+ titleBarStyle: 'hidden',
69
69
  webPreferences: {
70
70
  preload: path.join(__dirname, 'preload.js'),
71
71
  nodeIntegration: false,
@@ -95,6 +95,18 @@ else {
95
95
  electron_1.app.quit();
96
96
  }
97
97
  }
98
+ // Handle external links securely
99
+ mainWindow.webContents.setWindowOpenHandler(({ url }) => {
100
+ // Only allow http/https links to be opened externally for security
101
+ const isExternal = url.startsWith('http:') || url.startsWith('https:');
102
+ if (isExternal) {
103
+ electron_1.shell.openExternal(url);
104
+ // Deny the default action of opening a new Electron window/tab
105
+ return { action: 'deny' };
106
+ }
107
+ // For internal or non-web links, allow the default behavior
108
+ return { action: 'allow' };
109
+ });
98
110
  mainWindow.on('closed', () => {
99
111
  mainWindow = null;
100
112
  });
@@ -382,8 +394,8 @@ electron_1.ipcMain.handle('get-running-processes', async () => {
382
394
  else {
383
395
  scriptRunnerPath = localScriptRunnerPath;
384
396
  }
385
- const { getRunningProcesses } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
386
- return getRunningProcesses();
397
+ const { getRunningProcessesClean } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
398
+ return await getRunningProcessesClean();
387
399
  });
388
400
  // Stop script by PID
389
401
  electron_1.ipcMain.handle('stop-script', async (_, pid) => {
@@ -430,7 +442,8 @@ electron_1.ipcMain.handle('open-url', async (_, url) => {
430
442
  else {
431
443
  corePath = localCorePath;
432
444
  }
433
- const { getBrowserSettings } = await Promise.resolve(`${corePath}`).then(s => __importStar(require(s)));
445
+ const coreModule = require(corePath);
446
+ const { getBrowserSettings } = coreModule;
434
447
  const browserSettings = getBrowserSettings();
435
448
  let command;
436
449
  let args = [url];
@@ -520,7 +533,8 @@ electron_1.ipcMain.handle('open-in-editor', async (_, projectPath) => {
520
533
  else {
521
534
  corePath = localCorePath;
522
535
  }
523
- const { getEditorSettings } = await Promise.resolve(`${corePath}`).then(s => __importStar(require(s)));
536
+ const coreModule = require(corePath);
537
+ const { getEditorSettings } = coreModule;
524
538
  const editorSettings = getEditorSettings();
525
539
  let command;
526
540
  let args = [projectPath];
@@ -606,3 +620,19 @@ electron_1.ipcMain.handle('save-settings', async (_, settings) => {
606
620
  throw error;
607
621
  }
608
622
  });
623
+ // Open external URL securely (for anchor tags and manual calls)
624
+ electron_1.ipcMain.on('open-external-url', (event, url) => {
625
+ try {
626
+ // SECURITY: Ensure only http/https links to prevent arbitrary file execution
627
+ const parsedUrl = new URL(url);
628
+ if (['http:', 'https:'].includes(parsedUrl.protocol)) {
629
+ electron_1.shell.openExternal(url);
630
+ }
631
+ else {
632
+ console.warn(`Blocked attempt to open non-http/https URL: ${url}`);
633
+ }
634
+ }
635
+ catch (error) {
636
+ console.error('Error opening external URL:', error);
637
+ }
638
+ });
@@ -18,6 +18,11 @@ export interface ProjectPort {
18
18
  last_detected: number;
19
19
  created_at: number;
20
20
  }
21
+ declare global {
22
+ interface Window {
23
+ electronAPI: ElectronAPI;
24
+ }
25
+ }
21
26
  export interface ElectronAPI {
22
27
  getProjects: () => Promise<Project[]>;
23
28
  addProject: (path: string) => Promise<Project>;
@@ -83,4 +88,5 @@ export interface ElectronAPI {
83
88
  customPath?: string;
84
89
  };
85
90
  }) => Promise<void>;
91
+ openExternal: (url: string) => void;
86
92
  }
@@ -24,6 +24,7 @@ electron_1.contextBridge.exposeInMainWorld('electronAPI', {
24
24
  stopProject: (projectPath) => electron_1.ipcRenderer.invoke('stop-project', projectPath),
25
25
  openUrl: (url) => electron_1.ipcRenderer.invoke('open-url', url),
26
26
  openInEditor: (projectPath) => electron_1.ipcRenderer.invoke('open-in-editor', projectPath),
27
+ openExternal: (url) => electron_1.ipcRenderer.send('open-external-url', url),
27
28
  getSettings: () => electron_1.ipcRenderer.invoke('get-settings'),
28
29
  saveSettings: (settings) => electron_1.ipcRenderer.invoke('save-settings', settings),
29
30
  });