Repository: denoland/deno
Pull request: feat(flags): improve help output and make `deno run` list tasks

- rewrite flag help
- use gray for indentation
- reorganize permission flags and split them up
- make help subcommand act like help flag
- `deno run` outputs list of tasks
- Fixes #25120

error handling for `deno run` in case of no config file being found needs to be improved

Changed files:
filename: Cargo.lock
patch: @@ -152,15 +152,16 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.13"
+version = "0.6.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
+checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
 dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
  "anstyle-wincon",
  "colorchoice",
+ "is_terminal_polyfill",
  "utf8parse",
 ]
 
@@ -1146,6 +1147,7 @@ dependencies = [
 name = "deno"
 version = "1.46.0-rc.3"
 dependencies = [
+ "anstream",
  "async-trait",
  "base32",
  "base64 0.21.7",
@@ -3871,6 +3873,12 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
 [[package]]
 name = "itertools"
 version = "0.10.5"

filename: cli/Cargo.toml
patch: @@ -83,6 +83,7 @@ libsui = "0.3.0"
 napi_sym.workspace = true
 node_resolver.workspace = true
 
+anstream = "0.6.14"
 async-trait.workspace = true
 base32.workspace = true
 base64.workspace = true

filename: cli/args/flags.rs
patch: @@ -9,6 +9,7 @@ use clap::ArgMatches;
 use clap::ColorChoice;
 use clap::Command;
 use clap::ValueHint;
+use color_print::cstr;
 use deno_config::glob::FilePatterns;
 use deno_config::glob::PathOrPatternSet;
 use deno_core::anyhow::bail;
@@ -376,6 +377,7 @@ pub struct WatchFlagsWithPaths {
 pub struct TaskFlags {
   pub cwd: Option<String>,
   pub task: Option<String>,
+  pub is_run: bool,
 }
 
 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
@@ -1107,7 +1109,7 @@ impl Flags {
   }
 }
 
-static ENV_VARIABLES_HELP: &str = color_print::cstr!(
+static ENV_VARIABLES_HELP: &str = cstr!(
   r#"<y>Environment variables:</>
   <g>DENO_AUTH_TOKENS</>      A semi-colon separated list of bearer tokens and hostnames
                         to use when fetching remote modules from private repositories
@@ -1132,7 +1134,7 @@ static ENV_VARIABLES_HELP: &str = color_print::cstr!(
   <g>NPM_CONFIG_REGISTRY</>   URL to use for the npm registry."#
 );
 
-static DENO_HELP: &str = color_print::cstr!(
+static DENO_HELP: &str = cstr!(
   "Deno: <g>A modern JavaScript and TypeScript runtime</>
 
 <p(245)>Usage:</> <g>{usage}</>
@@ -1247,6 +1249,19 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
       app
     };
 
+    help_parse(&mut flags, subcommand);
+    return Ok(flags);
+  } else if let Some(help_subcommand_matches) =
+    matches.subcommand_matches("help")
+  {
+    app.build();
+    let subcommand =
+      if let Some(sub) = help_subcommand_matches.subcommand_name() {
+        app.find_subcommand(sub).unwrap().clone()
+      } else {
+        app
+      };
+
     help_parse(&mut flags, subcommand);
     return Ok(flags);
   }
@@ -1283,15 +1298,6 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
       "upgrade" => upgrade_parse(&mut flags, &mut m),
       "vendor" => vendor_parse(&mut flags, &mut m),
       "publish" => publish_parse(&mut flags, &mut m),
-      "help" => {
-        let subcommand = if let Some((sub, _)) = matches.remove_subcommand() {
-          app.find_subcommand(sub).unwrap().clone()
-        } else {
-          app
-        };
-
-        help_parse(&mut flags, subcommand)
-      }
       _ => unreachable!(),
     }
   } else {
@@ -1373,12 +1379,7 @@ fn help_parse(flags: &mut Flags, mut subcommand: Command) {
   for (mut i, (arg, heading)) in args.into_iter().enumerate() {
     if let Some(heading) = heading {
       let heading_i = HEADING_ORDER.iter().position(|h| h == &heading).unwrap();
-      i += (if heading == UNSTABLE_HEADING {
-        // ensures the unstable section is always last
-        50
-      } else {
-        heading_i
-      }) * 100;
+      i += heading_i * 100;
     }
 
     subcommand = subcommand.mut_arg(arg, |arg| arg.display_order(i));
@@ -1546,11 +1547,10 @@ fn command(
 
 fn help_subcommand(app: &Command) -> Command {
   command("help", None, UnstableArgsConfig::None)
-    .hide(true)
+    .disable_version_flag(true)
     .disable_help_subcommand(true)
     .subcommands(app.get_subcommands().map(|command| {
       Command::new(command.get_name().to_owned())
-        .hide(true)
         .disable_help_flag(true)
         .disable_version_flag(true)
     }))
@@ -1582,13 +1582,15 @@ You can add multiple dependencies at once:
 fn remove_subcommand() -> Command {
   command(
     "remove",
-    "Remove dependencies from the configuration file.
+    cstr!(
+      "Remove dependencies from the configuration file.
 
   deno remove @std/path
 
 You can remove multiple dependencies at once:
   <p(245)>deno remove @std/path @std/assert</>
-",
+"
+    ),
     UnstableArgsConfig::None,
   )
   .defer(|cmd| {
@@ -1637,7 +1639,9 @@ glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}:
         Arg::new("filter")
           .long("filter")
           .allow_hyphen_values(true)
-          .help("Run benchmarks with this string or pattern in the bench name"),
+          .help(
+          "Run benchmarks with this string or regexp pattern in the bench name",
+        ),
       )
       .arg(
         Arg::new("files")
@@ -1743,7 +1747,7 @@ Unless --reload is specified, this command will not re-download already cached d
           // past alias for --all
           Arg::new("remote")
             .long("remote")
-            .help("Type-check all modules, including remote")
+            .help("Type-check all modules, including remote ones")
             .action(ArgAction::SetTrue)
             .conflicts_with("no-remote")
             .hide(true)
@@ -1790,11 +1794,11 @@ supported in canary.
         Arg::new("include")
           .long("include")
           .help(
-            "Includes an additional module in the compiled executable's module
-  graph. Use this flag if a dynamically imported module or a web worker main
-  module fails to load in the executable. This flag can be passed multiple
-  times, to include multiple additional modules.",
-          )
+            cstr!("Includes an additional module in the compiled executable's module graph.
+  <p(245)>Use this flag if a dynamically imported module or a web worker main module
+  fails to load in the executable. This flag can be passed multiple times,
+  to include multiple additional modules.</>",
+          ))
           .action(ArgAction::Append)
           .value_hint(ValueHint::FilePath)
           .help_heading(COMPILE_HEADING),
@@ -1804,7 +1808,7 @@ supported in canary.
           .long("output")
           .short('o')
           .value_parser(value_parser!(String))
-          .help("Output file (defaults to $PWD/<inferred-name>)")
+          .help(cstr!("Output file <p(245)>(defaults to $PWD/<<inferred-name>>)</>"))
           .value_hint(ValueHint::FilePath)
           .help_heading(COMPILE_HEADING),
       )
@@ -1936,10 +1940,9 @@ Generate html reports from lcov:
           .long("output")
           .value_parser(value_parser!(String))
           .help(
-            "Exports the coverage report in lcov format to the given file.
-  Filename should be passed along with '=' For example '--output=foo.lcov'
-  If no --output arg is specified then the report is written to stdout.",
-          )
+            cstr!("Exports the coverage report in lcov format to the given file.
+  <p(245)>If no --output arg is specified then the report is written to stdout.</>",
+          ))
           .require_equals(true)
           .value_hint(ValueHint::FilePath),
       )
@@ -1952,7 +1955,7 @@ Generate html reports from lcov:
       .arg(
         Arg::new("detailed")
           .long("detailed")
-          .help("Output coverage report in detailed format in the terminal.")
+          .help("Output coverage report in detailed format in the terminal")
           .action(ArgAction::SetTrue),
       )
       .arg(
@@ -2019,7 +2022,7 @@ Show documentation for runtime built-ins:
         .arg(
           Arg::new("name")
             .long("name")
-            .help("The name that will be displayed in the docs")
+            .help("The name that will be used in the docs (ie for breadcrumbs)")
             .action(ArgAction::Set)
             .require_equals(true).help_heading(DOC_HEADING)
         )
@@ -2042,14 +2045,14 @@ Show documentation for runtime built-ins:
         .arg(
           Arg::new("strip-trailing-html")
             .long("strip-trailing-html")
-            .help("Remove trailing .html from various links. Will still generate files with a .html extension.")
+            .help("Remove trailing .html from various links. Will still generate files with a .html extension")
             .requires("html")
             .action(ArgAction::SetTrue).help_heading(DOC_HEADING)
         )
         .arg(
           Arg::new("default-symbol-map")
             .long("default-symbol-map")
-            .help("Uses the provided mapping of default name to wanted name for usage blocks.")
+            .help("Uses the provided mapping of default name to wanted name for usage blocks")
             .requires("html")
             .action(ArgAction::Set)
             .require_equals(true).help_heading(DOC_HEADING)
@@ -2135,7 +2138,7 @@ This command has implicit access to all permissions (--allow-all).",
           Arg::new("code_arg")
             .num_args(1..)
             .action(ArgAction::Append)
-            .help("Code arg")
+            .help("Code to evaluate")
             .value_name("CODE_ARG")
             .required_unless_present("help"),
         )
@@ -2167,7 +2170,7 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
       .arg(config_arg())
       .arg(no_config_arg())
       .arg(
-        Arg::new("check")
+         Arg::new("check")
           .long("check")
           .help("Check if the source files are formatted")
           .num_args(0)
@@ -2214,23 +2217,23 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
           .default_missing_value("true")
           .require_equals(true)
           .help(
-            "Use tabs instead of spaces for indentation. Defaults to false.",
+          cstr!(  "Use tabs instead of spaces for indentation <p(245)>[default: false]</>"),
           )
           .help_heading(FMT_HEADING),
       )
       .arg(
         Arg::new("line-width")
           .long("line-width")
           .alias("options-line-width")
-          .help("Define maximum line width. Defaults to 80.")
+          .help(cstr!("Define maximum line width <p(245)>[default: 80]</>"))
           .value_parser(value_parser!(NonZeroU32))
           .help_heading(FMT_HEADING),
       )
       .arg(
         Arg::new("indent-width")
           .long("indent-width")
           .alias("options-indent-width")
-          .help("Define indentation width. Defaults to 2.")
+          .help(cstr!("Define indentation width <p(245)>[default: 2]</>"))
           .value_parser(value_parser!(NonZeroU8))
           .help_heading(FMT_HEADING),
       )
@@ -2242,15 +2245,15 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
           .value_parser(value_parser!(bool))
           .default_missing_value("true")
           .require_equals(true)
-          .help("Use single quotes. Defaults to false.")
+          .help(cstr!("Use single quotes <p(245)>[default: false]</>"))
           .help_heading(FMT_HEADING),
       )
       .arg(
         Arg::new("prose-wrap")
           .long("prose-wrap")
           .alias("options-prose-wrap")
           .value_parser(["always", "never", "preserve"])
-          .help("Define how prose should be wrapped. Defaults to always.")
+          .help(cstr!("Define how prose should be wrapped <p(245)>[default: always]</>"))
           .help_heading(FMT_HEADING),
       )
       .arg(
@@ -2262,36 +2265,38 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
           .default_missing_value("true")
           .require_equals(true)
           .help(
-            "Don't use semicolons except where necessary. Defaults to false.",
+           cstr!("Don't use semicolons except where necessary <p(245)>[default: false]</>"),
           )
           .help_heading(FMT_HEADING),
       )
       .arg(
         Arg::new("unstable-css")
           .long("unstable-css")
-          .help("Enable formatting CSS, SCSS, Sass and Less files.")
+          .help("Enable formatting CSS, SCSS, Sass and Less files")
           .value_parser(FalseyValueParser::new())
           .action(ArgAction::SetTrue)
           .help_heading(FMT_HEADING),
       )
       .arg(
         Arg::new("unstable-html")
           .long("unstable-html")
-          .help("Enable formatting HTML files.")
+          .help("Enable formatting HTML files")
           .value_parser(FalseyValueParser::new())
-          .action(ArgAction::SetTrue),
+          .action(ArgAction::SetTrue)
+          .help_heading(FMT_HEADING),
       )
       .arg(
         Arg::new("unstable-component")
           .long("unstable-component")
-          .help("Enable formatting Svelte, Vue, Astro and Angular files.")
+          .help("Enable formatting Svelte, Vue, Astro and Angular files")
           .value_parser(FalseyValueParser::new())
-          .action(ArgAction::SetTrue),
+          .action(ArgAction::SetTrue)
+          .help_heading(FMT_HEADING),
       )
       .arg(
         Arg::new("unstable-yaml")
           .long("unstable-yaml")
-          .help("Enable formatting YAML files.")
+          .help("Enable formatting YAML files")
           .value_parser(FalseyValueParser::new())
           .action(ArgAction::SetTrue)
           .help_heading(FMT_HEADING),
@@ -2304,7 +2309,12 @@ fn init_subcommand() -> Command {
     |cmd| {
       cmd
         .arg(Arg::new("dir").value_hint(ValueHint::DirPath))
-        .arg(Arg::new("lib").long("lib").action(ArgAction::SetTrue))
+        .arg(
+          Arg::new("lib")
+            .long("lib")
+            .help("Generate an example library project")
+            .action(ArgAction::SetTrue),
+        )
         .arg(
           Arg::new("serve")
             .long("serve")
@@ -2707,18 +2717,18 @@ fn repl_subcommand() -> Command {
           .num_args(1..)
           .use_value_delimiter(true)
           .require_equals(true)
-          .help("Evaluates the provided file(s) as scripts when the REPL starts. Accepts file paths and URLs.")
+          .help("Evaluates the provided file(s) as scripts when the REPL starts. Accepts file paths and URLs")
           .value_hint(ValueHint::AnyPath),
       )
       .arg(
         Arg::new("eval")
           .long("eval")
-          .help("Evaluates the provided code when the REPL starts.")
+          .help("Evaluates the provided code when the REPL starts")
           .value_name("code"),
       )
-      .after_help(color_print::cstr!("<y>Environment variables:</>
+      .after_help(cstr!("<y>Environment variables:</>
   <g>DENO_REPL_HISTORY</>  Set REPL history file path. History file is disabled when the value is empty.
-                       <p(245)>(defaults to $DENO_DIR/deno_history.txt)</>"))
+                       <p(245)>[default: $DENO_DIR/deno_history.txt]</>"))
     )
     .arg(env_file_arg())
 }
@@ -2734,16 +2744,14 @@ fn run_args(command: Command, top_level: bool) -> Command {
     .arg(if top_level {
       script_arg().trailing_var_arg(true).hide(true)
     } else {
-      script_arg()
-        .required_unless_present_any(["help", "v8-flags"])
-        .trailing_var_arg(true)
+      script_arg().trailing_var_arg(true)
     })
     .arg(env_file_arg())
     .arg(no_code_cache_arg())
 }
 
 fn run_subcommand() -> Command {
-  run_args(command("run", color_print::cstr!("Run a JavaScript or TypeScript program, or a task or script.
+  run_args(command("run", cstr!("Run a JavaScript or TypeScript program, or a task or script.
 
 By default all programs are run in sandbox without access to disk, network or ability to spawn subprocesses.
   <p(245)>deno run https://examples.deno.land/hello-world.ts</>
@@ -2774,13 +2782,13 @@ fn serve_subcommand() -> Command {
     .arg(
       Arg::new("port")
         .long("port")
-        .help("The TCP port to serve on, defaulting to 8000. Pass 0 to pick a random free port.")
+        .help("The TCP port to serve on, defaulting to 8000. Pass 0 to pick a random free port")
         .value_parser(value_parser!(u16)),
     )
     .arg(
       Arg::new("host")
         .long("host")
-        .help("The TCP address to serve on, defaulting to 0.0.0.0 (all interfaces).")
+        .help("The TCP address to serve on, defaulting to 0.0.0.0 (all interfaces)")
         .value_parser(serve_host_validator),
     )
     .arg(
@@ -2874,15 +2882,15 @@ Directory arguments are expanded to all contained files matching the glob
       .arg(
         Arg::new("trace-ops")
           .long("trace-ops")
-          .help("Deprecated alias for --trace-leaks.")
+          .help("Deprecated alias for --trace-leaks")
           .hide(true)
           .action(ArgAction::SetTrue)
           .help_heading(TEST_HEADING),
       )
       .arg(
         Arg::new("trace-leaks")
           .long("trace-leaks")
-          .help("Enable tracing of leaks. Useful when debugging leaking ops in test, but impacts test execution time.")
+          .help("Enable tracing of leaks. Useful when debugging leaking ops in test, but impacts test execution time")
           .action(ArgAction::SetTrue)
           .help_heading(TEST_HEADING),
       )
@@ -2897,7 +2905,7 @@ Directory arguments are expanded to all contained files matching the glob
         Arg::new("fail-fast")
           .long("fail-fast")
           .alias("failfast")
-          .help("Stop after N errors. Defaults to stopping after first failure.")
+          .help("Stop after N errors. Defaults to stopping after first failure")
           .num_args(0..=1)
           .require_equals(true)
           .value_name("N")
@@ -2923,7 +2931,7 @@ Directory arguments are expanded to all contained files matching the glob
         Arg::new("filter")
           .allow_hyphen_values(true)
           .long("filter")
-          .help("Run tests with this string or pattern in the test name")
+          .help("Run tests with this string or regexp pattern in the test name")
           .help_heading(TEST_HEADING),
       )
       .arg(
@@ -2946,14 +2954,14 @@ Directory arguments are expanded to all contained files matching the glob
           .conflicts_with("inspect")
           .conflicts_with("inspect-wait")
           .conflicts_with("inspect-brk")
-          .help("Collect coverage profile data into DIR. If DIR is not specified, it uses 'coverage/'.")
+          .help("Collect coverage profile data into DIR. If DIR is not specified, it uses 'coverage/'")
           .help_heading(TEST_HEADING),
       )
       .arg(
         Arg::new("clean")
           .long("clean")
-          .help("Empty the temporary coverage profile data directory before running tests.
-  Note: running multiple `deno test --clean` calls in series or parallel for the same coverage directory may cause race conditions.")
+          .help(cstr!("Empty the temporary coverage profile data directory before running tests.
+  <p(245)>Note: running multiple `deno test --clean` calls in series or parallel for the same coverage directory may cause race conditions.</>"))
           .action(ArgAction::SetTrue)
           .help_heading(TEST_HEADING),
       )
@@ -2990,13 +2998,13 @@ Directory arguments are expanded to all contained files matching the glob
           .long("junit-path")
           .value_name("PATH")
           .value_hint(ValueHint::FilePath)
-          .help("Write a JUnit XML test report to PATH. Use '-' to write to stdout which is the default when PATH is not provided.")
+          .help("Write a JUnit XML test report to PATH. Use '-' to write to stdout which is the default when PATH is not provided")
           .help_heading(TEST_HEADING)
       )
       .arg(
         Arg::new("reporter")
           .long("reporter")
-          .help("Select reporter to use. Default to 'pretty'.")
+          .help("Select reporter to use. Default to 'pretty'")
           .value_parser(["pretty", "dot", "junit", "tap"])
           .help_heading(TEST_HEADING)
       )
@@ -3013,7 +3021,7 @@ Directory arguments are expanded to all contained files matching the glob
 fn parallel_arg(descr: &str, jobs_fallback: bool) -> Arg {
   let arg = Arg::new("parallel")
     .long("parallel")
-    .help(format!("Run {descr} in parallel. Parallelism defaults to the number of available CPUs or the value of the DENO_JOBS environment variable."))
+    .help(format!("Run {descr} in parallel. Parallelism defaults to the number of available CPUs or the value of the DENO_JOBS environment variable"))
     .action(ArgAction::SetTrue);
   if jobs_fallback {
     arg.conflicts_with("jobs")
@@ -3216,7 +3224,8 @@ fn publish_subcommand() -> Command {
         ).arg(
         Arg::new("no-provenance")
           .long("no-provenance")
-          .help("Disable provenance attestation. Enabled by default on Github actions, publicly links the package to where it was built and published from.")
+          .help(cstr!("Disable provenance attestation.
+  <p(245)>Enabled by default on Github actions, publicly links the package to where it was built and published from.</>"))
           .action(ArgAction::SetTrue)
         .help_heading(PUBLISH_HEADING)
       )
@@ -3248,33 +3257,51 @@ fn compile_args_without_check_args(app: Command) -> Command {
 
 fn permission_args(app: Command) -> Command {
   app
-    .after_help(color_print::cstr!(r#"<y>Permission options:</>
-Docs: https://docs.deno.com/go/permissions
-
-  <g>-A, --allow-all</>                               Allow all permissions.
-  <g>-R, --{allow,deny}-read[=<<PATH>...]</>           Allow / deny file system read access. Optionally specify allowed / denied paths.
-                                                  <p(245)>--allow-read  |  --allow-read="/etc,/var/log.txt"  |  --deny-read="/etc/hosts"</>
-  <g>-W, --{allow,write}-read[=<<PATH>...]</>          Allow / deny file system write access. Optionally specify allowed / denied paths.
-                                                  <p(245)>--allow-write  |  --allow-write="/etc,/var/log.txt"  |  --deny-write="/etc/hosts"</>
-  <g>-N, --{allow,deny}-net[=<<IP_OR_HOSTNAME>...]</>  Allow / deny network access. Optionally specify allowed IP addresses and host names, with ports as necessary.
-                                                  <p(245)>--allow-net  |  --allow-net="localhost:8080,deno.land"  |  --deny-net="deno.com"</>
-  <g>-E --{allow,deny}-env[=<<VARIABLE_NAME>...]</>    Allow / deny access to environment variables. Optionally specify accessible / inacessible environment variables.
-                                                  <p(245)>--allow-env  |  --allow-env="PORT,HOME,PATH"  |  --deny-env="ACCESS_TOKEN"</>
-  <g>-S --{allow,deny}-sys[=<<API_NAME>...]</>         Allow / deny access to OS information. Optionally allow / deny specific APIs by function name.
-                                                  <p(245)>--allow-sys  |  --allow-sys="systemMemoryInfo,osRelease"  |  --deny-sys="hostname"</>
-      <g>--{allow,deny}-run[=<<PROGRAM_NAME>...]</>    Allow / deny running subprocesses. Optionally specify allowed / denied runnable program names.
-                                                  <p(245)>--allow-run  |  --allow-run="whoami,ps"  |  --deny-run="cat"</>
-      <g>--{allow,deny}-ffi[=<<PATH>...]</>            (Unstable) Allow / deny loading dynamic libraries. Optionally specify allowed / denied directories or files.
-                                                  <p(245)>--allow-ffi  |  --allow-ffi="./libfoo.so"  |  --deny-ffi="./libfoo.so"</>
-      <g>--{allow,deny}-hrtime</>                     Allow / deny high-resolution time measurement. Note: this can enable timing attacks and fingerprinting.
-      <g>--no-prompt</>                               Always throw if required permission wasn't passed. Can also be set via the DENO_NO_PROMPT environment variable.
+    .after_help(cstr!(r#"<y>Permission options:</>
+Docs: <c>https://docs.deno.com/go/permissions</>
+
+  <g>-A, --allow-all</>                        Allow all permissions.
+  <g>--no-prompt</>                        Always throw if required permission wasn't passed.
+                                           <p(245)>Can also be set via the DENO_NO_PROMPT environment variable.</>
+  <g>-R, --allow-read[=<<PATH>...]</>           Allow file system read access. Optionally specify allowed paths.
+                                           <p(245)>--allow-read  |  --allow-read="/etc,/var/log.txt"</>
+  <g>-W, --allow-write[=<<PATH>...]</>          Allow file system write access. Optionally specify allowed paths.
+                                           <p(245)>--allow-write  |  --allow-write="/etc,/var/log.txt"</>
+  <g>-N, --allow-net[=<<IP_OR_HOSTNAME>...]</>  Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary.
+                                           <p(245)>--allow-net  |  --allow-net="localhost:8080,deno.land"</>
+  <g>-E, --allow-env[=<<VARIABLE_NAME>...]</>   Allow access to environment variables. Optionally specify accessible environment variables.
+                                           <p(245)>--allow-env  |  --allow-env="PORT,HOME,PATH"</>
+  <g>-S, --allow-sys[=<<API_NAME>...]</>        Allow access to OS information. Optionally allow specific APIs by function name.
+                                           <p(245)>--allow-sys  |  --allow-sys="systemMemoryInfo,osRelease"</>
+      <g>--allow-run[=<<PROGRAM_NAME>...]</>    Allow running subprocesses. Optionally specify allowed runnable program names.
+                                           <p(245)>--allow-run  |  --allow-run="whoami,ps"</>
+      <g>--allow-ffi[=<<PATH>...]</>            (Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.
+                                           <p(245)>--allow-ffi  |  --allow-ffi="./libfoo.so"</>
+      <g>--allow-hrtime</>                     Allow high-resolution time measurement. Note: this can enable timing attacks and fingerprinting.
+                                           <p(245)>--allow-hrtime</>
+  <g>    --deny-read[=<<PATH>...]</>            Deny file system read access. Optionally specify denied paths.
+                                           <p(245)>--deny-read  |  --deny-read="/etc,/var/log.txt"</>
+  <g>    --deny-write[=<<PATH>...]</>           Deny file system write access. Optionally specify denied paths.
+                                           <p(245)>--deny-write  |  --deny-write="/etc,/var/log.txt"</>
+  <g>    --deny-net[=<<IP_OR_HOSTNAME>...]</>   Deny network access. Optionally specify defined IP addresses and host names, with ports as necessary.
+                                           <p(245)>--deny-net  |  --deny-net="localhost:8080,deno.land"</>
+  <g>    --deny-env[=<<VARIABLE_NAME>...]</>    Deny access to environment variables. Optionally specify inacessible environment variables.
+                                           <p(245)>--deny-env  |  --deny-env="PORT,HOME,PATH"</>
+  <g>-S, --deny-sys[=<<API_NAME>...]</>         Deny access to OS information. Optionally deny specific APIs by function name.
+                                           <p(245)>--deny-sys  |  --deny-sys="systemMemoryInfo,osRelease"</>
+      <g>--deny-run[=<<PROGRAM_NAME>...]</>     Deny running subprocesses. Optionally specify denied runnable program names.
+                                           <p(245)>--deny-run  |  --deny-run="whoami,ps"</>
+      <g>--deny-ffi[=<<PATH>...]</>             (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
+                                           <p(245)>--deny-ffi  |  --deny-ffi="./libfoo.so"</>
+      <g>--deny-hrtime</>                      Deny high-resolution time measurement.
+                                           <p(245)>--deny-hrtime</>
 "#))
     .arg(
       Arg::new("allow-all")
         .short('A')
         .long("allow-all")
         .action(ArgAction::SetTrue)
-        .help("Allow all permissions.")
+        .help("Allow all permissions")
         .hide(true),
     )
     .arg(
@@ -3285,7 +3312,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PATH")
-        .help("Allow file system read access. Optionally specify allowed paths.")
+        .help("Allow file system read access. Optionally specify allowed paths")
         .value_parser(value_parser!(String))
         .value_hint(ValueHint::AnyPath)
         .hide(true),
@@ -3297,7 +3324,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PATH")
-        .help("Deny file system read access. Optionally specify denied paths.")
+        .help("Deny file system read access. Optionally specify denied paths")
         .value_parser(value_parser!(String))
         .value_hint(ValueHint::AnyPath)
         .hide(true),
@@ -3310,7 +3337,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PATH")
-        .help("Allow file system write access. Optionally specify allowed paths.")
+        .help("Allow file system write access. Optionally specify allowed paths")
         .value_parser(value_parser!(String))
         .value_hint(ValueHint::AnyPath)
         .hide(true),
@@ -3322,7 +3349,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PATH")
-        .help("Deny file system write access. Optionally specify denied paths.")
+        .help("Deny file system write access. Optionally specify denied paths")
         .value_parser(value_parser!(String))
         .value_hint(ValueHint::AnyPath)
         .hide(true),
@@ -3335,7 +3362,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("IP_OR_HOSTNAME")
-        .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary.")
+        .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary")
         .value_parser(flags_net::validator)
         .hide(true),
     )
@@ -3346,7 +3373,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("IP_OR_HOSTNAME")
-        .help("Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary.")
+        .help("Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary")
         .value_parser(flags_net::validator)
         .hide(true),
     )
@@ -3358,7 +3385,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("VARIABLE_NAME")
-        .help("Allow access to system environment information. Optionally specify accessible environment variables.")
+        .help("Allow access to system environment information. Optionally specify accessible environment variables")
         .value_parser(|key: &str| {
           if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
             return Err(format!("invalid key \"{key}\""));
@@ -3379,7 +3406,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("VARIABLE_NAME")
-        .help("Deny access to system environment information. Optionally specify accessible environment variables.")
+        .help("Deny access to system environment information. Optionally specify accessible environment variables")
         .value_parser(|key: &str| {
           if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
             return Err(format!("invalid key \"{key}\""));
@@ -3401,7 +3428,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("API_NAME")
-        .help("Allow access to OS information. Optionally allow specific APIs by function name.")
+        .help("Allow access to OS information. Optionally allow specific APIs by function name")
         .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string))
         .hide(true),
     )
@@ -3412,7 +3439,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("API_NAME")
-        .help("Deny access to OS information. Optionally deny specific APIs by function name.")
+        .help("Deny access to OS information. Optionally deny specific APIs by function name")
         .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string))
         .hide(true),
     )
@@ -3423,7 +3450,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PROGRAM_NAME")
-        .help("Allow running subprocesses. Optionally specify allowed runnable program names.")
+        .help("Allow running subprocesses. Optionally specify allowed runnable program names")
         .hide(true),
     )
     .arg(
@@ -3433,7 +3460,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PROGRAM_NAME")
-        .help("Deny running subprocesses. Optionally specify denied runnable program names.")
+        .help("Deny running subprocesses. Optionally specify denied runnable program names")
         .hide(true),
     )
     .arg(
@@ -3443,7 +3470,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PATH")
-        .help("(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.")
+        .help("(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files")
         .value_parser(value_parser!(String))
         .value_hint(ValueHint::AnyPath)
         .hide(true),
@@ -3455,7 +3482,7 @@ Docs: https://docs.deno.com/go/permissions
         .use_value_delimiter(true)
         .require_equals(true)
         .value_name("PATH")
-        .help("(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.")
+        .help("(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files")
         .value_parser(value_parser!(String))
         .value_hint(ValueHint::AnyPath)
         .hide(true),
@@ -3464,14 +3491,14 @@ Docs: https://docs.deno.com/go/permissions
       Arg::new("allow-hrtime")
         .long("allow-hrtime")
         .action(ArgAction::SetTrue)
-        .help("Allow high-resolution time measurement. Note: this can enable timing attacks and fingerprinting.")
+        .help("Allow high-resolution time measurement. Note: this can enable timing attacks and fingerprinting")
         .hide(true),
     )
     .arg(
       Arg::new("deny-hrtime")
         .long("deny-hrtime")
         .action(ArgAction::SetTrue)
-        .help("Deny high-resolution time measurement. Note: this can prevent timing attacks and fingerprinting.")
+        .help("Deny high-resolution time measurement. Note: this can prevent timing attacks and fingerprinting")
         .hide(true),
     )
     .arg(
@@ -3515,7 +3542,8 @@ fn inspect_args(app: Command) -> Command {
       Arg::new("inspect")
         .long("inspect")
         .value_name("HOST_AND_PORT")
-        .help("Activate inspector on host:port (default: 127.0.0.1:9229)")
+        .default_missing_value("127.0.0.1:9229")
+        .help(cstr!("Activate inspector on host:port <p(245)>[default: 127.0.0.1:9229]</>"))
         .num_args(0..=1)
         .require_equals(true)
         .value_parser(value_parser!(SocketAddr))
@@ -3525,6 +3553,7 @@ fn inspect_args(app: Command) -> Command {
       Arg::new("inspect-brk")
         .long("inspect-brk")
         .value_name("HOST_AND_PORT")
+        .default_missing_value("127.0.0.1:9229")
         .help(
           "Activate inspector on host:port, wait for debugger to connect and break at the start of user script",
         )
@@ -3537,6 +3566,7 @@ fn inspect_args(app: Command) -> Command {
       Arg::new("inspect-wait")
         .long("inspect-wait")
         .value_name("HOST_AND_PORT")
+        .default_missing_value("127.0.0.1:9229")
         .help(
           "Activate inspector on host:port and wait for debugger to connect before running user code",
         )
@@ -3552,10 +3582,10 @@ fn import_map_arg() -> Arg {
     .long("import-map")
     .alias("importmap")
     .value_name("FILE")
-    .help(
-      "Load import map file from local file or remote URL.
-  Docs: https://docs.deno.com/runtime/manual/basics/import_maps",
-    )
+    .help(cstr!(
+      "Load import map file from local file or remote URL
+  <p(245)>Docs: https://docs.deno.com/runtime/manual/basics/import_maps</>",
+    ))
     .value_hint(ValueHint::FilePath)
     .help_heading(DEPENDENCY_MANAGEMENT_HEADING)
 }
@@ -3565,11 +3595,11 @@ fn env_file_arg() -> Arg {
     .long("env-file")
     .alias("env")
     .value_name("FILE")
-    .help(
-      "Load environment variables from local file.
-  Only the first environment variable with a given key is used.
-  Existing process environment variables are not overwritten.",
-    )
+    .help(cstr!(
+      "Load environment variables from local file
+  <p(245)>Only the first environment variable with a given key is used.
+  Existing process environment variables are not overwritten.</>"
+    ))
     .value_hint(ValueHint::FilePath)
     .default_missing_value(".env")
     .require_equals(true)
@@ -3585,7 +3615,7 @@ fn reload_arg() -> Arg {
     .long("reload")
     .value_name("CACHE_BLOCKLIST")
     .help(
-      color_print::cstr!("Reload source code cache (recompile TypeScript)
+      cstr!("Reload source code cache (recompile TypeScript)
   <p(245)>no value                                                 Reload everything
   jsr:@std/http/file-server,jsr:@std/assert/assert-equals  Reloads specific modules
   npm:                                                     Reload all npm modules
@@ -3683,9 +3713,9 @@ fn v8_flags_arg() -> Arg {
     .use_value_delimiter(true)
     .require_equals(true)
     .value_name("V8_FLAGS")
-    .help("To see a list of all available flags use --v8-flags=--help.
-  Flags can also be set via the DENO_V8_FLAGS environment variable.
-  Any flags set with this flag are appended after the DENO_V8_FLAGS environment variable")
+    .help( cstr!("To see a list of all available flags use --v8-flags=--help
+  <p(245)>Flags can also be set via the DENO_V8_FLAGS environment variable.
+  Any flags set with this flag are appended after the DENO_V8_FLAGS environment variable</>"))
 }
 
 fn seed_arg() -> Arg {
@@ -3713,14 +3743,14 @@ fn hmr_arg(takes_files: bool) -> Arg {
       .use_value_delimiter(true)
       .require_equals(true)
       .help(
-        color_print::cstr!(
+        cstr!(
         "Watch for file changes and restart process automatically.
   <p(245)>Local files from entry point module graph are watched by default.
   Additional paths might be watched by passing them as arguments to this flag.</>"),
       )
       .value_hint(ValueHint::AnyPath)
   } else {
-    arg.action(ArgAction::SetTrue).help(color_print::cstr!(
+    arg.action(ArgAction::SetTrue).help(cstr!(
       "Watch for file changes and restart process automatically.
   <p(245)>Only local files from entry point module graph are watched.</>"
     ))
@@ -3740,14 +3770,14 @@ fn watch_arg(takes_files: bool) -> Arg {
       .use_value_delimiter(true)
       .require_equals(true)
       .help(
-        color_print::cstr!(
+        cstr!(
         "Watch for file changes and restart process automatically.
   <p(245)>Local files from entry point module graph are watched by default.
   Additional paths might be watched by passing them as arguments to this flag.</>"),
       )
       .value_hint(ValueHint::AnyPath)
   } else {
-    arg.action(ArgAction::SetTrue).help(color_print::cstr!(
+    arg.action(ArgAction::SetTrue).help(cstr!(
       "Watch for file changes and restart process automatically.
   <p(245)>Only local files from entry point module graph are watched.</>"
     ))
@@ -3789,10 +3819,7 @@ fn no_check_arg() -> Arg {
     .require_equals(true)
     .value_name("NO_CHECK_TYPE")
     .long("no-check")
-    .help(
-      "Skip type-checking. If the value of '--no-check=remote' is supplied,
-  diagnostic errors from remote modules will be ignored.",
-    )
+    .help("Skip type-checking. If the value of \"remote\" is supplied, diagnostic errors from remote modules will be ignored")
     .help_heading(TYPE_CHECKING_HEADING)
 }
 
@@ -3807,17 +3834,16 @@ fn check_arg(checks_local_by_default: bool) -> Arg {
 
   if checks_local_by_default {
     arg.help(
-      "Set type-checking behavior. This subcommand type-checks local modules by
-  default, so adding --check is redundant.
-  If the value of \"all\" is supplied, remote modules will be included.
-  Alternatively, the 'deno check' subcommand can be used.",
-    )
+      cstr!("Set type-checking behavior. This subcommand type-checks local modules by default, so adding --check is redundant
+  <p(245)>If the value of \"all\" is supplied, remote modules will be included.
+  Alternatively, the 'deno check' subcommand can be used</>",
+    ))
   } else {
-    arg.help(
-      "Enable type-checking. This subcommand does not type-check by default.
-  If the value of \"all\" is supplied, remote modules will be included.
-  Alternatively, the 'deno check' subcommand can be used.",
-    )
+    arg.help(cstr!(
+      "Enable type-checking. This subcommand does not type-check by default
+  <p(245)>If the value of \"all\" is supplied, remote modules will be included.
+  Alternatively, the 'deno check' subcommand can be used</>"
+    ))
   }
 }
 
@@ -3854,7 +3880,7 @@ fn lock_write_arg() -> Arg {
   Arg::new("lock-write")
     .action(ArgAction::SetTrue)
     .long("lock-write")
-    .help("Force overwriting the lock file.")
+    .help("Force overwriting the lock file")
     .conflicts_with("no-lock")
     .hide(true)
 }
@@ -3873,18 +3899,18 @@ fn config_arg() -> Arg {
     .short('c')
     .long("config")
     .value_name("FILE")
-    .help("Configure different aspects of deno including TypeScript, linting, and code formatting.
-  Typically the configuration file will be called `deno.json` or `deno.jsonc` and
+    .help(cstr!("Configure different aspects of deno including TypeScript, linting, and code formatting
+  <p(245)>Typically the configuration file will be called `deno.json` or `deno.jsonc` and
   automatically detected; in that case this flag is not necessary.
-  Docs: https://docs.deno.com/go/config")
+  Docs: https://docs.deno.com/go/config</>"))
     .value_hint(ValueHint::FilePath)
 }
 
 fn no_config_arg() -> Arg {
   Arg::new("no-config")
     .long("no-config")
     .action(ArgAction::SetTrue)
-    .help("Disable automatic loading of the configuration file.")
+    .help("Disable automatic loading of the configuration file")
     .conflicts_with("config")
 }
 
@@ -3923,10 +3949,7 @@ fn vendor_arg() -> Arg {
     .value_parser(value_parser!(bool))
     .default_missing_value("true")
     .require_equals(true)
-    .help(
-      "Enables or disables the use of a local vendor folder
-  for remote modules and node_modules folder for npm packages",
-    )
+    .help("Toggles local vendor folder usage for remote modules and a node_modules folder for npm packages")
     .help_heading(DEPENDENCY_MANAGEMENT_HEADING)
 }
 
@@ -3950,7 +3973,8 @@ fn allow_scripts_arg() -> Arg {
     .require_equals(true)
     .value_name("PACKAGE")
     .value_parser(parse_packages_allowed_scripts)
-    .help("Allow running npm lifecycle scripts for the given packages. Note: Scripts will only be executed when using a node_modules directory (`--node-modules-dir`)")
+    .help(cstr!("Allow running npm lifecycle scripts for the given packages
+  <p(245)>Note: Scripts will only be executed when using a node_modules directory (`--node-modules-dir`)</>"))
 }
 
 enum UnstableArgsConfig {
@@ -3972,7 +3996,8 @@ impl Iterator for UnstableArgsIter {
     let arg = if self.idx == 0 {
       Arg::new("unstable")
         .long("unstable")
-        .help("Enable all unstable features and APIs. Instead of using this flag, consider enabling individual unstable features.\n  To view the list of individual unstable feature flags, run this command again with --help=unstable.")
+        .help(cstr!("Enable all unstable features and APIs. Instead of using this flag, consider enabling individual unstable features
+  <p(245)>To view the list of individual unstable feature flags, run this command again with --help=unstable</>"))
         .action(ArgAction::SetTrue)
         .hide(matches!(self.cfg, UnstableArgsConfig::None))
     } else if self.idx == 1 {
@@ -4006,9 +4031,7 @@ impl Iterator for UnstableArgsIter {
     } else if self.idx == 3 {
       Arg::new("unstable-sloppy-imports")
       .long("unstable-sloppy-imports")
-      .help(
-        "Enable unstable resolving of specifiers by extension probing, .js to .ts, and directory probing.",
-      )
+      .help("Enable unstable resolving of specifiers by extension probing, .js to .ts, and directory probing")
       .env("DENO_UNSTABLE_SLOPPY_IMPORTS")
       .value_parser(FalseyValueParser::new())
       .action(ArgAction::SetTrue)
@@ -4628,7 +4651,7 @@ fn repl_parse(flags: &mut Flags, matches: &mut ArgMatches) {
 fn run_parse(
   flags: &mut Flags,
   matches: &mut ArgMatches,
-  mut app: Command,
+  app: Command,
   bare: bool,
 ) -> clap::error::Result<()> {
   // todo(dsherret): remove this in Deno 2.0
@@ -4679,35 +4702,31 @@ fn run_parse(
   }
 
   runtime_args_parse(flags, matches, true, true);
+  ext_arg_parse(flags, matches);
 
   flags.code_cache_enabled = !matches.get_flag("no-code-cache");
 
-  let mut script_arg =
-    matches.remove_many::<String>("script_arg").ok_or_else(|| {
-      if bare {
-        app.override_usage("deno [OPTIONS] [COMMAND] [SCRIPT_ARG]...").error(
-          clap::error::ErrorKind::MissingRequiredArgument,
-          "[SCRIPT_ARG] may only be omitted with --v8-flags=--help, else to use the repl with arguments, please use the `deno repl` subcommand",
-        )
-      } else {
-        app.find_subcommand_mut("run").unwrap().error(
-          clap::error::ErrorKind::MissingRequiredArgument,
-          "[SCRIPT_ARG] may only be omitted with --v8-flags=--help",
-        )
-      }
-    })?;
-
-  let script = script_arg.next().unwrap();
-  flags.argv.extend(script_arg);
-
-  ext_arg_parse(flags, matches);
-  temp_netlify_deno_1_hack(flags, &script);
-
-  flags.subcommand = DenoSubcommand::Run(RunFlags {
-    script,
-    watch: watch_arg_parse_with_paths(matches),
-    bare,
-  });
+  if let Some(mut script_arg) = matches.remove_many::<String>("script_arg") {
+    let script = script_arg.next().unwrap();
+    flags.argv.extend(script_arg);
+    temp_netlify_deno_1_hack(flags, &script);
+    flags.subcommand = DenoSubcommand::Run(RunFlags {
+      script,
+      watch: watch_arg_parse_with_paths(matches),
+      bare,
+    });
+  } else if bare {
+    return Err(app.override_usage("deno [OPTIONS] [COMMAND] [SCRIPT_ARG]...").error(
+      clap::error::ErrorKind::MissingRequiredArgument,
+      "[SCRIPT_ARG] may only be omitted with --v8-flags=--help, else to use the repl with arguments, please use the `deno repl` subcommand",
+    ));
+  } else {
+    flags.subcommand = DenoSubcommand::Task(TaskFlags {
+      cwd: None,
+      task: None,
+      is_run: true,
+    });
+  }
 
   Ok(())
 }
@@ -4781,6 +4800,7 @@ fn task_parse(flags: &mut Flags, matches: &mut ArgMatches) {
   let mut task_flags = TaskFlags {
     cwd: matches.remove_one::<String>("cwd"),
     task: None,
+    is_run: false,
   };
 
   if let Some((task, mut matches)) = matches.remove_subcommand() {
@@ -5153,34 +5173,9 @@ fn runtime_args_parse(
 }
 
 fn inspect_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
-  let default = || "127.0.0.1:9229".parse::<SocketAddr>().unwrap();
-  flags.inspect = if matches.contains_id("inspect") {
-    Some(
-      matches
-        .remove_one::<SocketAddr>("inspect")
-        .unwrap_or_else(default),
-    )
-  } else {
-    None
-  };
-  flags.inspect_brk = if matches.contains_id("inspect-brk") {
-    Some(
-      matches
-        .remove_one::<SocketAddr>("inspect-brk")
-        .unwrap_or_else(default),
-    )
-  } else {
-    None
-  };
-  flags.inspect_wait = if matches.contains_id("inspect-wait") {
-    Some(
-      matches
-        .remove_one::<SocketAddr>("inspect-wait")
-        .unwrap_or_else(default),
-    )
-  } else {
-    None
-  };
+  flags.inspect = matches.remove_one::<SocketAddr>("inspect");
+  flags.inspect_brk = matches.remove_one::<SocketAddr>("inspect-brk");
+  flags.inspect_wait = matches.remove_one::<SocketAddr>("inspect-wait");
 }
 
 fn import_map_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
@@ -5886,10 +5881,7 @@ mod tests {
     );
 
     let r = flags_from_vec(svec!["deno", "run", "--v8-flags=--expose-gc"]);
-    assert!(r
-      .unwrap_err()
-      .to_string()
-      .contains("[SCRIPT_ARG] may only be omitted with --v8-flags=--help"));
+    assert!(r.is_ok());
   }
 
   #[test]
@@ -10341,6 +10333,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: Some("build".to_string()),
+          is_run: false,
         }),
         argv: svec!["hello", "world"],
         ..Flags::default()
@@ -10354,6 +10347,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: Some("build".to_string()),
+          is_run: false,
         }),
         ..Flags::default()
       }
@@ -10366,6 +10360,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: Some("foo".to_string()),
           task: Some("build".to_string()),
+          is_run: false,
         }),
         ..Flags::default()
       }
@@ -10390,6 +10385,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: Some("build".to_string()),
+          is_run: false,
         }),
         argv: svec!["--", "hello", "world"],
         config_flag: ConfigFlag::Path("deno.json".to_owned()),
@@ -10406,6 +10402,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: Some("foo".to_string()),
           task: Some("build".to_string()),
+          is_run: false,
         }),
         argv: svec!["--", "hello", "world"],
         ..Flags::default()
@@ -10423,6 +10420,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: Some("build".to_string()),
+          is_run: false,
         }),
         argv: svec!["--"],
         ..Flags::default()
@@ -10439,6 +10437,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: Some("build".to_string()),
+          is_run: false,
         }),
         argv: svec!["-1", "--test"],
         ..Flags::default()
@@ -10455,6 +10454,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: Some("build".to_string()),
+          is_run: false,
         }),
         argv: svec!["--test"],
         ..Flags::default()
@@ -10472,6 +10472,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: Some("build".to_string()),
+          is_run: false,
         }),
         log_level: Some(log::Level::Error),
         ..Flags::default()
@@ -10488,6 +10489,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: None,
+          is_run: false,
         }),
         ..Flags::default()
       }
@@ -10503,6 +10505,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: None,
+          is_run: false,
         }),
         config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
         ..Flags::default()
@@ -10519,6 +10522,7 @@ mod tests {
         subcommand: DenoSubcommand::Task(TaskFlags {
           cwd: None,
           task: None,
+          is_run: false,
         }),
         config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
         ..Flags::default()
@@ -11052,4 +11056,43 @@ mod tests {
       .to_string()
       .contains("Usage: deno [OPTIONS] [COMMAND] [SCRIPT_ARG]..."));
   }
+
+  #[test]
+  fn equal_help_output() {
+    for command in clap_root().get_subcommands() {
+      if command.get_name() == "help" {
+        continue;
+      }
+
+      let long_flag = if let DenoSubcommand::Help(help) =
+        flags_from_vec(svec!["deno", command.get_name(), "--help"])
+          .unwrap()
+          .subcommand
+      {
+        help.help.to_string()
+      } else {
+        unreachable!()
+      };
+      let short_flag = if let DenoSubcommand::Help(help) =
+        flags_from_vec(svec!["deno", command.get_name(), "-h"])
+          .unwrap()
+          .subcommand
+      {
+        help.help.to_string()
+      } else {
+        unreachable!()
+      };
+      let subcommand = if let DenoSubcommand::Help(help) =
+        flags_from_vec(svec!["deno", "help", command.get_name()])
+          .unwrap()
+          .subcommand
+      {
+        help.help.to_string()
+      } else {
+        unreachable!()
+      };
+      assert_eq!(long_flag, short_flag, "{} subcommand", command.get_name());
+      assert_eq!(long_flag, subcommand, "{} subcommand", command.get_name());
+    }
+  }
 }

filename: cli/main.rs
patch: @@ -218,9 +218,10 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
                 let task_flags = TaskFlags {
                   cwd: None,
                   task: Some(run_flags.script.clone()),
+                  is_run: true,
                 };
                 new_flags.subcommand = DenoSubcommand::Task(task_flags.clone());
-                let result = tools::task::execute_script(Arc::new(new_flags), task_flags.clone(), true).await;
+                let result = tools::task::execute_script(Arc::new(new_flags), task_flags.clone()).await;
                 match result {
                   Ok(v) => Ok(v),
                   Err(_) => {
@@ -240,7 +241,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
       tools::serve::serve(flags, serve_flags).await
     }),
     DenoSubcommand::Task(task_flags) => spawn_subcommand(async {
-      tools::task::execute_script(flags, task_flags, false).await
+      tools::task::execute_script(flags, task_flags).await
     }),
     DenoSubcommand::Test(test_flags) => {
       spawn_subcommand(async {
@@ -290,7 +291,21 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
       tools::registry::publish(flags, publish_flags).await
     }),
     DenoSubcommand::Help(help_flags) => spawn_subcommand(async move {
-      display::write_to_stdout_ignore_sigpipe(help_flags.help.ansi().to_string().as_bytes())
+      use std::io::Write;
+
+      let mut stream = anstream::AutoStream::new(std::io::stdout(), if colors::use_color() {
+        anstream::ColorChoice::Auto
+      } else {
+        anstream::ColorChoice::Never
+      });
+
+      match stream.write_all(help_flags.help.ansi().to_string().as_bytes()) {
+        Ok(()) => Ok(()),
+        Err(e) => match e.kind() {
+          std::io::ErrorKind::BrokenPipe => Ok(()),
+          _ => Err(e),
+        },
+      }
     }),
   };
 

filename: cli/tools/task.rs
patch: @@ -29,13 +29,24 @@ use std::sync::Arc;
 pub async fn execute_script(
   flags: Arc<Flags>,
   task_flags: TaskFlags,
-  using_run: bool,
 ) -> Result<i32, AnyError> {
   let factory = CliFactory::from_flags(flags);
   let cli_options = factory.cli_options()?;
   let start_dir = &cli_options.start_dir;
   if !start_dir.has_deno_or_pkg_json() {
-    bail!("deno task couldn't find deno.json(c). See https://docs.deno.com/go/config")
+    if task_flags.is_run {
+      bail!(
+        r#"deno run couldn't find deno.json(c).
+If you meant to run a script, specify it, e.g., `deno run ./script.ts`.
+To run a task, ensure the config file exists.
+Examples:
+- Script: `deno run ./script.ts`
+- Task: `deno run dev`
+See https://docs.deno.com/go/config"#
+      )
+    } else {
+      bail!("deno task couldn't find deno.json(c). See https://docs.deno.com/go/config")
+    }
   }
   let force_use_pkg_json =
     std::env::var_os(crate::task_runner::USE_PKG_JSON_HIDDEN_ENV_VAR_NAME)
@@ -142,7 +153,7 @@ pub async fn execute_script(
       }
     },
     None => {
-      if using_run {
+      if task_flags.is_run {
         return Err(anyhow!("Task not found: {}", task_name));
       }
       log::error!("Task not found: {}", task_name);