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