hud-python 0.4.21__py3-none-any.whl → 0.4.23__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.

Potentially problematic release.


This version of hud-python might be problematic. Click here for more details.

Files changed (63) hide show
  1. hud/agents/base.py +37 -37
  2. hud/agents/claude.py +11 -6
  3. hud/agents/grounded_openai.py +282 -0
  4. hud/agents/misc/response_agent.py +3 -2
  5. hud/agents/openai.py +2 -2
  6. hud/agents/openai_chat_generic.py +3 -1
  7. hud/agents/tests/test_client.py +6 -1
  8. hud/agents/tests/test_grounded_openai_agent.py +155 -0
  9. hud/cli/__init__.py +34 -24
  10. hud/cli/analyze.py +27 -26
  11. hud/cli/build.py +50 -46
  12. hud/cli/debug.py +7 -7
  13. hud/cli/dev.py +107 -99
  14. hud/cli/eval.py +33 -31
  15. hud/cli/hf.py +53 -53
  16. hud/cli/init.py +28 -28
  17. hud/cli/list_func.py +22 -22
  18. hud/cli/pull.py +36 -36
  19. hud/cli/push.py +76 -74
  20. hud/cli/remove.py +42 -40
  21. hud/cli/rl/__init__.py +2 -2
  22. hud/cli/rl/init.py +41 -41
  23. hud/cli/rl/pod.py +97 -91
  24. hud/cli/rl/ssh.py +42 -40
  25. hud/cli/rl/train.py +75 -73
  26. hud/cli/rl/utils.py +10 -10
  27. hud/cli/tests/test_analyze.py +1 -1
  28. hud/cli/tests/test_analyze_metadata.py +2 -2
  29. hud/cli/tests/test_pull.py +45 -45
  30. hud/cli/tests/test_push.py +31 -29
  31. hud/cli/tests/test_registry.py +15 -15
  32. hud/cli/utils/environment.py +11 -11
  33. hud/cli/utils/interactive.py +18 -18
  34. hud/cli/utils/logging.py +12 -12
  35. hud/cli/utils/metadata.py +12 -12
  36. hud/cli/utils/registry.py +5 -5
  37. hud/cli/utils/runner.py +23 -23
  38. hud/cli/utils/server.py +16 -16
  39. hud/settings.py +6 -0
  40. hud/shared/hints.py +7 -7
  41. hud/tools/executors/tests/test_base_executor.py +1 -1
  42. hud/tools/executors/xdo.py +1 -1
  43. hud/tools/grounding/__init__.py +13 -0
  44. hud/tools/grounding/config.py +54 -0
  45. hud/tools/grounding/grounded_tool.py +314 -0
  46. hud/tools/grounding/grounder.py +302 -0
  47. hud/tools/grounding/tests/__init__.py +1 -0
  48. hud/tools/grounding/tests/test_grounded_tool.py +196 -0
  49. hud/tools/tests/test_playwright_tool.py +1 -1
  50. hud/tools/tests/test_tools_init.py +1 -1
  51. hud/tools/tests/test_utils.py +2 -2
  52. hud/types.py +4 -4
  53. hud/utils/__init__.py +3 -3
  54. hud/utils/agent_factories.py +86 -0
  55. hud/utils/{design.py → hud_console.py} +39 -33
  56. hud/utils/pretty_errors.py +6 -6
  57. hud/utils/tests/test_version.py +1 -1
  58. hud/version.py +1 -1
  59. {hud_python-0.4.21.dist-info → hud_python-0.4.23.dist-info}/METADATA +3 -1
  60. {hud_python-0.4.21.dist-info → hud_python-0.4.23.dist-info}/RECORD +63 -54
  61. {hud_python-0.4.21.dist-info → hud_python-0.4.23.dist-info}/WHEEL +0 -0
  62. {hud_python-0.4.21.dist-info → hud_python-0.4.23.dist-info}/entry_points.txt +0 -0
  63. {hud_python-0.4.21.dist-info → hud_python-0.4.23.dist-info}/licenses/LICENSE +0 -0
hud/cli/pull.py CHANGED
@@ -12,7 +12,7 @@ import yaml
12
12
  from rich.table import Table
13
13
 
14
14
  from hud.settings import settings
15
- from hud.utils.design import HUDDesign
15
+ from hud.utils.hud_console import HUDConsole
16
16
 
17
17
  from .utils.registry import save_to_registry
18
18
 
@@ -115,8 +115,8 @@ def pull_environment(
115
115
  verbose: bool = False,
116
116
  ) -> None:
117
117
  """Pull HUD environment from registry."""
118
- design = HUDDesign()
119
- design.header("HUD Environment Pull")
118
+ hud_console = HUDConsole()
119
+ hud_console.header("HUD Environment Pull")
120
120
 
121
121
  # Two modes:
122
122
  # 1. Pull from lock file (recommended)
@@ -133,10 +133,10 @@ def pull_environment(
133
133
 
134
134
  lock_path = Path(lock_file) if lock_file else None
135
135
  if lock_path and not lock_path.exists():
136
- design.error(f"Lock file not found: {lock_file}")
136
+ hud_console.error(f"Lock file not found: {lock_file}")
137
137
  raise typer.Exit(1)
138
138
 
139
- design.info(f"Reading lock file: {lock_file}")
139
+ hud_console.info(f"Reading lock file: {lock_file}")
140
140
  if lock_path:
141
141
  with open(lock_path) as f:
142
142
  lock_data = yaml.safe_load(f)
@@ -149,29 +149,29 @@ def pull_environment(
149
149
  # Check if it's a simple org/name or org/name:tag format (no @sha256)
150
150
  if "/" in target and "@" not in target:
151
151
  # Looks like org/env reference, possibly with tag
152
- design.info(f"Checking HUD registry for: {target}")
152
+ hud_console.info(f"Checking HUD registry for: {target}")
153
153
 
154
154
  # Check for API key (not required for pulling, but good to inform)
155
155
  if not settings.api_key:
156
- design.info("No HUD API key set (pulling from public registry)")
156
+ hud_console.info("No HUD API key set (pulling from public registry)")
157
157
 
158
158
  lock_data = fetch_lock_from_registry(target)
159
159
 
160
160
  if lock_data:
161
- design.success("Found in HUD registry")
161
+ hud_console.success("Found in HUD registry")
162
162
  image_ref = lock_data.get("image", "")
163
163
  else:
164
164
  # Fall back to treating as Docker image
165
165
  if not settings.api_key:
166
- design.info(
166
+ hud_console.info(
167
167
  "Not found in HUD registry (try setting HUD_API_KEY for private environments)" # noqa: E501
168
168
  )
169
169
  else:
170
- design.info("Not found in HUD registry, treating as Docker image")
170
+ hud_console.info("Not found in HUD registry, treating as Docker image")
171
171
 
172
172
  # Try to get metadata from Docker registry
173
173
  if not lock_data:
174
- design.info(f"Fetching Docker metadata for: {image_ref}")
174
+ hud_console.info(f"Fetching Docker metadata for: {image_ref}")
175
175
  manifest = get_docker_manifest(image_ref)
176
176
 
177
177
  if manifest:
@@ -184,12 +184,12 @@ def pull_environment(
184
184
  lock_data["size"] = format_size(size)
185
185
 
186
186
  if verbose:
187
- design.info(
187
+ hud_console.info(
188
188
  f"Retrieved manifest (type: {manifest.get('mediaType', 'unknown')})"
189
189
  )
190
190
 
191
191
  # Display environment summary
192
- design.section_title("Environment Details")
192
+ hud_console.section_title("Environment Details")
193
193
 
194
194
  # Create summary table
195
195
  table = Table(show_header=False, box=None)
@@ -210,8 +210,8 @@ def pull_environment(
210
210
  # Minimal data from Docker manifest
211
211
  table.add_row("Source", "Docker Registry")
212
212
  if not yes:
213
- design.warning("Note: Limited metadata available from Docker registry.")
214
- design.info("For full environment details, use a lock file.\n")
213
+ hud_console.warning("Note: Limited metadata available from Docker registry.")
214
+ hud_console.info("For full environment details, use a lock file.\n")
215
215
  else:
216
216
  # Full lock file data
217
217
  if "build" in lock_data:
@@ -242,38 +242,38 @@ def pull_environment(
242
242
  table.add_row("Source", "Unknown")
243
243
 
244
244
  # Use design's console to maintain consistent output
245
- design.console.print(table)
245
+ hud_console.console.print(table)
246
246
 
247
247
  # Tool summary (show after table)
248
248
  if lock_data and "tools" in lock_data:
249
- design.section_title("Available Tools")
249
+ hud_console.section_title("Available Tools")
250
250
  for tool in lock_data["tools"]:
251
- design.info(f"• {tool['name']}: {tool['description']}")
251
+ hud_console.info(f"• {tool['name']}: {tool['description']}")
252
252
 
253
253
  # Show warnings if no metadata
254
254
  if not lock_data and not yes:
255
- design.warning("No metadata available for this image.")
256
- design.info("The image will be pulled without verification.")
255
+ hud_console.warning("No metadata available for this image.")
256
+ hud_console.info("The image will be pulled without verification.")
257
257
 
258
258
  # If verify only, stop here
259
259
  if verify_only:
260
- design.success("Verification complete")
260
+ hud_console.success("Verification complete")
261
261
  return
262
262
 
263
263
  # Ask for confirmation unless --yes
264
264
  if not yes:
265
- design.info("")
265
+ hud_console.info("")
266
266
  # Show simple name for confirmation, not the full digest
267
267
  if ":" in image_ref and "@" in image_ref:
268
268
  simple_name = image_ref.split("@")[0]
269
269
  else:
270
270
  simple_name = image_ref
271
271
  if not typer.confirm(f"Pull {simple_name}?"):
272
- design.info("Aborted")
272
+ hud_console.info("Aborted")
273
273
  raise typer.Exit(0)
274
274
 
275
275
  # Pull the image
276
- design.progress_message(f"Pulling {image_ref}...")
276
+ hud_console.progress_message(f"Pulling {image_ref}...")
277
277
 
278
278
  # Run docker pull with progress
279
279
  process = subprocess.Popen( # noqa: S603
@@ -287,12 +287,12 @@ def pull_environment(
287
287
 
288
288
  for line in process.stdout or []:
289
289
  if verbose or "Downloading" in line or "Extracting" in line or "Pull complete" in line:
290
- design.info(line.rstrip())
290
+ hud_console.info(line.rstrip())
291
291
 
292
292
  process.wait()
293
293
 
294
294
  if process.returncode != 0:
295
- design.error("Pull failed")
295
+ hud_console.error("Pull failed")
296
296
  raise typer.Exit(1)
297
297
 
298
298
  # Store lock file locally if we have full lock data (not minimal manifest data)
@@ -301,22 +301,22 @@ def pull_environment(
301
301
  save_to_registry(lock_data, image_ref, verbose)
302
302
 
303
303
  # Success!
304
- design.success("Pull complete!")
304
+ hud_console.success("Pull complete!")
305
305
 
306
306
  # Show usage
307
- design.section_title("Next Steps")
307
+ hud_console.section_title("Next Steps")
308
308
 
309
309
  # Extract simple name for examples
310
310
  simple_ref = image_ref.split("@")[0] if ":" in image_ref and "@" in image_ref else image_ref
311
311
 
312
- design.info("1. Quick analysis (from metadata):")
313
- design.command_example(f"hud analyze {simple_ref}")
314
- design.info("")
315
- design.info("2. Live analysis (runs container):")
316
- design.command_example(f"hud analyze {simple_ref} --live")
317
- design.info("")
318
- design.info("3. Run the environment:")
319
- design.command_example(f"hud run {simple_ref}")
312
+ hud_console.info("1. Quick analysis (from metadata):")
313
+ hud_console.command_example(f"hud analyze {simple_ref}")
314
+ hud_console.info("")
315
+ hud_console.info("2. Live analysis (runs container):")
316
+ hud_console.command_example(f"hud analyze {simple_ref} --live")
317
+ hud_console.info("")
318
+ hud_console.info("3. Run the environment:")
319
+ hud_console.command_example(f"hud run {simple_ref}")
320
320
 
321
321
 
322
322
  def pull_command(
hud/cli/push.py CHANGED
@@ -11,7 +11,7 @@ import requests
11
11
  import typer
12
12
  import yaml
13
13
 
14
- from hud.utils.design import HUDDesign
14
+ from hud.utils.hud_console import HUDConsole
15
15
 
16
16
 
17
17
  def _get_response_text(response: requests.Response) -> str:
@@ -123,8 +123,8 @@ def push_environment(
123
123
  verbose: bool = False,
124
124
  ) -> None:
125
125
  """Push HUD environment to registry."""
126
- design = HUDDesign()
127
- design.header("HUD Environment Push")
126
+ hud_console = HUDConsole()
127
+ hud_console.header("HUD Environment Push")
128
128
 
129
129
  # Import settings lazily after any environment setup
130
130
  from hud.settings import settings
@@ -134,19 +134,19 @@ def push_environment(
134
134
  lock_path = env_dir / "hud.lock.yaml"
135
135
 
136
136
  if not lock_path.exists():
137
- design.error(f"No hud.lock.yaml found in {directory}")
138
- design.info("Run 'hud build' first to generate a lock file")
137
+ hud_console.error(f"No hud.lock.yaml found in {directory}")
138
+ hud_console.info("Run 'hud build' first to generate a lock file")
139
139
  raise typer.Exit(1)
140
140
 
141
141
  # Check for API key first
142
142
  if not settings.api_key:
143
- design.error("No HUD API key found")
144
- design.warning("A HUD API key is required to push environments.")
145
- design.info("\nTo get started:")
146
- design.info("1. Get your API key at: https://hud.so/settings")
147
- design.command_example("export HUD_API_KEY=your-key-here", "Set your API key")
148
- design.command_example("hud push", "Try again")
149
- design.info("")
143
+ hud_console.error("No HUD API key found")
144
+ hud_console.warning("A HUD API key is required to push environments.")
145
+ hud_console.info("\nTo get started:")
146
+ hud_console.info("1. Get your API key at: https://hud.so/settings")
147
+ hud_console.command_example("export HUD_API_KEY=your-key-here", "Set your API key")
148
+ hud_console.command_example("hud push", "Try again")
149
+ hud_console.info("")
150
150
  raise typer.Exit(1)
151
151
 
152
152
  # Load lock file
@@ -184,24 +184,24 @@ def push_environment(
184
184
  # Use provided tag, or internal version, or current tag as fallback
185
185
  if tag:
186
186
  final_tag = tag
187
- design.info(f"Using specified tag: {tag}")
187
+ hud_console.info(f"Using specified tag: {tag}")
188
188
  elif internal_version:
189
189
  final_tag = internal_version
190
- design.info(f"Using internal version from lock file: {internal_version}")
190
+ hud_console.info(f"Using internal version from lock file: {internal_version}")
191
191
  else:
192
192
  final_tag = current_tag
193
- design.info(f"Using current tag: {current_tag}")
193
+ hud_console.info(f"Using current tag: {current_tag}")
194
194
 
195
195
  # Suggest a registry image
196
196
  image = f"{username}/{base_name}:{final_tag}"
197
- design.info(f"Auto-detected Docker username: {username}")
198
- design.info(f"Will push to: {image}")
197
+ hud_console.info(f"Auto-detected Docker username: {username}")
198
+ hud_console.info(f"Will push to: {image}")
199
199
 
200
200
  if not yes and not typer.confirm(f"\nPush to {image}?"):
201
- design.info("Aborted.")
201
+ hud_console.info("Aborted.")
202
202
  raise typer.Exit(0)
203
203
  else:
204
- design.error(
204
+ hud_console.error(
205
205
  "Not logged in to Docker Hub. Please specify --image or run 'docker login'"
206
206
  )
207
207
  raise typer.Exit(1)
@@ -215,11 +215,11 @@ def push_environment(
215
215
  existing_tag = image.split(":")[-1]
216
216
  if existing_tag != final_tag:
217
217
  if tag:
218
- design.warning(
218
+ hud_console.warning(
219
219
  f"Image already has tag '{existing_tag}', overriding with '{final_tag}'"
220
220
  )
221
221
  else:
222
- design.info(
222
+ hud_console.info(
223
223
  f"Image has tag '{existing_tag}', but using internal version '{final_tag}'"
224
224
  )
225
225
  image = image.rsplit(":", 1)[0] + f":{final_tag}"
@@ -229,10 +229,10 @@ def push_environment(
229
229
  image = f"{image}:{final_tag}"
230
230
 
231
231
  if tag:
232
- design.info(f"Using specified tag: {tag}")
232
+ hud_console.info(f"Using specified tag: {tag}")
233
233
  else:
234
- design.info(f"Using internal version from lock file: {internal_version}")
235
- design.info(f"Will push to: {image}")
234
+ hud_console.info(f"Using internal version from lock file: {internal_version}")
235
+ hud_console.info(f"Will push to: {image}")
236
236
 
237
237
  # Verify local image exists
238
238
  # Extract the tag part (before @sha256:...) for Docker operations
@@ -250,7 +250,7 @@ def push_environment(
250
250
  try:
251
251
  subprocess.run(["docker", "inspect", version_tag], capture_output=True, check=True) # noqa: S603, S607
252
252
  image_to_push = version_tag
253
- design.info(f"Found version-tagged image: {version_tag}")
253
+ hud_console.info(f"Found version-tagged image: {version_tag}")
254
254
  except subprocess.CalledProcessError:
255
255
  pass
256
256
 
@@ -259,10 +259,10 @@ def push_environment(
259
259
  subprocess.run(["docker", "inspect", local_tag], capture_output=True, check=True) # noqa: S603, S607
260
260
  image_to_push = local_tag
261
261
  except subprocess.CalledProcessError:
262
- design.error(f"Local image not found: {local_tag}")
262
+ hud_console.error(f"Local image not found: {local_tag}")
263
263
  if version_tag:
264
- design.error(f"Also tried: {version_tag}")
265
- design.info("Run 'hud build' first to create the image")
264
+ hud_console.error(f"Also tried: {version_tag}")
265
+ hud_console.info("Run 'hud build' first to create the image")
266
266
  raise typer.Exit(1) # noqa: B904
267
267
 
268
268
  # Check if local image has the expected label
@@ -273,16 +273,16 @@ def push_environment(
273
273
  # Skip hash verification - the lock file may have been updated with digest after build
274
274
  if verbose:
275
275
  if expected_label:
276
- design.info(f"Image label: {expected_label[:12]}...")
276
+ hud_console.info(f"Image label: {expected_label[:12]}...")
277
277
  if version_label:
278
- design.info(f"Version label: {version_label}")
278
+ hud_console.info(f"Version label: {version_label}")
279
279
 
280
280
  # Tag the image for push
281
- design.progress_message(f"Tagging {image_to_push} as {image}")
281
+ hud_console.progress_message(f"Tagging {image_to_push} as {image}")
282
282
  subprocess.run(["docker", "tag", image_to_push, image], check=True) # noqa: S603, S607
283
283
 
284
284
  # Push the image
285
- design.progress_message(f"Pushing {image} to registry...")
285
+ hud_console.progress_message(f"Pushing {image} to registry...")
286
286
 
287
287
  # Show push output
288
288
  process = subprocess.Popen( # noqa: S603
@@ -295,12 +295,12 @@ def push_environment(
295
295
  )
296
296
 
297
297
  for line in process.stdout or []:
298
- design.info(line.rstrip())
298
+ hud_console.info(line.rstrip())
299
299
 
300
300
  process.wait()
301
301
 
302
302
  if process.returncode != 0:
303
- design.error("Push failed")
303
+ hud_console.error("Push failed")
304
304
  raise typer.Exit(1)
305
305
 
306
306
  # Get the digest of the pushed image
@@ -316,11 +316,11 @@ def push_environment(
316
316
  pushed_digest = image
317
317
 
318
318
  # Success!
319
- design.success("Push complete!")
319
+ hud_console.success("Push complete!")
320
320
 
321
321
  # Show the final image reference
322
- design.section_title("Pushed Image")
323
- design.status_item("Registry", pushed_digest, primary=True)
322
+ hud_console.section_title("Pushed Image")
323
+ hud_console.status_item("Registry", pushed_digest, primary=True)
324
324
 
325
325
  # Update the lock file with registry information
326
326
  lock_data["image"] = pushed_digest
@@ -338,7 +338,7 @@ def push_environment(
338
338
  with open(lock_path, "w") as f:
339
339
  yaml.dump(lock_data, f, default_flow_style=False, sort_keys=False)
340
340
 
341
- design.success("Updated lock file with registry image")
341
+ hud_console.success("Updated lock file with registry image")
342
342
 
343
343
  # Upload lock file to HUD registry
344
344
  try:
@@ -376,19 +376,19 @@ def push_environment(
376
376
 
377
377
  # Validate the image format
378
378
  if not name_with_tag:
379
- design.warning("Could not determine image name for registry upload")
379
+ hud_console.warning("Could not determine image name for registry upload")
380
380
  raise typer.Exit(0)
381
381
 
382
382
  # For HUD registry, we need org/name format
383
383
  if "/" not in name_with_tag:
384
- design.warning("Image name must include organization/namespace for HUD registry")
385
- design.info(f"Current format: {name_with_tag}")
386
- design.info("Expected format: org/name:tag (e.g., hudpython/myenv:v1.0)")
387
- design.info("\nYour Docker push succeeded - share hud.lock.yaml manually")
384
+ hud_console.warning("Image name must include organization/namespace for HUD registry")
385
+ hud_console.info(f"Current format: {name_with_tag}")
386
+ hud_console.info("Expected format: org/name:tag (e.g., hudpython/myenv:v1.0)")
387
+ hud_console.info("\nYour Docker push succeeded - share hud.lock.yaml manually")
388
388
  raise typer.Exit(0)
389
389
 
390
390
  # Upload to HUD registry
391
- design.progress_message("Uploading metadata to HUD registry...")
391
+ hud_console.progress_message("Uploading metadata to HUD registry...")
392
392
 
393
393
  # URL-encode the path segments to handle special characters in tags
394
394
  url_safe_path = "/".join(quote(part, safe="") for part in name_with_tag.split("/"))
@@ -405,48 +405,50 @@ def push_environment(
405
405
  response = requests.post(registry_url, json=payload, headers=headers, timeout=10)
406
406
 
407
407
  if response.status_code in [200, 201]:
408
- design.success("Metadata uploaded to HUD registry")
409
- design.info("Others can now pull with:")
410
- design.command_example(f"hud pull {name_with_tag}")
411
- design.info("")
408
+ hud_console.success("Metadata uploaded to HUD registry")
409
+ hud_console.info("Others can now pull with:")
410
+ hud_console.command_example(f"hud pull {name_with_tag}")
411
+ hud_console.info("")
412
412
  elif response.status_code == 401:
413
- design.error("Authentication failed")
414
- design.info("Check your HUD_API_KEY is valid")
415
- design.info("Get a new key at: https://hud.so/settings")
413
+ hud_console.error("Authentication failed")
414
+ hud_console.info("Check your HUD_API_KEY is valid")
415
+ hud_console.info("Get a new key at: https://hud.so/settings")
416
416
  elif response.status_code == 403:
417
- design.error("Permission denied")
418
- design.info("You may not have access to push to this namespace")
417
+ hud_console.error("Permission denied")
418
+ hud_console.info("You may not have access to push to this namespace")
419
419
  elif response.status_code == 409:
420
- design.warning("This version already exists in the registry")
421
- design.info("Consider using a different tag if you want to update")
420
+ hud_console.warning("This version already exists in the registry")
421
+ hud_console.info("Consider using a different tag if you want to update")
422
422
  else:
423
- design.warning(f"Could not upload to registry: {response.status_code}")
424
- design.warning(_get_response_text(response))
425
- design.info("Share hud.lock.yaml manually\n")
423
+ hud_console.warning(f"Could not upload to registry: {response.status_code}")
424
+ hud_console.warning(_get_response_text(response))
425
+ hud_console.info("Share hud.lock.yaml manually\n")
426
426
  except requests.exceptions.Timeout:
427
- design.warning("Registry upload timed out")
428
- design.info("The registry might be slow or unavailable")
429
- design.info("Your Docker push succeeded - share hud.lock.yaml manually")
427
+ hud_console.warning("Registry upload timed out")
428
+ hud_console.info("The registry might be slow or unavailable")
429
+ hud_console.info("Your Docker push succeeded - share hud.lock.yaml manually")
430
430
  except requests.exceptions.ConnectionError:
431
- design.warning("Could not connect to HUD registry")
432
- design.info("Check your internet connection")
433
- design.info("Your Docker push succeeded - share hud.lock.yaml manually")
431
+ hud_console.warning("Could not connect to HUD registry")
432
+ hud_console.info("Check your internet connection")
433
+ hud_console.info("Your Docker push succeeded - share hud.lock.yaml manually")
434
434
  except Exception as e:
435
- design.warning(f"Registry upload failed: {e}")
436
- design.info("Share hud.lock.yaml manually")
435
+ hud_console.warning(f"Registry upload failed: {e}")
436
+ hud_console.info("Share hud.lock.yaml manually")
437
437
 
438
438
  # Show usage examples
439
- design.section_title("What's Next?")
440
-
441
- design.info("Test locally:")
442
- design.command_example(f"hud run {image}")
443
- design.info("")
444
- design.info("Share environment:")
445
- design.info(" Share the updated hud.lock.yaml for others to reproduce your exact environment")
439
+ hud_console.section_title("What's Next?")
440
+
441
+ hud_console.info("Test locally:")
442
+ hud_console.command_example(f"hud run {image}")
443
+ hud_console.info("")
444
+ hud_console.info("Share environment:")
445
+ hud_console.info(
446
+ " Share the updated hud.lock.yaml for others to reproduce your exact environment"
447
+ )
446
448
 
447
449
  # TODO: Upload lock file to HUD registry
448
450
  if sign:
449
- design.warning("Signing not yet implemented")
451
+ hud_console.warning("Signing not yet implemented")
450
452
 
451
453
 
452
454
  def push_command(