Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/prime_cli/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ def post(self, endpoint: str, json: Optional[Dict[str, Any]] = None) -> Dict[str
"""Make a POST request to the API"""
return self.request("POST", endpoint, json=json)

def patch(self, endpoint: str, json: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""Make a PATCH request to the API"""
return self.request("PATCH", endpoint, json=json)

def delete(self, endpoint: str) -> Dict[str, Any]:
"""Make a DELETE request to the API"""
return self.request("DELETE", endpoint)
Expand Down Expand Up @@ -216,6 +220,10 @@ async def post(self, endpoint: str, json: Optional[Dict[str, Any]] = None) -> Di
"""Make an async POST request to the API"""
return await self.request("POST", endpoint, json=json)

async def patch(self, endpoint: str, json: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""Make an async PATCH request to the API"""
return await self.request("PATCH", endpoint, json=json)

async def delete(self, endpoint: str) -> Dict[str, Any]:
"""Make an async DELETE request to the API"""
return await self.request("DELETE", endpoint)
Expand Down
86 changes: 82 additions & 4 deletions src/prime_cli/commands/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,87 @@ def push(
f"{owner_info['name']}/{env_name}[/green]"
)
except APIError as e:
console.print(f"[red]Failed to resolve environment: {e}[/red]")
raise typer.Exit(1)
# Handle missing username (slug) by prompting user to set it and retrying
err_msg = str(e)
if "missing a username" in err_msg.lower():
console.print(
"[yellow]Your user profile is missing a username.[/yellow] "
"You must choose a username to publish environments."
)
console.print(
"[dim]Note: This username can only be chosen once and will be public.[/dim]"
)

while True:
try:
chosen = (
typer.prompt(
"Enter your desired username",
)
.strip()
.lower()
)
except typer.Abort:
console.print("[red]Cancelled by user[/red]")
raise typer.Exit(1)

if not chosen:
console.print("[red]Username cannot be empty[/red]")
continue

if not re.match(r"^[a-z0-9-]{3,30}$", chosen):
console.print(
"[red]Invalid username.[/red] "
"Use 3-30 chars with lowercase letters, numbers, and '-' only."
)
continue

try:
client.patch("/user/slug", json={"slug": chosen})
console.print(f"[green]✓ Username set to {chosen}[/green]")
break
except APIError as se:
se_msg = str(se)
if "409" in se_msg or "already taken" in se_msg.lower():
console.print(
"[red]That username is already taken.[/red] "
"Please choose another."
)
continue
else:
console.print(f"[red]Failed to set username: {se}[/red]")
raise typer.Exit(1)

# Retry resolve after setting username
try:
response = client.post("/environmentshub/resolve", json=resolve_data)

if "data" in response:
resolve_response = response["data"]
else:
resolve_response = response

env_id = resolve_response["id"]
owner_info = resolve_response["owner"]

if resolve_response["created"]:
console.print(
f"[green]✓ Created environment: {owner_info['name']}/"
f"{env_name}[/green]"
)
else:
console.print(
f"[green]✓ Found existing environment: "
f"{owner_info['name']}/{env_name}[/green]"
)
except APIError as e2:
console.print(
f"[red]Failed to resolve environment after setting username: {e2}[/red]"
)
raise typer.Exit(1)
else:
console.print(f"[red]Failed to resolve environment: {e}[/red]")
raise typer.Exit(1)

console.print("Uploading wheel ...")

Expand Down Expand Up @@ -1608,8 +1687,7 @@ def eval_env(
else:
if not inference_base_url:
console.print(
"[red]Inference URL not configured.[/red] "
"Check [bold]prime config view[/bold]."
"[red]Inference URL not configured.[/red] Check [bold]prime config view[/bold]."
)
raise typer.Exit(1)
chosen_base = inference_base_url.rstrip("/")
Expand Down