skypilot-nightly 1.0.0.dev20250618__py3-none-any.whl → 1.0.0.dev20250619__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. sky/__init__.py +2 -2
  2. sky/cli.py +2 -2
  3. sky/client/cli/__init__.py +0 -0
  4. sky/client/{cli.py → cli/command.py} +97 -630
  5. sky/client/cli/deprecation_utils.py +99 -0
  6. sky/client/cli/flags.py +342 -0
  7. sky/dashboard/out/404.html +1 -1
  8. sky/dashboard/out/_next/static/chunks/{webpack-ebc2404fd6ce581c.js → webpack-0263b00d6a10e64a.js} +1 -1
  9. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  10. sky/dashboard/out/clusters/[cluster].html +1 -1
  11. sky/dashboard/out/clusters.html +1 -1
  12. sky/dashboard/out/config.html +1 -1
  13. sky/dashboard/out/index.html +1 -1
  14. sky/dashboard/out/infra/[context].html +1 -1
  15. sky/dashboard/out/infra.html +1 -1
  16. sky/dashboard/out/jobs/[job].html +1 -1
  17. sky/dashboard/out/jobs.html +1 -1
  18. sky/dashboard/out/users.html +1 -1
  19. sky/dashboard/out/workspace/new.html +1 -1
  20. sky/dashboard/out/workspaces/[name].html +1 -1
  21. sky/dashboard/out/workspaces.html +1 -1
  22. sky/jobs/constants.py +0 -2
  23. sky/jobs/scheduler.py +7 -4
  24. sky/jobs/server/core.py +6 -3
  25. sky/jobs/state.py +9 -8
  26. sky/jobs/utils.py +1 -1
  27. sky/provision/common.py +10 -0
  28. sky/resources.py +7 -6
  29. sky/serve/server/core.py +5 -0
  30. sky/skylet/constants.py +4 -0
  31. sky/utils/env_options.py +6 -0
  32. sky/utils/schemas.py +2 -2
  33. {skypilot_nightly-1.0.0.dev20250618.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/METADATA +1 -1
  34. {skypilot_nightly-1.0.0.dev20250618.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/RECORD +40 -37
  35. /sky/dashboard/out/_next/static/{LRpGymRCqq-feuFyoWz4m → whetcrnbXtqQcMRbXUbhW}/_buildManifest.js +0 -0
  36. /sky/dashboard/out/_next/static/{LRpGymRCqq-feuFyoWz4m → whetcrnbXtqQcMRbXUbhW}/_ssgManifest.js +0 -0
  37. {skypilot_nightly-1.0.0.dev20250618.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/WHEEL +0 -0
  38. {skypilot_nightly-1.0.0.dev20250618.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/entry_points.txt +0 -0
  39. {skypilot_nightly-1.0.0.dev20250618.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/licenses/LICENSE +0 -0
  40. {skypilot_nightly-1.0.0.dev20250618.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/top_level.txt +0 -0
@@ -24,9 +24,7 @@ listed in "sky --help". Take care to put logically connected commands close to
24
24
  each other.
25
25
  """
26
26
  import collections
27
- import copy
28
27
  import fnmatch
29
- import functools
30
28
  import os
31
29
  import pathlib
32
30
  import shlex
@@ -40,7 +38,6 @@ from typing import (Any, Callable, Dict, Generator, List, Optional, Set, Tuple,
40
38
 
41
39
  import click
42
40
  import colorama
43
- import dotenv
44
41
  import requests as requests_lib
45
42
  from rich import progress as rich_progress
46
43
  import yaml
@@ -57,6 +54,7 @@ from sky import sky_logging
57
54
  from sky import skypilot_config
58
55
  from sky.adaptors import common as adaptors_common
59
56
  from sky.client import sdk
57
+ from sky.client.cli import flags
60
58
  from sky.data import storage_utils
61
59
  from sky.provision.kubernetes import constants as kubernetes_constants
62
60
  from sky.provision.kubernetes import utils as kubernetes_utils
@@ -215,38 +213,6 @@ def _get_glob_matches(candidate_names: List[str],
215
213
  return list(set(glob_storages))
216
214
 
217
215
 
218
- def _parse_env_var(env_var: str) -> Tuple[str, str]:
219
- """Parse env vars into a (KEY, VAL) pair."""
220
- if '=' not in env_var:
221
- value = os.environ.get(env_var)
222
- if value is None:
223
- raise click.UsageError(
224
- f'{env_var} is not set in local environment.')
225
- return (env_var, value)
226
- ret = tuple(env_var.split('=', 1))
227
- if len(ret) != 2:
228
- raise click.UsageError(
229
- f'Invalid env var: {env_var}. Must be in the form of KEY=VAL '
230
- 'or KEY.')
231
- return ret[0], ret[1]
232
-
233
-
234
- def _parse_secret_var(secret_var: str) -> Tuple[str, str]:
235
- """Parse secret vars into a (KEY, VAL) pair."""
236
- if '=' not in secret_var:
237
- value = os.environ.get(secret_var)
238
- if value is None:
239
- raise click.UsageError(
240
- f'{secret_var} is not set in local environment.')
241
- return (secret_var, value)
242
- ret = tuple(secret_var.split('=', 1))
243
- if len(ret) != 2:
244
- raise click.UsageError(
245
- f'Invalid secret var: {secret_var}. Must be in the form of KEY=VAL '
246
- 'or KEY.')
247
- return ret[0], ret[1]
248
-
249
-
250
216
  def _async_call_or_wait(request_id: str, async_call: bool,
251
217
  request_name: str) -> Any:
252
218
  short_request_id = request_id[:8]
@@ -296,245 +262,6 @@ def _merge_env_vars(env_dict: Optional[Dict[str, str]],
296
262
  return list(env_dict.items())
297
263
 
298
264
 
299
- def config_option(expose_value: bool):
300
- """A decorator for the --config option.
301
-
302
- This decorator is used to parse the --config option.
303
-
304
- Any overrides specified in the command line will be applied to the skypilot
305
- config before the decorated function is called.
306
-
307
- If expose_value is True, the decorated function will receive the parsed
308
- config overrides as 'config_override' parameter.
309
-
310
- Args:
311
- expose_value: Whether to expose the value of the option to the decorated
312
- function.
313
- """
314
-
315
- def preprocess_config_options(ctx, param, value):
316
- del ctx # Unused.
317
- param.name = 'config_override'
318
- try:
319
- if len(value) == 0:
320
- return None
321
- else:
322
- # Apply the config overrides to the skypilot config.
323
- return skypilot_config.apply_cli_config(value)
324
- except ValueError as e:
325
- raise click.BadParameter(f'{str(e)}') from e
326
-
327
- def return_option_decorator(func):
328
- return click.option(
329
- '--config',
330
- required=False,
331
- type=str,
332
- multiple=True,
333
- expose_value=expose_value,
334
- callback=preprocess_config_options,
335
- help=('Path to a config file or a comma-separated '
336
- 'list of key-value pairs '
337
- '(e.g. "nested.key1=val1,another.key2=val2").'),
338
- )(func)
339
-
340
- return return_option_decorator
341
-
342
-
343
- _COMMON_OPTIONS = [
344
- click.option('--async/--no-async',
345
- 'async_call',
346
- required=False,
347
- is_flag=True,
348
- default=False,
349
- help=('Run the command asynchronously.'))
350
- ]
351
-
352
- _TASK_OPTIONS = [
353
- click.option(
354
- '--workdir',
355
- required=False,
356
- type=click.Path(exists=True, file_okay=False),
357
- help=('If specified, sync this dir to the remote working directory, '
358
- 'where the task will be invoked. '
359
- 'Overrides the "workdir" config in the YAML if both are supplied.'
360
- )),
361
- click.option(
362
- '--infra',
363
- required=False,
364
- type=str,
365
- help='Infrastructure to use. '
366
- 'Format: cloud, cloud/region, cloud/region/zone, '
367
- 'k8s/context-name, or ssh/node-pool-name. '
368
- 'Examples: aws, aws/us-east-1, aws/us-east-1/us-east-1a, '
369
- # TODO(zhwu): we have to use `\*` to make sure the docs build
370
- # not complaining about the `*`, but this will cause `--help`
371
- # to show `\*` instead of `*`.
372
- 'aws/\\*/us-east-1a, k8s/my-context, ssh/my-nodes.'),
373
- click.option(
374
- '--cloud',
375
- required=False,
376
- type=str,
377
- help=('The cloud to use. If specified, overrides the "resources.cloud" '
378
- 'config. Passing "none" resets the config.'),
379
- hidden=True),
380
- click.option(
381
- '--region',
382
- required=False,
383
- type=str,
384
- help=('The region to use. If specified, overrides the '
385
- '"resources.region" config. Passing "none" resets the config.'),
386
- hidden=True),
387
- click.option(
388
- '--zone',
389
- required=False,
390
- type=str,
391
- help=('The zone to use. If specified, overrides the '
392
- '"resources.zone" config. Passing "none" resets the config.'),
393
- hidden=True),
394
- click.option(
395
- '--num-nodes',
396
- required=False,
397
- type=int,
398
- help=('Number of nodes to execute the task on. '
399
- 'Overrides the "num_nodes" config in the YAML if both are '
400
- 'supplied.')),
401
- click.option(
402
- '--cpus',
403
- default=None,
404
- type=str,
405
- required=False,
406
- help=('Number of vCPUs each instance must have (e.g., '
407
- '``--cpus=4`` (exactly 4) or ``--cpus=4+`` (at least 4)). '
408
- 'This is used to automatically select the instance type.')),
409
- click.option(
410
- '--memory',
411
- default=None,
412
- type=str,
413
- required=False,
414
- help=(
415
- 'Amount of memory each instance must have in GB (e.g., '
416
- '``--memory=16`` (exactly 16GB), ``--memory=16+`` (at least 16GB))'
417
- )),
418
- click.option('--disk-size',
419
- default=None,
420
- type=int,
421
- required=False,
422
- help=('OS disk size in GBs.')),
423
- click.option('--disk-tier',
424
- default=None,
425
- type=click.Choice(resources_utils.DiskTier.supported_tiers(),
426
- case_sensitive=False),
427
- required=False,
428
- help=resources_utils.DiskTier.cli_help_message()),
429
- click.option('--network-tier',
430
- default=None,
431
- type=click.Choice(
432
- resources_utils.NetworkTier.supported_tiers(),
433
- case_sensitive=False),
434
- required=False,
435
- help=resources_utils.NetworkTier.cli_help_message()),
436
- click.option(
437
- '--use-spot/--no-use-spot',
438
- required=False,
439
- default=None,
440
- help=('Whether to request spot instances. If specified, overrides the '
441
- '"resources.use_spot" config.')),
442
- click.option('--image-id',
443
- required=False,
444
- default=None,
445
- help=('Custom image id for launching the instances. '
446
- 'Passing "none" resets the config.')),
447
- click.option('--env-file',
448
- required=False,
449
- type=dotenv.dotenv_values,
450
- help="""\
451
- Path to a dotenv file with environment variables to set on the remote
452
- node.
453
-
454
- If any values from ``--env-file`` conflict with values set by
455
- ``--env``, the ``--env`` value will be preferred."""),
456
- click.option(
457
- '--env',
458
- required=False,
459
- type=_parse_env_var,
460
- multiple=True,
461
- help="""\
462
- Environment variable to set on the remote node.
463
- It can be specified multiple times.
464
- Examples:
465
-
466
- \b
467
- 1. ``--env MY_ENV=1``: set ``$MY_ENV`` on the cluster to be 1.
468
-
469
- 2. ``--env MY_ENV2=$HOME``: set ``$MY_ENV2`` on the cluster to be the
470
- same value of ``$HOME`` in the local environment where the CLI command
471
- is run.
472
-
473
- 3. ``--env MY_ENV3``: set ``$MY_ENV3`` on the cluster to be the
474
- same value of ``$MY_ENV3`` in the local environment.""",
475
- ),
476
- click.option(
477
- '--secret',
478
- required=False,
479
- type=_parse_secret_var,
480
- multiple=True,
481
- help="""\
482
- Secret variable to set on the remote node. These variables will be
483
- redacted in logs and YAML outputs for security. It can be specified
484
- multiple times. Examples:
485
-
486
- \b
487
- 1. ``--secret API_KEY=secret123``: set ``$API_KEY`` on the cluster to
488
- be secret123.
489
-
490
- 2. ``--secret JWT_SECRET``: set ``$JWT_SECRET`` on the cluster to be
491
- the same value of ``$JWT_SECRET`` in the local environment.""",
492
- )
493
- ]
494
- _TASK_OPTIONS_WITH_NAME = [
495
- click.option('--name',
496
- '-n',
497
- required=False,
498
- type=str,
499
- help=('Task name. Overrides the "name" '
500
- 'config in the YAML if both are supplied.')),
501
- ] + _TASK_OPTIONS
502
- _EXTRA_RESOURCES_OPTIONS = [
503
- click.option(
504
- '--gpus',
505
- required=False,
506
- type=str,
507
- help=
508
- ('Type and number of GPUs to use. Example values: '
509
- '"V100:8", "V100" (short for a count of 1), or "V100:0.5" '
510
- '(fractional counts are supported by the scheduling framework). '
511
- 'If a new cluster is being launched by this command, this is the '
512
- 'resources to provision. If an existing cluster is being reused, this'
513
- ' is seen as the task demand, which must fit the cluster\'s total '
514
- 'resources and is used for scheduling the task. '
515
- 'Overrides the "accelerators" '
516
- 'config in the YAML if both are supplied. '
517
- 'Passing "none" resets the config.')),
518
- click.option(
519
- '--instance-type',
520
- '-t',
521
- required=False,
522
- type=str,
523
- help=('The instance type to use. If specified, overrides the '
524
- '"resources.instance_type" config. Passing "none" resets the '
525
- 'config.'),
526
- ),
527
- click.option(
528
- '--ports',
529
- required=False,
530
- type=str,
531
- multiple=True,
532
- help=('Ports to open on the cluster. '
533
- 'If specified, overrides the "ports" config in the YAML. '),
534
- ),
535
- ]
536
-
537
-
538
265
  def _complete_cluster_name(ctx: click.Context, param: click.Parameter,
539
266
  incomplete: str) -> List[str]:
540
267
  """Handle shell completion for cluster names."""
@@ -1018,94 +745,6 @@ class _DocumentedCodeCommand(click.Command):
1018
745
  return super().get_help(ctx)
1019
746
 
1020
747
 
1021
- def _with_deprecation_warning(
1022
- f,
1023
- original_name: str,
1024
- alias_name: str,
1025
- override_command_argument: Optional[Dict[str, Any]] = None):
1026
-
1027
- @functools.wraps(f)
1028
- def wrapper(self, *args, **kwargs):
1029
- override_str = ''
1030
- if override_command_argument is not None:
1031
- overrides = []
1032
- for k, v in override_command_argument.items():
1033
- if isinstance(v, bool):
1034
- if v:
1035
- overrides.append(f'--{k}')
1036
- else:
1037
- overrides.append(f'--no-{k}')
1038
- else:
1039
- overrides.append(f'--{k.replace("_", "-")}={v}')
1040
- override_str = ' with additional arguments ' + ' '.join(overrides)
1041
- click.secho(
1042
- f'WARNING: `{alias_name}` has been renamed to `{original_name}` '
1043
- f'and will be removed in a future release. Please use the '
1044
- f'latter{override_str} instead.\n',
1045
- err=True,
1046
- fg='yellow')
1047
- return f(self, *args, **kwargs)
1048
-
1049
- return wrapper
1050
-
1051
-
1052
- def _override_arguments(callback, override_command_argument: Dict[str, Any]):
1053
-
1054
- def wrapper(*args, **kwargs):
1055
- logger.info(f'Overriding arguments: {override_command_argument}')
1056
- kwargs.update(override_command_argument)
1057
- return callback(*args, **kwargs)
1058
-
1059
- return wrapper
1060
-
1061
-
1062
- def _add_command_alias(
1063
- group: click.Group,
1064
- command: click.Command,
1065
- hidden: bool = False,
1066
- new_group: Optional[click.Group] = None,
1067
- new_command_name: Optional[str] = None,
1068
- override_command_argument: Optional[Dict[str, Any]] = None,
1069
- with_warning: bool = True,
1070
- ) -> None:
1071
- """Add a alias of a command to a group."""
1072
- if new_group is None:
1073
- new_group = group
1074
- if new_command_name is None:
1075
- new_command_name = command.name
1076
- if new_group == group and new_command_name == command.name:
1077
- raise ValueError('Cannot add an alias to the same command.')
1078
- new_command = copy.deepcopy(command)
1079
- new_command.hidden = hidden
1080
- new_command.name = new_command_name
1081
-
1082
- if override_command_argument:
1083
- new_command.callback = _override_arguments(new_command.callback,
1084
- override_command_argument)
1085
-
1086
- orig = f'sky {group.name} {command.name}'
1087
- alias = f'sky {new_group.name} {new_command_name}'
1088
- if with_warning:
1089
- new_command.invoke = _with_deprecation_warning(
1090
- new_command.invoke,
1091
- orig,
1092
- alias,
1093
- override_command_argument=override_command_argument)
1094
- new_group.add_command(new_command, name=new_command_name)
1095
-
1096
-
1097
- def _deprecate_and_hide_command(group, command_to_deprecate,
1098
- alternative_command):
1099
- """Hide a command and show a deprecation note, hinting the alternative."""
1100
- command_to_deprecate.hidden = True
1101
- if group is not None:
1102
- orig = f'sky {group.name} {command_to_deprecate.name}'
1103
- else:
1104
- orig = f'sky {command_to_deprecate.name}'
1105
- command_to_deprecate.invoke = _with_deprecation_warning(
1106
- command_to_deprecate.invoke, alternative_command, orig)
1107
-
1108
-
1109
748
  @click.group(cls=_NaturalOrderGroup, context_settings=_CONTEXT_SETTINGS)
1110
749
  @click.option('--install-shell-completion',
1111
750
  type=click.Choice(['bash', 'zsh', 'fish', 'auto']),
@@ -1159,7 +798,7 @@ def _handle_infra_cloud_region_zone_options(infra: Optional[str],
1159
798
 
1160
799
 
1161
800
  @cli.command(cls=_DocumentedCodeCommand)
1162
- @config_option(expose_value=True)
801
+ @flags.config_option(expose_value=True)
1163
802
  @click.argument('entrypoint',
1164
803
  required=False,
1165
804
  type=str,
@@ -1190,8 +829,8 @@ def _handle_infra_cloud_region_zone_options(infra: Optional[str],
1190
829
  help=('(Deprecated) Local docker support is deprecated. '
1191
830
  'To run locally, create a local Kubernetes cluster with '
1192
831
  '``sky local up``.'))
1193
- @_add_click_options(_TASK_OPTIONS_WITH_NAME + _EXTRA_RESOURCES_OPTIONS +
1194
- _COMMON_OPTIONS)
832
+ @_add_click_options(flags.TASK_OPTIONS_WITH_NAME +
833
+ flags.EXTRA_RESOURCES_OPTIONS + flags.COMMON_OPTIONS)
1195
834
  @click.option(
1196
835
  '--idle-minutes-to-autostop',
1197
836
  '-i',
@@ -1405,7 +1044,7 @@ def launch(
1405
1044
 
1406
1045
 
1407
1046
  @cli.command(cls=_DocumentedCodeCommand)
1408
- @config_option(expose_value=True)
1047
+ @flags.config_option(expose_value=True)
1409
1048
  @click.argument('cluster',
1410
1049
  required=False,
1411
1050
  type=str,
@@ -1430,8 +1069,8 @@ def launch(
1430
1069
  is_flag=True,
1431
1070
  help=('If True, as soon as a job is submitted, return from this call '
1432
1071
  'and do not stream execution logs.'))
1433
- @_add_click_options(_TASK_OPTIONS_WITH_NAME + _EXTRA_RESOURCES_OPTIONS +
1434
- _COMMON_OPTIONS)
1072
+ @_add_click_options(flags.TASK_OPTIONS_WITH_NAME +
1073
+ flags.EXTRA_RESOURCES_OPTIONS + flags.COMMON_OPTIONS)
1435
1074
  @usage_lib.entrypoint
1436
1075
  # pylint: disable=redefined-builtin
1437
1076
  def exec(cluster: Optional[str],
@@ -1854,13 +1493,8 @@ def _show_enabled_infra(active_workspace: str, show_workspace: bool):
1854
1493
 
1855
1494
 
1856
1495
  @cli.command()
1857
- @config_option(expose_value=False)
1858
- @click.option('--verbose',
1859
- '-v',
1860
- default=False,
1861
- is_flag=True,
1862
- required=False,
1863
- help='Show all information in full.')
1496
+ @flags.config_option(expose_value=False)
1497
+ @flags.verbose_option()
1864
1498
  @click.option(
1865
1499
  '--refresh',
1866
1500
  '-r',
@@ -1912,13 +1546,8 @@ def _show_enabled_infra(active_workspace: str, show_workspace: bool):
1912
1546
  type=str,
1913
1547
  nargs=-1,
1914
1548
  **_get_shell_complete_args(_complete_cluster_name))
1915
- @click.option('--all-users',
1916
- '-u',
1917
- default=False,
1918
- is_flag=True,
1919
- required=False,
1920
- help='Show all clusters, including those not owned by the '
1921
- 'current user.')
1549
+ @flags.all_users_option('Show all clusters, including those not owned by the '
1550
+ 'current user.')
1922
1551
  @usage_lib.entrypoint
1923
1552
  # pylint: disable=redefined-builtin
1924
1553
  def status(verbose: bool, refresh: bool, ip: bool, endpoints: bool,
@@ -2169,13 +1798,8 @@ def status(verbose: bool, refresh: bool, ip: bool, endpoints: bool,
2169
1798
 
2170
1799
 
2171
1800
  @cli.command()
2172
- @config_option(expose_value=False)
2173
- @click.option('--all',
2174
- '-a',
2175
- default=False,
2176
- is_flag=True,
2177
- required=False,
2178
- help='Show all cluster information.')
1801
+ @flags.config_option(expose_value=False)
1802
+ @flags.all_option('Show all cluster information.')
2179
1803
  @usage_lib.entrypoint
2180
1804
  def cost_report(all: bool): # pylint: disable=redefined-builtin
2181
1805
  # NOTE(dev): Keep the docstring consistent between the Python API and CLI.
@@ -2240,13 +1864,8 @@ def cost_report(all: bool): # pylint: disable=redefined-builtin
2240
1864
 
2241
1865
 
2242
1866
  @cli.command()
2243
- @config_option(expose_value=False)
2244
- @click.option('--all-users',
2245
- '-u',
2246
- default=False,
2247
- is_flag=True,
2248
- required=False,
2249
- help='Show all users\' information in full.')
1867
+ @flags.config_option(expose_value=False)
1868
+ @flags.all_users_option('Show all users\' information in full.')
2250
1869
  @click.option('--skip-finished',
2251
1870
  '-s',
2252
1871
  default=False,
@@ -2302,7 +1921,7 @@ def queue(clusters: List[str], skip_finished: bool, all_users: bool):
2302
1921
 
2303
1922
 
2304
1923
  @cli.command()
2305
- @config_option(expose_value=False)
1924
+ @flags.config_option(expose_value=False)
2306
1925
  @click.option(
2307
1926
  '--sync-down',
2308
1927
  '-s',
@@ -2440,31 +2059,16 @@ def logs(
2440
2059
 
2441
2060
 
2442
2061
  @cli.command()
2443
- @config_option(expose_value=False)
2062
+ @flags.config_option(expose_value=False)
2444
2063
  @click.argument('cluster',
2445
2064
  required=True,
2446
2065
  type=str,
2447
2066
  **_get_shell_complete_args(_complete_cluster_name))
2448
- @click.option('--all',
2449
- '-a',
2450
- default=False,
2451
- is_flag=True,
2452
- required=False,
2453
- help='Cancel all jobs from current user on the specified cluster.'
2454
- )
2455
- @click.option('--all-users',
2456
- '-u',
2457
- default=False,
2458
- is_flag=True,
2459
- required=False,
2460
- help='Cancel all jobs on the specified cluster for all users.')
2461
- @click.option('--yes',
2462
- '-y',
2463
- is_flag=True,
2464
- default=False,
2465
- required=False,
2466
- help='Skip confirmation prompt.')
2467
- @_add_click_options(_COMMON_OPTIONS)
2067
+ @flags.all_option('Cancel all jobs from current user on the specified cluster.')
2068
+ @flags.all_users_option(
2069
+ 'Cancel all jobs on the specified cluster for all users.')
2070
+ @flags.yes_option()
2071
+ @_add_click_options(flags.COMMON_OPTIONS)
2468
2072
  @click.argument('jobs', required=False, type=int, nargs=-1)
2469
2073
  @usage_lib.entrypoint
2470
2074
  def cancel(
@@ -2544,28 +2148,15 @@ def cancel(
2544
2148
 
2545
2149
 
2546
2150
  @cli.command(cls=_DocumentedCodeCommand)
2547
- @config_option(expose_value=False)
2151
+ @flags.config_option(expose_value=False)
2548
2152
  @click.argument('clusters',
2549
2153
  nargs=-1,
2550
2154
  required=False,
2551
2155
  **_get_shell_complete_args(_complete_cluster_name))
2552
- @click.option('--all',
2553
- '-a',
2554
- default=False,
2555
- is_flag=True,
2556
- help='Stop all existing clusters.')
2557
- @click.option('--all-users',
2558
- '-u',
2559
- default=False,
2560
- is_flag=True,
2561
- help='Stop all existing clusters for all users.')
2562
- @click.option('--yes',
2563
- '-y',
2564
- is_flag=True,
2565
- default=False,
2566
- required=False,
2567
- help='Skip confirmation prompt.')
2568
- @_add_click_options(_COMMON_OPTIONS)
2156
+ @flags.all_option('Stop all existing clusters.')
2157
+ @flags.all_users_option('Stop all existing clusters for all users.')
2158
+ @flags.yes_option()
2159
+ @_add_click_options(flags.COMMON_OPTIONS)
2569
2160
  @usage_lib.entrypoint
2570
2161
  def stop(
2571
2162
  clusters: List[str],
@@ -2612,21 +2203,13 @@ def stop(
2612
2203
 
2613
2204
 
2614
2205
  @cli.command(cls=_DocumentedCodeCommand)
2615
- @config_option(expose_value=False)
2206
+ @flags.config_option(expose_value=False)
2616
2207
  @click.argument('clusters',
2617
2208
  nargs=-1,
2618
2209
  required=False,
2619
2210
  **_get_shell_complete_args(_complete_cluster_name))
2620
- @click.option('--all',
2621
- '-a',
2622
- default=False,
2623
- is_flag=True,
2624
- help='Autostop all existing clusters.')
2625
- @click.option('--all-users',
2626
- '-u',
2627
- default=False,
2628
- is_flag=True,
2629
- help='Autostop all existing clusters for all users.')
2211
+ @flags.all_option('Autostop all existing clusters.')
2212
+ @flags.all_users_option('Autostop all existing clusters for all users.')
2630
2213
  @click.option('--idle-minutes',
2631
2214
  '-i',
2632
2215
  type=int,
@@ -2648,13 +2231,8 @@ def stop(
2648
2231
  required=False,
2649
2232
  help='Use autodown (tear down the cluster; non-restartable), instead '
2650
2233
  'of autostop (restartable).')
2651
- @click.option('--yes',
2652
- '-y',
2653
- is_flag=True,
2654
- default=False,
2655
- required=False,
2656
- help='Skip confirmation prompt.')
2657
- @_add_click_options(_COMMON_OPTIONS)
2234
+ @flags.yes_option()
2235
+ @_add_click_options(flags.COMMON_OPTIONS)
2658
2236
  @usage_lib.entrypoint
2659
2237
  def autostop(
2660
2238
  clusters: List[str],
@@ -2725,23 +2303,13 @@ def autostop(
2725
2303
 
2726
2304
 
2727
2305
  @cli.command(cls=_DocumentedCodeCommand)
2728
- @config_option(expose_value=False)
2306
+ @flags.config_option(expose_value=False)
2729
2307
  @click.argument('clusters',
2730
2308
  nargs=-1,
2731
2309
  required=False,
2732
2310
  **_get_shell_complete_args(_complete_cluster_name))
2733
- @click.option('--all',
2734
- '-a',
2735
- default=False,
2736
- is_flag=True,
2737
- required=False,
2738
- help='Start all existing clusters.')
2739
- @click.option('--yes',
2740
- '-y',
2741
- is_flag=True,
2742
- default=False,
2743
- required=False,
2744
- help='Skip confirmation prompt.')
2311
+ @flags.all_option('Start all existing clusters.')
2312
+ @flags.yes_option()
2745
2313
  @click.option(
2746
2314
  '--idle-minutes-to-autostop',
2747
2315
  '-i',
@@ -2785,7 +2353,7 @@ def autostop(
2785
2353
  required=False,
2786
2354
  help=('Force start the cluster even if it is already UP. Useful for '
2787
2355
  'upgrading the SkyPilot runtime on the cluster.'))
2788
- @_add_click_options(_COMMON_OPTIONS)
2356
+ @_add_click_options(flags.COMMON_OPTIONS)
2789
2357
  @usage_lib.entrypoint
2790
2358
  # pylint: disable=redefined-builtin
2791
2359
  def start(
@@ -2971,27 +2539,14 @@ def start(
2971
2539
 
2972
2540
 
2973
2541
  @cli.command(cls=_DocumentedCodeCommand)
2974
- @config_option(expose_value=False)
2542
+ @flags.config_option(expose_value=False)
2975
2543
  @click.argument('clusters',
2976
2544
  nargs=-1,
2977
2545
  required=False,
2978
2546
  **_get_shell_complete_args(_complete_cluster_name))
2979
- @click.option('--all',
2980
- '-a',
2981
- default=False,
2982
- is_flag=True,
2983
- help='Tear down all existing clusters.')
2984
- @click.option('--all-users',
2985
- '-u',
2986
- default=False,
2987
- is_flag=True,
2988
- help='Tear down all existing clusters for all users.')
2989
- @click.option('--yes',
2990
- '-y',
2991
- is_flag=True,
2992
- default=False,
2993
- required=False,
2994
- help='Skip confirmation prompt.')
2547
+ @flags.all_option('Tear down all existing clusters.')
2548
+ @flags.all_users_option('Tear down all existing clusters for all users.')
2549
+ @flags.yes_option()
2995
2550
  @click.option(
2996
2551
  '--purge',
2997
2552
  '-p',
@@ -3004,7 +2559,7 @@ def start(
3004
2559
  ' in certain manual troubleshooting scenarios; with it set, it is the'
3005
2560
  ' user\'s responsibility to ensure there are no leaked instances and '
3006
2561
  'related resources.'))
3007
- @_add_click_options(_COMMON_OPTIONS)
2562
+ @_add_click_options(flags.COMMON_OPTIONS)
3008
2563
  @usage_lib.entrypoint
3009
2564
  def down(
3010
2565
  clusters: List[str],
@@ -3410,13 +2965,9 @@ def _down_or_stop_clusters(
3410
2965
 
3411
2966
 
3412
2967
  @cli.command(cls=_DocumentedCodeCommand)
3413
- @config_option(expose_value=False)
2968
+ @flags.config_option(expose_value=False)
3414
2969
  @click.argument('infra_list', required=False, type=str, nargs=-1)
3415
- @click.option('--verbose',
3416
- '-v',
3417
- is_flag=True,
3418
- default=False,
3419
- help='Show the activated account for each cloud.')
2970
+ @flags.verbose_option('Show the activated account for each cloud.')
3420
2971
  @click.option(
3421
2972
  '--workspace',
3422
2973
  '-w',
@@ -3460,13 +3011,9 @@ def check(infra_list: Tuple[str],
3460
3011
 
3461
3012
 
3462
3013
  @cli.command()
3463
- @config_option(expose_value=False)
3014
+ @flags.config_option(expose_value=False)
3464
3015
  @click.argument('accelerator_str', required=False)
3465
- @click.option('--all',
3466
- '-a',
3467
- is_flag=True,
3468
- default=False,
3469
- help='Show details of all GPU/TPU/accelerator offerings.')
3016
+ @flags.all_option('Show details of all GPU/TPU/accelerator offerings.')
3470
3017
  @click.option('--infra',
3471
3018
  default=None,
3472
3019
  type=str,
@@ -4106,13 +3653,8 @@ def storage():
4106
3653
 
4107
3654
 
4108
3655
  @storage.command('ls', cls=_DocumentedCodeCommand)
4109
- @config_option(expose_value=False)
4110
- @click.option('--verbose',
4111
- '-v',
4112
- default=False,
4113
- is_flag=True,
4114
- required=False,
4115
- help='Show all information in full.')
3656
+ @flags.config_option(expose_value=False)
3657
+ @flags.verbose_option()
4116
3658
  @usage_lib.entrypoint
4117
3659
  # pylint: disable=redefined-builtin
4118
3660
  def storage_ls(verbose: bool):
@@ -4125,25 +3667,20 @@ def storage_ls(verbose: bool):
4125
3667
 
4126
3668
 
4127
3669
  @storage.command('delete', cls=_DocumentedCodeCommand)
4128
- @config_option(expose_value=False)
3670
+ @flags.config_option(expose_value=False)
4129
3671
  @click.argument('names',
4130
3672
  required=False,
4131
3673
  type=str,
4132
3674
  nargs=-1,
4133
3675
  **_get_shell_complete_args(_complete_storage_name))
4134
- @click.option('--all',
4135
- '-a',
4136
- default=False,
4137
- is_flag=True,
4138
- required=False,
4139
- help='Delete all storage objects.')
3676
+ @flags.all_option('Delete all storage objects.')
4140
3677
  @click.option('--yes',
4141
3678
  '-y',
4142
3679
  default=False,
4143
3680
  is_flag=True,
4144
3681
  required=False,
4145
3682
  help='Skip confirmation prompt.')
4146
- @_add_click_options(_COMMON_OPTIONS)
3683
+ @_add_click_options(flags.COMMON_OPTIONS)
4147
3684
  @usage_lib.entrypoint
4148
3685
  def storage_delete(names: List[str], all: bool, yes: bool, async_call: bool): # pylint: disable=redefined-builtin
4149
3686
  """Delete storage objects.
@@ -4206,15 +3743,15 @@ def jobs():
4206
3743
 
4207
3744
 
4208
3745
  @jobs.command('launch', cls=_DocumentedCodeCommand)
4209
- @config_option(expose_value=True)
3746
+ @flags.config_option(expose_value=True)
4210
3747
  @click.argument('entrypoint',
4211
3748
  required=True,
4212
3749
  type=str,
4213
3750
  nargs=-1,
4214
3751
  **_get_shell_complete_args(_complete_file_name))
4215
3752
  # TODO(zhwu): Add --dryrun option to test the launch command.
4216
- @_add_click_options(_TASK_OPTIONS_WITH_NAME + _EXTRA_RESOURCES_OPTIONS +
4217
- _COMMON_OPTIONS)
3753
+ @_add_click_options(flags.TASK_OPTIONS_WITH_NAME +
3754
+ flags.EXTRA_RESOURCES_OPTIONS + flags.COMMON_OPTIONS)
4218
3755
  @click.option('--cluster',
4219
3756
  '-c',
4220
3757
  default=None,
@@ -4226,11 +3763,13 @@ def jobs():
4226
3763
  type=str,
4227
3764
  help='Recovery strategy to use for managed jobs.')
4228
3765
  @click.option('--priority',
4229
- type=click.IntRange(0, 1000),
3766
+ type=click.IntRange(constants.MIN_PRIORITY,
3767
+ constants.MAX_PRIORITY),
4230
3768
  default=None,
4231
3769
  show_default=True,
4232
- help=('Job priority from 0 to 1000. A higher number is higher '
4233
- 'priority. Default is 500.'))
3770
+ help=f'Job priority from ({constants.MIN_PRIORITY} '
3771
+ f'to {constants.MAX_PRIORITY}). '
3772
+ f'Default: {constants.DEFAULT_PRIORITY}.')
4234
3773
  @click.option(
4235
3774
  '--detach-run',
4236
3775
  '-d',
@@ -4238,12 +3777,7 @@ def jobs():
4238
3777
  is_flag=True,
4239
3778
  help=('If True, as soon as a job is submitted, return from this call '
4240
3779
  'and do not stream execution logs.'))
4241
- @click.option('--yes',
4242
- '-y',
4243
- is_flag=True,
4244
- default=False,
4245
- required=False,
4246
- help='Skip confirmation prompt.')
3780
+ @flags.yes_option()
4247
3781
  @timeline.event
4248
3782
  @usage_lib.entrypoint
4249
3783
  def jobs_launch(
@@ -4358,13 +3892,8 @@ def jobs_launch(
4358
3892
 
4359
3893
 
4360
3894
  @jobs.command('queue', cls=_DocumentedCodeCommand)
4361
- @config_option(expose_value=False)
4362
- @click.option('--verbose',
4363
- '-v',
4364
- default=False,
4365
- is_flag=True,
4366
- required=False,
4367
- help='Show all information in full.')
3895
+ @flags.config_option(expose_value=False)
3896
+ @flags.verbose_option()
4368
3897
  @click.option(
4369
3898
  '--refresh',
4370
3899
  '-r',
@@ -4379,18 +3908,8 @@ def jobs_launch(
4379
3908
  is_flag=True,
4380
3909
  required=False,
4381
3910
  help='Show only pending/running jobs\' information.')
4382
- @click.option('--all-users',
4383
- '-u',
4384
- default=False,
4385
- is_flag=True,
4386
- required=False,
4387
- help='Show jobs from all users.')
4388
- @click.option('--all',
4389
- '-a',
4390
- default=False,
4391
- is_flag=True,
4392
- required=False,
4393
- help='Show all jobs.')
3911
+ @flags.all_users_option('Show jobs from all users.')
3912
+ @flags.all_option('Show all jobs.')
4394
3913
  @usage_lib.entrypoint
4395
3914
  # pylint: disable=redefined-builtin
4396
3915
  def jobs_queue(verbose: bool, refresh: bool, skip_finished: bool,
@@ -4473,31 +3992,16 @@ def jobs_queue(verbose: bool, refresh: bool, skip_finished: bool,
4473
3992
 
4474
3993
 
4475
3994
  @jobs.command('cancel', cls=_DocumentedCodeCommand)
4476
- @config_option(expose_value=False)
3995
+ @flags.config_option(expose_value=False)
4477
3996
  @click.option('--name',
4478
3997
  '-n',
4479
3998
  required=False,
4480
3999
  type=str,
4481
4000
  help='Managed job name to cancel.')
4482
4001
  @click.argument('job_ids', default=None, type=int, required=False, nargs=-1)
4483
- @click.option('--all',
4484
- '-a',
4485
- is_flag=True,
4486
- default=False,
4487
- required=False,
4488
- help='Cancel all managed jobs for the current user.')
4489
- @click.option('--yes',
4490
- '-y',
4491
- is_flag=True,
4492
- default=False,
4493
- required=False,
4494
- help='Skip confirmation prompt.')
4495
- @click.option('--all-users',
4496
- '-u',
4497
- is_flag=True,
4498
- default=False,
4499
- required=False,
4500
- help='Cancel all managed jobs from all users.')
4002
+ @flags.all_option('Cancel all managed jobs for the current user.')
4003
+ @flags.yes_option()
4004
+ @flags.all_users_option('Cancel all managed jobs from all users.')
4501
4005
  @usage_lib.entrypoint
4502
4006
  # pylint: disable=redefined-builtin
4503
4007
  def jobs_cancel(name: Optional[str], job_ids: Tuple[int], all: bool, yes: bool,
@@ -4549,7 +4053,7 @@ def jobs_cancel(name: Optional[str], job_ids: Tuple[int], all: bool, yes: bool,
4549
4053
 
4550
4054
 
4551
4055
  @jobs.command('logs', cls=_DocumentedCodeCommand)
4552
- @config_option(expose_value=False)
4056
+ @flags.config_option(expose_value=False)
4553
4057
  @click.option('--name',
4554
4058
  '-n',
4555
4059
  required=False,
@@ -4614,7 +4118,7 @@ def jobs_logs(name: Optional[str], job_id: Optional[int], follow: bool,
4614
4118
 
4615
4119
 
4616
4120
  @jobs.command('dashboard', cls=_DocumentedCodeCommand)
4617
- @config_option(expose_value=False)
4121
+ @flags.config_option(expose_value=False)
4618
4122
  @usage_lib.entrypoint
4619
4123
  def jobs_dashboard():
4620
4124
  """Opens a dashboard for managed jobs."""
@@ -4622,7 +4126,7 @@ def jobs_dashboard():
4622
4126
 
4623
4127
 
4624
4128
  @cli.command(cls=_DocumentedCodeCommand)
4625
- @config_option(expose_value=False)
4129
+ @flags.config_option(expose_value=False)
4626
4130
  @usage_lib.entrypoint
4627
4131
  def dashboard() -> None:
4628
4132
  """Starts the dashboard for skypilot."""
@@ -4756,7 +4260,7 @@ def _generate_task_with_service(
4756
4260
 
4757
4261
 
4758
4262
  @serve.command('up', cls=_DocumentedCodeCommand)
4759
- @config_option(expose_value=False)
4263
+ @flags.config_option(expose_value=False)
4760
4264
  @click.argument('service_yaml',
4761
4265
  required=True,
4762
4266
  type=str,
@@ -4768,13 +4272,9 @@ def _generate_task_with_service(
4768
4272
  type=str,
4769
4273
  help='A service name. Unique for each service. If not provided, '
4770
4274
  'a unique name is autogenerated.')
4771
- @_add_click_options(_TASK_OPTIONS + _EXTRA_RESOURCES_OPTIONS + _COMMON_OPTIONS)
4772
- @click.option('--yes',
4773
- '-y',
4774
- is_flag=True,
4775
- default=False,
4776
- required=False,
4777
- help='Skip confirmation prompt.')
4275
+ @_add_click_options(flags.TASK_OPTIONS + flags.EXTRA_RESOURCES_OPTIONS +
4276
+ flags.COMMON_OPTIONS)
4277
+ @flags.yes_option()
4778
4278
  @timeline.event
4779
4279
  @usage_lib.entrypoint
4780
4280
  def serve_up(
@@ -4875,14 +4375,15 @@ def serve_up(
4875
4375
  # TODO(MaoZiming): Expose mix replica traffic option to user.
4876
4376
  # Currently, we do not mix traffic from old and new replicas.
4877
4377
  @serve.command('update', cls=_DocumentedCodeCommand)
4878
- @config_option(expose_value=False)
4378
+ @flags.config_option(expose_value=False)
4879
4379
  @click.argument('service_name', required=True, type=str)
4880
4380
  @click.argument('service_yaml',
4881
4381
  required=True,
4882
4382
  type=str,
4883
4383
  nargs=-1,
4884
4384
  **_get_shell_complete_args(_complete_file_name))
4885
- @_add_click_options(_TASK_OPTIONS + _EXTRA_RESOURCES_OPTIONS + _COMMON_OPTIONS)
4385
+ @_add_click_options(flags.TASK_OPTIONS + flags.EXTRA_RESOURCES_OPTIONS +
4386
+ flags.COMMON_OPTIONS)
4886
4387
  @click.option('--mode',
4887
4388
  default=serve_lib.DEFAULT_UPDATE_MODE.value,
4888
4389
  type=click.Choice([m.value for m in serve_lib.UpdateMode],
@@ -4891,12 +4392,7 @@ def serve_up(
4891
4392
  help=('Update mode. If "rolling", SkyServe will update the '
4892
4393
  'service with rolling update. If "blue_green", SkyServe '
4893
4394
  'will update the service with blue-green update. '))
4894
- @click.option('--yes',
4895
- '-y',
4896
- is_flag=True,
4897
- default=False,
4898
- required=False,
4899
- help='Skip confirmation prompt.')
4395
+ @flags.yes_option()
4900
4396
  @timeline.event
4901
4397
  @usage_lib.entrypoint
4902
4398
  def serve_update(
@@ -4981,13 +4477,8 @@ def serve_update(
4981
4477
 
4982
4478
 
4983
4479
  @serve.command('status', cls=_DocumentedCodeCommand)
4984
- @config_option(expose_value=False)
4985
- @click.option('--verbose',
4986
- '-v',
4987
- default=False,
4988
- is_flag=True,
4989
- required=False,
4990
- help='Show all information in full.')
4480
+ @flags.config_option(expose_value=False)
4481
+ @flags.verbose_option()
4991
4482
  @click.option('--endpoint',
4992
4483
  default=False,
4993
4484
  is_flag=True,
@@ -5107,29 +4598,20 @@ def serve_status(verbose: bool, endpoint: bool, service_names: List[str]):
5107
4598
 
5108
4599
 
5109
4600
  @serve.command('down', cls=_DocumentedCodeCommand)
5110
- @config_option(expose_value=False)
4601
+ @flags.config_option(expose_value=False)
5111
4602
  @click.argument('service_names', required=False, type=str, nargs=-1)
5112
- @click.option('--all',
5113
- '-a',
5114
- default=False,
5115
- is_flag=True,
5116
- help='Tear down all services.')
4603
+ @flags.all_option('Tear down all services.')
5117
4604
  @click.option('--purge',
5118
4605
  '-p',
5119
4606
  default=False,
5120
4607
  is_flag=True,
5121
4608
  help='Tear down services in failed status.')
5122
- @click.option('--yes',
5123
- '-y',
5124
- is_flag=True,
5125
- default=False,
5126
- required=False,
5127
- help='Skip confirmation prompt.')
4609
+ @flags.yes_option()
5128
4610
  @click.option('--replica-id',
5129
4611
  default=None,
5130
4612
  type=int,
5131
4613
  help='Tear down a given replica')
5132
- @_add_click_options(_COMMON_OPTIONS)
4614
+ @_add_click_options(flags.COMMON_OPTIONS)
5133
4615
  @usage_lib.entrypoint
5134
4616
  # pylint: disable=redefined-builtin
5135
4617
  def serve_down(
@@ -5221,7 +4703,7 @@ def serve_down(
5221
4703
 
5222
4704
 
5223
4705
  @serve.command('logs', cls=_DocumentedCodeCommand)
5224
- @config_option(expose_value=False)
4706
+ @flags.config_option(expose_value=False)
5225
4707
  @click.option(
5226
4708
  '--follow/--no-follow',
5227
4709
  is_flag=True,
@@ -5401,8 +4883,8 @@ def local():
5401
4883
  help='Password for the ssh-user to execute sudo commands. '
5402
4884
  'Required only if passwordless sudo is not setup.')
5403
4885
  @local.command('up', cls=_DocumentedCodeCommand)
5404
- @config_option(expose_value=False)
5405
- @_add_click_options(_COMMON_OPTIONS)
4886
+ @flags.config_option(expose_value=False)
4887
+ @_add_click_options(flags.COMMON_OPTIONS)
5406
4888
  @usage_lib.entrypoint
5407
4889
  def local_up(gpus: bool, ips: str, ssh_user: str, ssh_key_path: str,
5408
4890
  cleanup: bool, context_name: Optional[str],
@@ -5457,8 +4939,8 @@ def local_up(gpus: bool, ips: str, ssh_user: str, ssh_key_path: str,
5457
4939
 
5458
4940
 
5459
4941
  @local.command('down', cls=_DocumentedCodeCommand)
5460
- @config_option(expose_value=False)
5461
- @_add_click_options(_COMMON_OPTIONS)
4942
+ @flags.config_option(expose_value=False)
4943
+ @_add_click_options(flags.COMMON_OPTIONS)
5462
4944
  @usage_lib.entrypoint
5463
4945
  def local_down(async_call: bool):
5464
4946
  """Deletes a local cluster."""
@@ -5521,7 +5003,7 @@ def api_stop():
5521
5003
 
5522
5004
 
5523
5005
  @api.command('logs', cls=_DocumentedCodeCommand)
5524
- @config_option(expose_value=False)
5006
+ @flags.config_option(expose_value=False)
5525
5007
  @click.argument('request_id', required=False, type=str)
5526
5008
  @click.option('--server-logs',
5527
5009
  is_flag=True,
@@ -5561,20 +5043,10 @@ def api_logs(request_id: Optional[str], server_logs: bool,
5561
5043
 
5562
5044
 
5563
5045
  @api.command('cancel', cls=_DocumentedCodeCommand)
5564
- @config_option(expose_value=False)
5046
+ @flags.config_option(expose_value=False)
5565
5047
  @click.argument('request_ids', required=False, type=str, nargs=-1)
5566
- @click.option('--all',
5567
- '-a',
5568
- is_flag=True,
5569
- default=False,
5570
- required=False,
5571
- help='Cancel all your requests.')
5572
- @click.option('--all-users',
5573
- '-u',
5574
- is_flag=True,
5575
- default=False,
5576
- required=False,
5577
- help='Cancel all requests from all users.')
5048
+ @flags.all_option('Cancel all your requests.')
5049
+ @flags.all_users_option('Cancel all requests from all users.')
5578
5050
  @usage_lib.entrypoint
5579
5051
  # pylint: disable=redefined-builtin
5580
5052
  def api_cancel(request_ids: Optional[List[str]], all: bool, all_users: bool):
@@ -5603,7 +5075,7 @@ def api_cancel(request_ids: Optional[List[str]], all: bool, all_users: bool):
5603
5075
 
5604
5076
 
5605
5077
  @api.command('status', cls=_DocumentedCodeCommand)
5606
- @config_option(expose_value=False)
5078
+ @flags.config_option(expose_value=False)
5607
5079
  @click.argument('request_ids', required=False, type=str, nargs=-1)
5608
5080
  @click.option('--all-status',
5609
5081
  '-a',
@@ -5611,12 +5083,7 @@ def api_cancel(request_ids: Optional[List[str]], all: bool, all_users: bool):
5611
5083
  default=False,
5612
5084
  required=False,
5613
5085
  help='Show requests of all statuses.')
5614
- @click.option('--verbose',
5615
- '-v',
5616
- is_flag=True,
5617
- default=False,
5618
- required=False,
5619
- help='Show more details.')
5086
+ @flags.verbose_option('Show more details.')
5620
5087
  @usage_lib.entrypoint
5621
5088
  # pylint: disable=redefined-builtin
5622
5089
  def api_status(request_ids: Optional[List[str]], all_status: bool,
@@ -5647,7 +5114,7 @@ def api_status(request_ids: Optional[List[str]], all_status: bool,
5647
5114
 
5648
5115
 
5649
5116
  @api.command('login', cls=_DocumentedCodeCommand)
5650
- @config_option(expose_value=False)
5117
+ @flags.config_option(expose_value=False)
5651
5118
  @click.option('--endpoint',
5652
5119
  '-e',
5653
5120
  required=False,
@@ -5663,7 +5130,7 @@ def api_login(endpoint: Optional[str], get_token: bool):
5663
5130
 
5664
5131
 
5665
5132
  @api.command('info', cls=_DocumentedCodeCommand)
5666
- @config_option(expose_value=False)
5133
+ @flags.config_option(expose_value=False)
5667
5134
  @usage_lib.entrypoint
5668
5135
  def api_info():
5669
5136
  """Shows the SkyPilot API server URL."""