@@ -98,13 +98,18 @@ impl vite_task_plan::PlanRequestParser for PlanRequestParser<'_> {
9898 match self . command_handler . handle_command ( command) . await ? {
9999 HandledCommand :: Synthesized ( synthetic) => Ok ( Some ( PlanRequest :: Synthetic ( synthetic) ) ) ,
100100 HandledCommand :: ViteTaskCommand ( cli_command) => match cli_command {
101- Command :: Cache { .. } => Ok ( Some ( PlanRequest :: Synthetic ( SyntheticPlanRequest {
102- program : Arc :: from ( OsStr :: new ( command. program . as_str ( ) ) ) ,
103- args : Arc :: clone ( & command. args ) ,
104- cache_config : UserCacheConfig :: disabled ( ) ,
105- envs : Arc :: clone ( & command. envs ) ,
106- } ) ) ) ,
107- Command :: Run ( run_command) => Ok ( Some ( run_command. into_plan_request ( & command. cwd ) ?) ) ,
101+ Command :: Cache { .. } => Ok ( Some ( PlanRequest :: Synthetic (
102+ command. to_synthetic_plan_request ( UserCacheConfig :: disabled ( ) ) ,
103+ ) ) ) ,
104+ Command :: Run ( run_command) => match run_command. into_plan_request ( & command. cwd ) {
105+ Ok ( plan_request) => Ok ( Some ( plan_request) ) ,
106+ Err ( crate :: cli:: CLITaskQueryError :: MissingTaskSpecifier ) => {
107+ Ok ( Some ( PlanRequest :: Synthetic (
108+ command. to_synthetic_plan_request ( UserCacheConfig :: disabled ( ) ) ,
109+ ) ) )
110+ }
111+ Err ( err) => Err ( err. into ( ) ) ,
112+ } ,
108113 } ,
109114 HandledCommand :: Verbatim => Ok ( None ) ,
110115 }
@@ -223,13 +228,19 @@ impl<'a> Session<'a> {
223228 Command :: Cache { ref subcmd } => self . handle_cache_command ( subcmd) ,
224229 Command :: Run ( run_command) => {
225230 let cwd = Arc :: clone ( & self . cwd ) ;
226- let plan = self . plan_from_cli ( cwd, run_command) . await ?;
227- let reporter = LabeledReporter :: new ( std:: io:: stdout ( ) , self . workspace_path ( ) ) ;
228- Ok ( self
229- . execute ( plan, Box :: new ( reporter) )
230- . await
231- . err ( )
232- . unwrap_or ( ExitStatus :: SUCCESS ) )
231+ match self . plan_from_cli ( cwd, run_command) . await {
232+ Ok ( plan) => {
233+ let reporter =
234+ LabeledReporter :: new ( std:: io:: stdout ( ) , self . workspace_path ( ) ) ;
235+ Ok ( self
236+ . execute ( plan, Box :: new ( reporter) )
237+ . await
238+ . err ( )
239+ . unwrap_or ( ExitStatus :: SUCCESS ) )
240+ }
241+ Err ( err) if err. is_missing_task_specifier ( ) => self . print_task_list ( ) . await ,
242+ Err ( err) => Err ( err. into ( ) ) ,
243+ }
233244 }
234245 }
235246 }
@@ -245,6 +256,63 @@ impl<'a> Session<'a> {
245256 }
246257 }
247258
259+ #[ expect(
260+ clippy:: future_not_send,
261+ reason = "session is single-threaded, futures do not need to be Send"
262+ ) ]
263+ async fn print_task_list ( & mut self ) -> anyhow:: Result < ExitStatus > {
264+ use std:: io:: Write ;
265+
266+ let cwd = Arc :: clone ( & self . cwd ) ;
267+ let task_graph = self . ensure_task_graph_loaded ( ) . await ?;
268+ let mut entries = task_graph. list_tasks ( ) ;
269+ entries. sort_unstable_by ( |a, b| {
270+ a. task_display
271+ . package_name
272+ . cmp ( & b. task_display . package_name )
273+ . then_with ( || a. task_display . task_name . cmp ( & b. task_display . task_name ) )
274+ } ) ;
275+
276+ // Find the most specific package containing the CWD (longest matching path)
277+ let current_package_path = entries
278+ . iter ( )
279+ . map ( |e| & e. task_display . package_path )
280+ . filter ( |p| cwd. as_path ( ) . starts_with ( p. as_path ( ) ) )
281+ . max_by_key ( |p| p. as_path ( ) . as_os_str ( ) . len ( ) ) ;
282+
283+ let ( current, others) : ( Vec < _ > , Vec < _ > ) = entries
284+ . iter ( )
285+ . partition ( |e| current_package_path == Some ( & e. task_display . package_path ) ) ;
286+
287+ let mut stdout = std:: io:: stdout ( ) . lock ( ) ;
288+
289+ if !current. is_empty ( ) {
290+ let package_name = & current[ 0 ] . task_display . package_name ;
291+ if package_name. is_empty ( ) {
292+ writeln ! ( stdout, "Tasks in the current package" ) ?;
293+ } else {
294+ writeln ! ( stdout, "Tasks in the current package ({package_name})" ) ?;
295+ }
296+ for entry in & current {
297+ writeln ! ( stdout, " {}" , entry. task_display. task_name) ?;
298+ writeln ! ( stdout, " {}" , entry. command) ?;
299+ }
300+ }
301+
302+ if !others. is_empty ( ) {
303+ if !current. is_empty ( ) {
304+ writeln ! ( stdout) ?;
305+ }
306+ writeln ! ( stdout, "Tasks in other packages" ) ?;
307+ for entry in & others {
308+ writeln ! ( stdout, " {}" , entry. task_display) ?;
309+ writeln ! ( stdout, " {}" , entry. command) ?;
310+ }
311+ }
312+
313+ Ok ( ExitStatus :: SUCCESS )
314+ }
315+
248316 /// Lazily initializes and returns the execution cache.
249317 /// The cache is only created when first accessed to avoid `SQLite` race conditions
250318 /// when multiple processes start simultaneously.
@@ -323,15 +391,21 @@ impl<'a> Session<'a> {
323391 cwd : Arc < AbsolutePath > ,
324392 command : RunCommand ,
325393 ) -> Result < ExecutionPlan , vite_task_plan:: Error > {
326- let plan_request = command. into_plan_request ( & cwd) . map_err ( |error| {
327- TaskPlanErrorKind :: ParsePlanRequestError {
328- error : error. into ( ) ,
329- program : Str :: from ( "vp" ) ,
330- args : Arc :: default ( ) ,
331- cwd : Arc :: clone ( & cwd) ,
394+ let plan_request = match command. into_plan_request ( & cwd) {
395+ Ok ( plan_request) => plan_request,
396+ Err ( crate :: cli:: CLITaskQueryError :: MissingTaskSpecifier ) => {
397+ return Err ( TaskPlanErrorKind :: MissingTaskSpecifier . with_empty_call_stack ( ) ) ;
398+ }
399+ Err ( error) => {
400+ return Err ( TaskPlanErrorKind :: ParsePlanRequestError {
401+ error : error. into ( ) ,
402+ program : Str :: from ( "vp" ) ,
403+ args : Arc :: default ( ) ,
404+ cwd : Arc :: clone ( & cwd) ,
405+ }
406+ . with_empty_call_stack ( ) ) ;
332407 }
333- . with_empty_call_stack ( )
334- } ) ?;
408+ } ;
335409 let plan = ExecutionPlan :: plan (
336410 plan_request,
337411 & self . workspace_path ,
0 commit comments