@@ -271,6 +271,54 @@ def cli():
271271 note = get_startup_note ()
272272 click .echo (click .style (f"{ note } \n " , fg = "bright_black" , italic = True ))
273273
274+ def run_wizard ():
275+ click .echo ("\n 🧙 PySpector Scan Wizard\n " )
276+
277+ mode = click .prompt (
278+ "What do you want to scan?" ,
279+ type = click .Choice (["local" , "repo" ]),
280+ default = "local"
281+ )
282+
283+ scan_path = None
284+ repo_url = None
285+
286+ if mode == "local" :
287+ scan_path = Path (click .prompt ("Path to file or directory" , type = str ))
288+ else :
289+ repo_url = click .prompt ("GitHub/GitLab repository URL" , type = str )
290+
291+ ai_scan = click .confirm ("Enable AI / LLM vulnerability scanning?" , default = False )
292+
293+ severity_level = click .prompt (
294+ "Minimum severity level" ,
295+ type = click .Choice (["LOW" , "MEDIUM" , "HIGH" , "CRITICAL" ]),
296+ default = "LOW"
297+ )
298+
299+ report_format = click .prompt (
300+ "Report format" ,
301+ type = click .Choice (["console" , "json" , "sarif" , "html" ]),
302+ default = "console"
303+ )
304+
305+ output_file = None
306+ if report_format != "console" :
307+ output_file = Path (
308+ click .prompt ("Output file path" , type = str )
309+ )
310+
311+ click .echo ("\n [*] Wizard completed. Starting scan...\n " )
312+
313+ return {
314+ "scan_path" : scan_path ,
315+ "repo_url" : repo_url ,
316+ "ai_scan" : ai_scan ,
317+ "severity_level" : severity_level ,
318+ "report_format" : report_format ,
319+ "output_file" : output_file ,
320+ }
321+
274322
275323
276324@click .command (help = "Scan a directory, file, or remote Git repository for vulnerabilities." )
@@ -284,6 +332,7 @@ def cli():
284332@click .option ('--plugin' , 'plugins' , multiple = True , help = "Load and execute a plugin (can be specified multiple times)" )
285333@click .option ('--plugin-config' , 'plugin_config_file' , type = click .Path (exists = True , path_type = Path ), help = "Path to plugin configuration JSON file" )
286334@click .option ('--list-plugins' , 'list_plugins' , is_flag = True , help = "List available plugins and exit" )
335+ @click .option ('--wizard' , is_flag = True , help = "Interactive guided scan for first-time users" )
287336def run_scan_command (
288337 path : Optional [Path ],
289338 repo_url : Optional [str ],
@@ -294,10 +343,47 @@ def run_scan_command(
294343 ai_scan : bool ,
295344 plugins : tuple ,
296345 plugin_config_file : Optional [Path ],
297- list_plugins : bool
346+ list_plugins : bool ,
347+ wizard : bool
298348):
299349 """The main scan command with plugin support."""
300-
350+ # --- Wizard Mode ---
351+ if wizard :
352+ params = run_wizard ()
353+
354+ # Repo scan
355+ if params ["repo_url" ]:
356+ with tempfile .TemporaryDirectory () as temp_dir :
357+ click .echo (f"[*] Cloning '{ params ['repo_url' ]} ' into temporary directory..." )
358+ subprocess .run (
359+ ['git' , 'clone' , '--depth' , '1' , params ["repo_url" ], temp_dir ],
360+ check = True ,
361+ capture_output = True ,
362+ text = True
363+ )
364+ _execute_scan (
365+ Path (temp_dir ),
366+ config_path ,
367+ params ["output_file" ],
368+ params ["report_format" ],
369+ params ["severity_level" ],
370+ params ["ai_scan" ],
371+ plugins = (),
372+ plugin_config = {}
373+ )
374+ else :
375+ _execute_scan (
376+ params ["scan_path" ],
377+ config_path ,
378+ params ["output_file" ],
379+ params ["report_format" ],
380+ params ["severity_level" ],
381+ params ["ai_scan" ],
382+ plugins = (),
383+ plugin_config = {}
384+ )
385+ return
386+
301387 # Handle --list-plugins
302388 if list_plugins :
303389 plugin_manager = get_plugin_manager ()
0 commit comments