2020from genelab .cli ._interactive import pick_task_interactively
2121from genelab .cli ._render import (
2222 render_cache ,
23- render_hint ,
23+ render_entry_info ,
24+ render_main_help ,
2425 render_registry ,
2526)
2627from genelab .cli ._scaffold import create_project_skeleton
@@ -67,23 +68,56 @@ class _RegistryKindArg(str, Enum):
6768)
6869
6970
71+ _RUN_FLAGS_HELP : Final [str ] = """\
72+ Shorthand flags rewritten into env overrides:
73+
74+ \b
75+ -v, --vis Enable the Genesis viewer (env.scene.vis=true).
76+ --gpu Use the GPU backend (env.scene.gpu=true).
77+ --steps N Run for N steps (env.scene.steps=N).
78+ --dt SECONDS Override the sim timestep (env.scene.dt=SECONDS).
79+ --a.b.c VALUE Set any dotted cfg path.
80+
81+ Runner flags (used when an RL runner is engaged):
82+
83+ \b
84+ --num_envs N Parallel environments.
85+ --agent KIND one of: zero, random, trained (play only).
86+ --checkpoint PATH Resume from a checkpoint.
87+ --seed N RNG seed.
88+ --log_dir PATH Override the log directory.
89+ --max_iterations N Cap training iterations (train only).
90+ --gpus N Distributed training across N GPUs (train only).
91+
92+ Use `genelab info TASK` to see the full overridable path list for a task.
93+ """
94+
95+
96+ _PLAY_HELP : Final [str ] = "Run a registered task.\n \n " + _RUN_FLAGS_HELP
97+ _TRAIN_HELP : Final [str ] = "Train a registered task when a runner exists.\n \n " + _RUN_FLAGS_HELP
98+
99+
70100app = typer .Typer (
71101 name = "genelab" ,
72- help = "Run registered GeneLab tasks." ,
102+ help = (
103+ "GeneLab — Genesis robot lab CLI.\n \n "
104+ "Run `genelab` with no arguments for a landing page with quickstart commands "
105+ "and a count of registered robots, envs, and tasks."
106+ ),
73107 no_args_is_help = False ,
74108 add_completion = False ,
75109 pretty_exceptions_enable = False ,
76- rich_markup_mode = None ,
110+ rich_markup_mode = "rich" ,
77111)
78112
79113project_app = typer .Typer (
80114 name = "project" ,
81- help = "Create and manage GeneLab projects." ,
115+ help = "Create and manage GeneLab extension projects." ,
82116 no_args_is_help = True ,
83117 pretty_exceptions_enable = False ,
84- rich_markup_mode = None ,
118+ rich_markup_mode = "rich" ,
85119)
86- app .add_typer (project_app , name = "project" )
120+ app .add_typer (project_app , name = "project" , rich_help_panel = "Project" )
87121
88122
89123def _version_callback (value : bool ) -> None :
@@ -109,33 +143,43 @@ def root_callback(
109143 typer .Option (
110144 "--import" ,
111145 metavar = "MODULE" ,
112- help = "Import a downstream extension module before dispatch (can be repeated )." ,
146+ help = "Import an extension module before dispatch (repeatable )." ,
113147 ),
114148 ] = None ,
115149 no_entry_points : Annotated [
116150 bool ,
117151 typer .Option (
118152 "--no-entry-points" ,
119- help = "Skip installed extensions from the genelab.extensions entry point group." ,
153+ help = "Skip installed entry points from the genelab.extensions group." ,
120154 ),
121155 ] = False ,
122156) -> None :
123157 _ = version # consumed by the eager callback
124- ctx . obj = _RootState (
158+ state = _RootState (
125159 extension_modules = list (extension_modules or []),
126160 no_entry_points = no_entry_points ,
127161 )
162+ ctx .obj = state
128163 if ctx .invoked_subcommand is None :
129- render_hint ()
164+ _load_extensions (state )
165+ render_main_help ()
130166
131167
132- @app .command ("cache" , help = "Create project-local simulation cache directories." )
168+ @app .command (
169+ "cache" ,
170+ help = "Create project-local simulation cache directories." ,
171+ rich_help_panel = "Utilities" ,
172+ )
133173def cache_cmd () -> None :
134174 ensure_project_cache ()
135175 render_cache (CACHE_DIR )
136176
137177
138- @app .command ("list" , help = "List registered robots, environments, or tasks." )
178+ @app .command (
179+ "list" ,
180+ help = "List registered robots, envs, or tasks." ,
181+ rich_help_panel = "Registry" ,
182+ )
139183def list_cmd (
140184 ctx : typer .Context ,
141185 kind : Annotated [
@@ -147,9 +191,29 @@ def list_cmd(
147191 render_registry (kind .value )
148192
149193
194+ @app .command (
195+ "info" ,
196+ help = "Show detail for one registered task, env, or robot." ,
197+ rich_help_panel = "Registry" ,
198+ )
199+ def info_cmd (
200+ ctx : typer .Context ,
201+ name : Annotated [
202+ str ,
203+ typer .Argument (
204+ metavar = "NAME" ,
205+ help = "Registered task, env, or robot name." ,
206+ ),
207+ ],
208+ ) -> None :
209+ _load_extensions (_state (ctx ))
210+ render_entry_info (name )
211+
212+
150213@app .command (
151214 "play" ,
152- help = "Run a registered task." ,
215+ help = _PLAY_HELP ,
216+ rich_help_panel = "Runtime" ,
153217 context_settings = {"allow_extra_args" : True , "ignore_unknown_options" : True },
154218)
155219def play_cmd (ctx : typer .Context ) -> None :
@@ -163,7 +227,8 @@ def play_cmd(ctx: typer.Context) -> None:
163227
164228@app .command (
165229 "train" ,
166- help = "Train a registered task when a runner exists." ,
230+ help = _TRAIN_HELP ,
231+ rich_help_panel = "Runtime" ,
167232 context_settings = {"allow_extra_args" : True , "ignore_unknown_options" : True },
168233)
169234def train_cmd (ctx : typer .Context ) -> None :
@@ -185,7 +250,7 @@ def project_new_cmd(
185250 typer .Option (
186251 "--path" ,
187252 "-p" ,
188- help = "Parent directory where the project directory is created." ,
253+ help = "Parent directory under which the project directory is created." ,
189254 ),
190255 ] = Path ("." ),
191256 package : Annotated [
0 commit comments