@@ -8,7 +8,7 @@ import { VersionPreference } from '../enums';
88import * as logger from '../logger' ;
99
1010/**
11- * Proxy lifecycle commands: start, stop, restart.
11+ * Proxy lifecycle commands: start, start with options, stop, restart.
1212 *
1313 * These commands control the Dev Proxy process.
1414 */
@@ -25,6 +25,12 @@ export function registerProxyCommands(
2525 vscode . commands . registerCommand ( Commands . start , ( ) => startDevProxy ( configuration , devProxyExe ) )
2626 ) ;
2727
28+ context . subscriptions . push (
29+ vscode . commands . registerCommand ( Commands . startWithOptions , ( ) =>
30+ startDevProxyWithOptions ( devProxyExe )
31+ )
32+ ) ;
33+
2834 context . subscriptions . push (
2935 vscode . commands . registerCommand ( Commands . stop , ( ) =>
3036 stopDevProxy ( apiClient , devProxyExe , configuration )
@@ -52,6 +58,306 @@ async function startDevProxy(
5258 terminalService . sendCommand ( terminal , command ) ;
5359}
5460
61+ async function startDevProxyWithOptions ( devProxyExe : string ) : Promise < void > {
62+ const args : string [ ] = [ ] ;
63+
64+ // Config file
65+ const configFiles = await vscode . workspace . findFiles (
66+ '**/devproxyrc.{json,jsonc}' ,
67+ '**/node_modules/**'
68+ ) ;
69+ const configItems : vscode . QuickPickItem [ ] = [
70+ { label : '$(remove) None' , description : 'Use default configuration' } ,
71+ ...configFiles . map ( f => ( {
72+ label : vscode . workspace . asRelativePath ( f ) ,
73+ description : f . fsPath ,
74+ } ) ) ,
75+ ] ;
76+
77+ const selectedConfig = await vscode . window . showQuickPick ( configItems , {
78+ title : 'Start with Options (1/13): Config file' ,
79+ placeHolder : 'Select a config file' ,
80+ } ) ;
81+ if ( selectedConfig === undefined ) {
82+ return ;
83+ }
84+ if ( selectedConfig . description && selectedConfig . description !== 'Use default configuration' ) {
85+ args . push ( '--config-file' , `"${ selectedConfig . description } "` ) ;
86+ }
87+
88+ // Port
89+ const port = await vscode . window . showInputBox ( {
90+ title : 'Start with Options (2/13): Port' ,
91+ prompt : 'Enter the proxy port number' ,
92+ value : '8000' ,
93+ validateInput : validatePortNumber ,
94+ } ) ;
95+ if ( port === undefined ) {
96+ return ;
97+ }
98+ if ( port && port !== '8000' ) {
99+ args . push ( '--port' , port ) ;
100+ }
101+
102+ // API port
103+ const apiPort = await vscode . window . showInputBox ( {
104+ title : 'Start with Options (3/13): API port' ,
105+ prompt : 'Enter the API port number' ,
106+ value : '8897' ,
107+ validateInput : validatePortNumber ,
108+ } ) ;
109+ if ( apiPort === undefined ) {
110+ return ;
111+ }
112+ if ( apiPort && apiPort !== '8897' ) {
113+ args . push ( '--api-port' , apiPort ) ;
114+ }
115+
116+ // IP address
117+ const ipAddress = await vscode . window . showInputBox ( {
118+ title : 'Start with Options (4/13): IP address' ,
119+ prompt : 'Enter the IP address to listen on' ,
120+ value : '127.0.0.1' ,
121+ validateInput : validateIpAddress ,
122+ } ) ;
123+ if ( ipAddress === undefined ) {
124+ return ;
125+ }
126+ if ( ipAddress && ipAddress !== '127.0.0.1' ) {
127+ args . push ( '--ip-address' , ipAddress ) ;
128+ }
129+
130+ // As system proxy
131+ const asSystemProxy = await vscode . window . showQuickPick (
132+ [
133+ { label : 'Yes' , description : 'Register as system proxy (default)' } ,
134+ { label : 'No' , description : 'Do not register as system proxy' } ,
135+ ] ,
136+ {
137+ title : 'Start with Options (5/13): As system proxy' ,
138+ placeHolder : 'Register Dev Proxy as a system proxy?' ,
139+ }
140+ ) ;
141+ if ( asSystemProxy === undefined ) {
142+ return ;
143+ }
144+ if ( asSystemProxy . label === 'No' ) {
145+ args . push ( '--as-system-proxy' , 'false' ) ;
146+ }
147+
148+ // Install cert
149+ const installCert = await vscode . window . showQuickPick (
150+ [
151+ { label : 'Yes' , description : 'Install certificate (default)' } ,
152+ { label : 'No' , description : 'Do not install certificate' } ,
153+ ] ,
154+ {
155+ title : 'Start with Options (6/13): Install certificate' ,
156+ placeHolder : 'Install the root certificate?' ,
157+ }
158+ ) ;
159+ if ( installCert === undefined ) {
160+ return ;
161+ }
162+ if ( installCert . label === 'No' ) {
163+ args . push ( '--install-cert' , 'false' ) ;
164+ }
165+
166+ // Log level
167+ const logLevel = await vscode . window . showQuickPick (
168+ [ 'trace' , 'debug' , 'information' , 'warning' , 'error' ] ,
169+ {
170+ title : 'Start with Options (7/13): Log level' ,
171+ placeHolder : 'Select a log level' ,
172+ }
173+ ) ;
174+ if ( logLevel === undefined ) {
175+ return ;
176+ }
177+ if ( logLevel !== 'information' ) {
178+ args . push ( '--log-level' , logLevel ) ;
179+ }
180+
181+ // Failure rate
182+ const failureRate = await vscode . window . showInputBox ( {
183+ title : 'Start with Options (8/13): Failure rate' ,
184+ prompt : 'Enter the failure rate (0-100)' ,
185+ value : '50' ,
186+ validateInput : validateFailureRate ,
187+ } ) ;
188+ if ( failureRate === undefined ) {
189+ return ;
190+ }
191+ if ( failureRate && failureRate !== '50' ) {
192+ args . push ( '--failure-rate' , failureRate ) ;
193+ }
194+
195+ // URLs to watch
196+ const urlsToWatch = await vscode . window . showInputBox ( {
197+ title : 'Start with Options (9/13): URLs to watch' ,
198+ prompt : 'Enter URLs to watch (space separated). Leave empty to use config file values.' ,
199+ placeHolder : 'https://api.example.com/* https://graph.microsoft.com/v1.0/*' ,
200+ value : '' ,
201+ } ) ;
202+ if ( urlsToWatch === undefined ) {
203+ return ;
204+ }
205+ if ( urlsToWatch . trim ( ) ) {
206+ args . push ( '--urls-to-watch' , urlsToWatch . trim ( ) ) ;
207+ }
208+
209+ // Record
210+ const record = await vscode . window . showQuickPick (
211+ [
212+ { label : 'No' , description : 'Do not record (default)' } ,
213+ { label : 'Yes' , description : 'Start recording immediately' } ,
214+ ] ,
215+ {
216+ title : 'Start with Options (10/13): Record' ,
217+ placeHolder : 'Start recording on launch?' ,
218+ }
219+ ) ;
220+ if ( record === undefined ) {
221+ return ;
222+ }
223+ if ( record . label === 'Yes' ) {
224+ args . push ( '--record' ) ;
225+ }
226+
227+ // No first run
228+ const noFirstRun = await vscode . window . showQuickPick (
229+ [
230+ { label : 'No' , description : 'Show first run experience (default)' } ,
231+ { label : 'Yes' , description : 'Skip first run experience' } ,
232+ ] ,
233+ {
234+ title : 'Start with Options (11/13): No first run' ,
235+ placeHolder : 'Skip the first run experience?' ,
236+ }
237+ ) ;
238+ if ( noFirstRun === undefined ) {
239+ return ;
240+ }
241+ if ( noFirstRun . label === 'Yes' ) {
242+ args . push ( '--no-first-run' ) ;
243+ }
244+
245+ // Timeout
246+ const timeout = await vscode . window . showInputBox ( {
247+ title : 'Start with Options (12/13): Timeout' ,
248+ prompt : 'Enter timeout in seconds. Leave empty for no timeout.' ,
249+ value : '' ,
250+ validateInput : validateTimeout ,
251+ } ) ;
252+ if ( timeout === undefined ) {
253+ return ;
254+ }
255+ if ( timeout . trim ( ) ) {
256+ args . push ( '--timeout' , timeout . trim ( ) ) ;
257+ }
258+
259+ // Watch PIDs
260+ const watchPids = await vscode . window . showInputBox ( {
261+ title : 'Start with Options (13/13): Watch PIDs and process names' ,
262+ prompt : 'Enter process IDs to watch (space separated). Leave empty to skip.' ,
263+ placeHolder : '1234 5678' ,
264+ value : '' ,
265+ validateInput : validateWatchPids ,
266+ } ) ;
267+ if ( watchPids === undefined ) {
268+ return ;
269+ }
270+ if ( watchPids . trim ( ) ) {
271+ args . push ( '--watch-pids' , watchPids . trim ( ) ) ;
272+ }
273+
274+ // Watch process names
275+ const watchProcessNames = await vscode . window . showInputBox ( {
276+ prompt : 'Enter process names to watch (space separated). Leave empty to skip.' ,
277+ placeHolder : 'msedge chrome' ,
278+ value : '' ,
279+ validateInput : validateProcessNames ,
280+ } ) ;
281+ if ( watchProcessNames === undefined ) {
282+ return ;
283+ }
284+ if ( watchProcessNames . trim ( ) ) {
285+ args . push ( '--watch-process-names' , watchProcessNames . trim ( ) ) ;
286+ }
287+
288+ const command = [ devProxyExe , ...args ] . join ( ' ' ) ;
289+ const terminalService = TerminalService . fromConfiguration ( ) ;
290+ const terminal = terminalService . getOrCreateTerminal ( ) ;
291+ terminalService . sendCommand ( terminal , command ) ;
292+ }
293+
294+ function validatePortNumber ( value : string ) : string | undefined {
295+ if ( ! value ) {
296+ return undefined ;
297+ }
298+ const num = Number ( value ) ;
299+ if ( ! Number . isInteger ( num ) || num < 1 || num > 65535 ) {
300+ return 'Port must be an integer between 1 and 65535' ;
301+ }
302+ return undefined ;
303+ }
304+
305+ function validateIpAddress ( value : string ) : string | undefined {
306+ if ( ! value ) {
307+ return undefined ;
308+ }
309+ if ( ! / ^ \d { 1 , 3 } \. \d { 1 , 3 } \. \d { 1 , 3 } \. \d { 1 , 3 } $ / . test ( value ) ) {
310+ return 'Enter a valid IPv4 address (e.g. 127.0.0.1)' ;
311+ }
312+ return undefined ;
313+ }
314+
315+ function validateFailureRate ( value : string ) : string | undefined {
316+ if ( ! value ) {
317+ return undefined ;
318+ }
319+ const num = Number ( value ) ;
320+ if ( ! Number . isInteger ( num ) || num < 0 || num > 100 ) {
321+ return 'Failure rate must be an integer between 0 and 100' ;
322+ }
323+ return undefined ;
324+ }
325+
326+ function validateTimeout ( value : string ) : string | undefined {
327+ if ( ! value ) {
328+ return undefined ;
329+ }
330+ const num = Number ( value ) ;
331+ if ( ! Number . isInteger ( num ) || num < 1 ) {
332+ return 'Timeout must be a positive integer' ;
333+ }
334+ return undefined ;
335+ }
336+
337+ function validateWatchPids ( value : string ) : string | undefined {
338+ if ( ! value ) {
339+ return undefined ;
340+ }
341+ const parts = value . trim ( ) . split ( / \s + / ) ;
342+ for ( const part of parts ) {
343+ const num = Number ( part ) ;
344+ if ( ! Number . isInteger ( num ) || num < 1 ) {
345+ return 'PIDs must be positive integers separated by spaces' ;
346+ }
347+ }
348+ return undefined ;
349+ }
350+
351+ function validateProcessNames ( value : string ) : string | undefined {
352+ if ( ! value ) {
353+ return undefined ;
354+ }
355+ if ( ! / ^ [ a - z A - Z 0 - 9 \s ] + $ / . test ( value ) ) {
356+ return 'Process names can only contain alphanumeric characters and spaces' ;
357+ }
358+ return undefined ;
359+ }
360+
55361async function stopDevProxy (
56362 apiClient : DevProxyApiClient ,
57363 devProxyExe : string ,
0 commit comments