q81801/agent
0
1Set-StrictMode -Version Latest2$ErrorActionPreference = "Stop"3 4$script_dir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }5$repo_root = (Resolve-Path (Join-Path $script_dir "..")).Path6$hf_token_file = if ($env:HF_TOKEN_FILE) { $env:HF_TOKEN_FILE } else { Join-Path $HOME ".cache/huggingface/token" }7$script:RestoreHfLoginRequired = $false8$script:RestoreHfLoginToken = ""9$script:RestoreHfLoginUsername = ""10 11function Trim-Value {12 param([AllowNull()][string]$Value)13 14 if ($null -eq $Value) {15 return ""16 }17 return $Value.Trim()18}19 20function Write-Info {21 param([string]$Message)22 23 Write-Host $Message24}25 26$script:BootstrapStepIndex = 027 28function Get-LogTimestamp {29 return (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")30}31 32function Write-StepStart {33 param([string]$Message)34 35 $script:BootstrapStepIndex += 136 Write-Info ("[{0}] [bootstrap step {1}] START {2}" -f (Get-LogTimestamp), $script:BootstrapStepIndex, $Message)37}38 39function Write-StepDone {40 param([string]$Message)41 42 Write-Info ("[{0}] [bootstrap step {1}] DONE {2}" -f (Get-LogTimestamp), $script:BootstrapStepIndex, $Message)43}44 45function Invoke-Step {46 param(47 [string]$Message,48 [ScriptBlock]$Action49 )50 51 Write-StepStart -Message $Message52 & $Action53 Write-StepDone -Message $Message54}55 56function Fail {57 param([string]$Message)58 59 throw $Message60}61 62function Prompt-Line {63 param(64 [string]$Prompt,65 [string]$DefaultValue = ""66 )67 68 if ([string]::IsNullOrEmpty($DefaultValue)) {69 $raw = Read-Host -Prompt $Prompt70 } else {71 $raw = Read-Host -Prompt "$Prompt [$DefaultValue]"72 }73 74 $value = Trim-Value $raw75 if ([string]::IsNullOrEmpty($value)) {76 $value = $DefaultValue77 }78 return $value79}80 81function Prompt-Required {82 param(83 [string]$Prompt,84 [string]$DefaultValue = ""85 )86 87 while ($true) {88 $value = Trim-Value (Prompt-Line -Prompt $Prompt -DefaultValue $DefaultValue)89 if (-not [string]::IsNullOrEmpty($value)) {90 return $value91 }92 Write-Host "This value is required." -ForegroundColor Red93 }94}95 96function Convert-SecureStringToPlainText {97 param([System.Security.SecureString]$SecureValue)98 99 if ($null -eq $SecureValue) {100 return ""101 }102 103 $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureValue)104 try {105 return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)106 }107 finally {108 [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)109 }110}111 112function Prompt-SecretOptional {113 param([string]$Prompt)114 115 $secure_value = Read-Host -Prompt $Prompt -AsSecureString116 $plain_text = Convert-SecureStringToPlainText -SecureValue $secure_value117 return Trim-Value $plain_text118}119 120function Prompt-SecretRequired {121 param([string]$Prompt)122 123 while ($true) {124 $value = Trim-Value (Prompt-SecretOptional -Prompt $Prompt)125 if (-not [string]::IsNullOrEmpty($value)) {126 return $value127 }128 Write-Host "This value is required." -ForegroundColor Red129 }130}131 132function Prompt-YesNo {133 param(134 [string]$Prompt,135 [ValidateSet("y", "n")][string]$DefaultValue = "n"136 )137 138 $hint = if ($DefaultValue -eq "y") { "[Y/n]" } else { "[y/N]" }139 140 while ($true) {141 $answer = Trim-Value (Read-Host -Prompt "$Prompt $hint")142 $answer = $answer.ToLowerInvariant()143 if ([string]::IsNullOrEmpty($answer)) {144 $answer = $DefaultValue145 }146 147 switch ($answer) {148 { $_ -in @("y", "yes") } { return "yes" }149 { $_ -in @("n", "no") } { return "no" }150 default {151 Write-Host "Please enter y or n." -ForegroundColor Red152 }153 }154 }155}156 157function Login-WithHfToken {158 param([string]$Token)159 160 & hf auth login --token $Token *> $null161 if ($LASTEXITCODE -ne 0) {162 Fail "hf auth login with token failed."163 }164}165 166function Restore-PreviousHfLoginIfNeeded {167 if (-not $script:RestoreHfLoginRequired) {168 return169 }170 if ([string]::IsNullOrEmpty($script:RestoreHfLoginToken)) {171 Write-Error "Skip restoring previous HF login because backup token is empty."172 $script:RestoreHfLoginRequired = $false173 return174 }175 176 $display_user = if ([string]::IsNullOrEmpty($script:RestoreHfLoginUsername)) { "unknown" } else { $script:RestoreHfLoginUsername }177 Write-Info "Restoring previous HF login for user: $display_user"178 & hf auth login --token $script:RestoreHfLoginToken *> $null179 if ($LASTEXITCODE -eq 0) {180 Write-Info "Previous HF login restored."181 } else {182 Write-Error "Failed to restore previous HF login. Please run: hf auth login"183 }184 185 $script:RestoreHfLoginRequired = $false186}187 188function New-RandomHex {189 param([int]$Length)190 191 if ($Length -le 0 -or ($Length % 2) -ne 0) {192 Fail "Length must be a positive even number."193 }194 195 $bytes = New-Object byte[] ($Length / 2)196 [System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes)197 return ($bytes | ForEach-Object { $_.ToString("x2") }) -join ""198}199 200function Ensure-Git {201 if (-not (Get-Command git -ErrorAction SilentlyContinue)) {202 Fail "git is required. Please install git first."203 }204}205 206function Ensure-HfCli {207 if (Get-Command hf -ErrorAction SilentlyContinue) {208 return209 }210 211 Write-Info "hf CLI not found. Installing via powershell -ExecutionPolicy ByPass -c `"irm https://hf.co/cli/install.ps1 | iex`" ..."212 & powershell -ExecutionPolicy ByPass -c "irm https://hf.co/cli/install.ps1 | iex"213 if ($LASTEXITCODE -ne 0) {214 Fail "hf CLI install failed. Please install manually and rerun."215 }216 217 $local_bin = Join-Path $HOME ".local/bin"218 if ((Test-Path $local_bin) -and -not (($env:PATH -split [IO.Path]::PathSeparator) -contains $local_bin)) {219 $env:PATH = "$local_bin$([IO.Path]::PathSeparator)$env:PATH"220 }221 222 if (-not (Get-Command hf -ErrorAction SilentlyContinue)) {223 Fail "hf CLI install failed. Please install manually and rerun."224 }225}226 227function Ensure-Python3 {228 if (-not (Get-Command python3 -ErrorAction SilentlyContinue)) {229 Fail "python3 is required. Please install python3 first."230 }231}232 233function Ensure-HuggingFaceHubPy {234 & python3 -c "import huggingface_hub" 2>$null235 if ($LASTEXITCODE -ne 0) {236 Fail "python3 package 'huggingface_hub' is required. Install with: python3 -m pip install --user 'huggingface_hub[cli]'"237 }238}239 240function Resolve-LatestOpenclawVersion {241 $python_code = @'242import json243import urllib.request244 245url = "https://registry.npmjs.org/openclaw/latest"246try:247 with urllib.request.urlopen(url, timeout=8) as response:248 payload = response.read().decode("utf-8", errors="replace")249 data = json.loads(payload)250 version = str(data.get("version", "")).strip()251 if version:252 print(version)253except Exception:254 pass255'@256 257 $version_output = & python3 -c $python_code 2>$null258 $version = Trim-Value (($version_output | Out-String))259 if ([string]::IsNullOrEmpty($version)) {260 return "latest"261 }262 return $version263}264 265function Read-CurrentHfToken {266 if (-not [string]::IsNullOrEmpty($env:HUGGINGFACE_HUB_TOKEN)) {267 return Trim-Value $env:HUGGINGFACE_HUB_TOKEN268 }269 if (-not [string]::IsNullOrEmpty($env:HF_TOKEN)) {270 return Trim-Value $env:HF_TOKEN271 }272 if (Test-Path $hf_token_file) {273 return Trim-Value (Get-Content -Path $hf_token_file -TotalCount 1)274 }275 return ""276}277 278function Test-HfLoggedIn {279 & hf auth whoami *> $null280 return ($LASTEXITCODE -eq 0)281}282 283function Get-HfUsername {284 $whoami_output = (& hf auth whoami 2>&1 | Out-String)285 286 $user_match = [regex]::Match($whoami_output, "(?im)^\s*user:\s*([^\s]+)")287 if ($user_match.Success) {288 return Trim-Value $user_match.Groups[1].Value289 }290 291 $login_match = [regex]::Match($whoami_output, "(?im)logged in as\s+([^\s]+)")292 if ($login_match.Success) {293 return Trim-Value $login_match.Groups[1].Value294 }295 296 $token_from_cache = Read-CurrentHfToken297 if (-not [string]::IsNullOrEmpty($token_from_cache)) {298 $env:HF_API_TOKEN = $token_from_cache299 $python_code = @'300from huggingface_hub import HfApi301import os302 303token = (os.environ.get("HF_API_TOKEN") or "").strip() or None304api = HfApi(token=token)305data = api.whoami(token=token)306name = data.get("name", "") if isinstance(data, dict) else ""307print((name or "").strip())308'@309 310 $name_output = & python3 -c $python_code 2>$null311 $name = Trim-Value (($name_output | Out-String))312 if (-not [string]::IsNullOrEmpty($name)) {313 return $name314 }315 }316 317 return ""318}319 320function Set-SpaceVariable {321 param(322 [string]$SpaceRepoId,323 [string]$Key,324 [string]$Value,325 [string]$ApiToken326 )327 328 $env:SPACE_REPO_ID = $SpaceRepoId329 $env:SPACE_VARIABLE_KEY = $Key330 $env:SPACE_VARIABLE_VALUE = $Value331 $env:HF_API_TOKEN = $ApiToken332 333 $python_code = @'334from huggingface_hub import HfApi335import os336 337token = (os.environ.get("HF_API_TOKEN") or "").strip() or None338api = HfApi(token=token)339try:340 api.add_space_variable(341 repo_id=os.environ["SPACE_REPO_ID"],342 key=os.environ["SPACE_VARIABLE_KEY"],343 value=os.environ["SPACE_VARIABLE_VALUE"],344 )345except Exception as exc:346 key = os.environ.get("SPACE_VARIABLE_KEY", "")347 repo_id = os.environ.get("SPACE_REPO_ID", "")348 raise SystemExit(f"failed to set space variable {key} on {repo_id}: {exc}")349'@350 351 & python3 -c $python_code352 if ($LASTEXITCODE -ne 0) {353 Fail "failed to set space variable $Key"354 }355}356 357function Set-SpaceSecret {358 param(359 [string]$SpaceRepoId,360 [string]$Key,361 [string]$Value,362 [string]$ApiToken363 )364 365 $env:SPACE_REPO_ID = $SpaceRepoId366 $env:SPACE_SECRET_KEY = $Key367 $env:SPACE_SECRET_VALUE = $Value368 $env:HF_API_TOKEN = $ApiToken369 370 $python_code = @'371from huggingface_hub import HfApi372import os373 374token = (os.environ.get("HF_API_TOKEN") or "").strip() or None375api = HfApi(token=token)376try:377 api.add_space_secret(378 repo_id=os.environ["SPACE_REPO_ID"],379 key=os.environ["SPACE_SECRET_KEY"],380 value=os.environ["SPACE_SECRET_VALUE"],381 )382except Exception as exc:383 key = os.environ.get("SPACE_SECRET_KEY", "")384 repo_id = os.environ.get("SPACE_REPO_ID", "")385 raise SystemExit(f"failed to set space secret {key} on {repo_id}: {exc}")386'@387 388 & python3 -c $python_code389 if ($LASTEXITCODE -ne 0) {390 Fail "failed to set space secret $Key"391 }392}393 394function Set-SpaceVariableLogged {395 param(396 [string]$SpaceRepoId,397 [string]$Key,398 [string]$Value,399 [string]$ApiToken400 )401 402 Invoke-Step -Message "Set Space variable $Key" -Action {403 Set-SpaceVariable -SpaceRepoId $SpaceRepoId -Key $Key -Value $Value -ApiToken $ApiToken404 }405}406 407function Set-SpaceSecretLogged {408 param(409 [string]$SpaceRepoId,410 [string]$Key,411 [string]$Value,412 [string]$ApiToken413 )414 415 Invoke-Step -Message "Set Space secret $Key" -Action {416 Set-SpaceSecret -SpaceRepoId $SpaceRepoId -Key $Key -Value $Value -ApiToken $ApiToken417 }418}419 420function Restart-Space {421 param(422 [string]$SpaceRepoId,423 [string]$ApiToken424 )425 426 $env:SPACE_RESTART_REPO_ID = $SpaceRepoId427 $env:HF_API_TOKEN = $ApiToken428 429 $python_code = @'430from huggingface_hub import HfApi431import os432 433token = (os.environ.get("HF_API_TOKEN") or "").strip() or None434api = HfApi(token=token)435try:436 api.restart_space(repo_id=os.environ["SPACE_RESTART_REPO_ID"])437except Exception as exc:438 repo_id = os.environ.get("SPACE_RESTART_REPO_ID", "")439 raise SystemExit(f"failed to restart space {repo_id}: {exc}")440'@441 442 & python3 -c $python_code443 if ($LASTEXITCODE -ne 0) {444 Fail "failed to restart space $SpaceRepoId"445 }446}447 448function Main {449 Invoke-Step -Message "Change directory to repository root" -Action {450 Set-Location $repo_root451 }452 453 Write-Info "OpenClaw Hugging Face bootstrap (interactive, Windows PowerShell)"454 Invoke-Step -Message "Check dependency git" -Action { Ensure-Git }455 Invoke-Step -Message "Check dependency hf CLI" -Action { Ensure-HfCli }456 Invoke-Step -Message "Check dependency python3" -Action { Ensure-Python3 }457 Invoke-Step -Message "Check dependency python package huggingface_hub" -Action { Ensure-HuggingFaceHubPy }458 Invoke-Step -Message "Print dependency versions" -Action {459 & git --version460 & hf version461 & python3 --version462 }463 464 $hf_token_for_backup = ""465 Invoke-Step -Message "Resolve HF login and HF_TOKEN" -Action {466 if (-not (Test-HfLoggedIn)) {467 Write-Info "HF CLI is not logged in."468 $hf_token_for_backup = Prompt-SecretRequired -Prompt "HF_TOKEN (required for hf auth login)"469 Login-WithHfToken -Token $hf_token_for_backup470 } else {471 $current_hf_username = Trim-Value (Get-HfUsername)472 if ([string]::IsNullOrEmpty($current_hf_username)) {473 $use_current_hf_user = Prompt-YesNo -Prompt "HF CLI is already logged in. Use current user?" -DefaultValue "y"474 } else {475 $use_current_hf_user = Prompt-YesNo -Prompt "HF CLI is already logged in as '$current_hf_username'. Use this user?" -DefaultValue "y"476 }477 478 if ($use_current_hf_user -eq "yes") {479 $hf_token_for_backup = Trim-Value (Read-CurrentHfToken)480 if ([string]::IsNullOrEmpty($hf_token_for_backup)) {481 $hf_token_for_backup = Prompt-SecretRequired -Prompt "Cannot read current token. Enter HF_TOKEN"482 Login-WithHfToken -Token $hf_token_for_backup483 }484 } else {485 $script:RestoreHfLoginToken = Trim-Value (Read-CurrentHfToken)486 if ([string]::IsNullOrEmpty($script:RestoreHfLoginToken)) {487 Fail "Cannot backup current HF token. Ensure current token is readable before switching users."488 }489 $script:RestoreHfLoginRequired = $true490 $script:RestoreHfLoginUsername = $current_hf_username491 492 $switch_hf_token = Prompt-SecretRequired -Prompt "HF_TOKEN for switching HF user"493 Login-WithHfToken -Token $switch_hf_token494 $hf_token_for_backup = $switch_hf_token495 }496 }497 498 if ([string]::IsNullOrEmpty($hf_token_for_backup)) {499 Fail "HF_TOKEN is required to configure Space secret HF_TOKEN."500 }501 }502 503 $hf_username = ""504 Invoke-Step -Message "Resolve HF username" -Action {505 $hf_username = Trim-Value (Get-HfUsername)506 if ([string]::IsNullOrEmpty($hf_username)) {507 $hf_username = Prompt-Required -Prompt "HF username (cannot parse from hf auth whoami)"508 }509 Write-Info "HF user: $hf_username"510 }511 512 $space_name = ""513 $dataset_name = ""514 Invoke-Step -Message "Collect Space and Dataset names" -Action {515 $space_name = Prompt-Required -Prompt "Space name (without username)" -DefaultValue "openclaw-hf"516 $dataset_name = Prompt-Required -Prompt "Dataset name (without username)" -DefaultValue "$space_name-backup"517 }518 519 $openclaw_version = ""520 Invoke-Step -Message "Resolve and confirm OPENCLAW_VERSION" -Action {521 $default_openclaw_version = Trim-Value $env:OPENCLAW_VERSION522 if ([string]::IsNullOrEmpty($default_openclaw_version)) {523 $default_openclaw_version = Resolve-LatestOpenclawVersion524 }525 $openclaw_version = Prompt-Required -Prompt "OPENCLAW_VERSION (press Enter to use detected latest)" -DefaultValue $default_openclaw_version526 }527 528 $space_repo_id = "$hf_username/$space_name"529 $dataset_repo_id = "$hf_username/$dataset_name"530 531 $gateway_token = ""532 $generated_gateway_token = $false533 Invoke-Step -Message "Collect OPENCLAW_GATEWAY_TOKEN" -Action {534 $gateway_token = Prompt-SecretOptional -Prompt "OPENCLAW_GATEWAY_TOKEN (optional, leave empty to auto-generate 32 chars)"535 if ([string]::IsNullOrEmpty($gateway_token)) {536 $gateway_token = New-RandomHex -Length 32537 $generated_gateway_token = $true538 Write-Info "OPENCLAW_GATEWAY_TOKEN generated automatically."539 }540 }541 542 $gateway_password = ""543 $generated_gateway_password = $false544 Invoke-Step -Message "Collect OPENCLAW_GATEWAY_PASSWORD" -Action {545 $gateway_password = Prompt-SecretOptional -Prompt "OPENCLAW_GATEWAY_PASSWORD (optional, leave empty to auto-generate 16 chars)"546 if ([string]::IsNullOrEmpty($gateway_password)) {547 $gateway_password = New-RandomHex -Length 16548 $generated_gateway_password = $true549 Write-Info "OPENCLAW_GATEWAY_PASSWORD generated automatically."550 }551 }552 553 $configure_llm = "no"554 $llm_base_url = ""555 $llm_model = ""556 $llm_api_key = ""557 $enable_sshx = "no"558 $sshx_auto_start_value = "false"559 Invoke-Step -Message "Collect custom LLM or sshx bootstrap options" -Action {560 $configure_llm = Prompt-YesNo -Prompt "Configure custom LLM now?" -DefaultValue "n"561 if ($configure_llm -eq "yes") {562 $llm_base_url = Prompt-Required -Prompt "OPENCLAW_LLM_BASE_URL"563 $llm_model = Prompt-Required -Prompt "OPENCLAW_LLM_MODEL"564 $llm_api_key = Prompt-SecretOptional -Prompt "OPENCLAW_LLM_API_KEY"565 if ([string]::IsNullOrEmpty($llm_api_key)) {566 Fail "OPENCLAW_LLM_API_KEY is required when enabling custom LLM config."567 }568 } else {569 $enable_sshx = Prompt-YesNo -Prompt "Set OPENCLAW_SSHX_AUTO_START=true for later sshx setup?" -DefaultValue "y"570 }571 }572 if ($enable_sshx -eq "yes") {573 $sshx_auto_start_value = "true"574 }575 576 Write-Info ""577 Write-Info "Planned deployment configuration:"578 Write-Info "Space repo: $space_repo_id"579 Write-Info "Dataset repo: $dataset_repo_id"580 Write-Info "OPENCLAW_VERSION: $openclaw_version"581 Write-Info "OPENCLAW_GATEWAY_CONTROLUI_ALLOW_INSECURE_AUTH=false"582 Write-Info "OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_DISABLE_DEVICE_AUTH=false"583 Write-Info "OPENCLAW_SSHX_AUTO_START=$sshx_auto_start_value"584 if ($configure_llm -eq "yes") {585 Write-Info "Custom LLM config: enabled"586 } else {587 Write-Info "Custom LLM config: disabled"588 }589 $proceed_with_deploy = Prompt-YesNo -Prompt "Proceed with these settings?" -DefaultValue "y"590 if ($proceed_with_deploy -ne "yes") {591 Write-Info "Cancelled by user before creating/updating Space or Dataset."592 return593 }594 595 Invoke-Step -Message "Create Space repo $space_repo_id" -Action {596 & hf repo create $space_repo_id --repo-type space --space-sdk docker --private --exist-ok597 if ($LASTEXITCODE -ne 0) {598 Fail "failed to create Space repo"599 }600 }601 Invoke-Step -Message "Create Dataset repo $dataset_repo_id" -Action {602 & hf repo create $dataset_repo_id --repo-type dataset --private --exist-ok603 if ($LASTEXITCODE -ne 0) {604 Fail "failed to create Dataset repo"605 }606 }607 Invoke-Step -Message "Upload repository to Space $space_repo_id" -Action {608 & hf upload $space_repo_id . --repo-type space --exclude ".git/**" --exclude ".git" --commit-message "feat: deploy openclaw to hf space"609 if ($LASTEXITCODE -ne 0) {610 Fail "failed to upload repository to Space"611 }612 }613 614 $api_token = ""615 Invoke-Step -Message "Resolve API token for Space configuration" -Action {616 $api_token = Read-CurrentHfToken617 if ([string]::IsNullOrEmpty($api_token)) {618 $api_token = $hf_token_for_backup619 }620 if ([string]::IsNullOrEmpty($api_token)) {621 Fail "unable to resolve API token for Space configuration."622 }623 }624 625 Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_BACKUP_DATASET_REPO" -Value $dataset_repo_id -ApiToken $api_token626 Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_VERSION" -Value $openclaw_version -ApiToken $api_token627 Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_CONTROLUI_ALLOW_INSECURE_AUTH" -Value "false" -ApiToken $api_token628 Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_DISABLE_DEVICE_AUTH" -Value "false" -ApiToken $api_token629 Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_TOKEN" -Value $gateway_token -ApiToken $api_token630 Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_PASSWORD" -Value $gateway_password -ApiToken $api_token631 Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "HF_TOKEN" -Value $hf_token_for_backup -ApiToken $api_token632 633 if ($configure_llm -eq "yes") {634 Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_LLM_BASE_URL" -Value $llm_base_url -ApiToken $api_token635 Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_LLM_MODEL" -Value $llm_model -ApiToken $api_token636 Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_LLM_API_KEY" -Value $llm_api_key -ApiToken $api_token637 }638 639 Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_SSHX_AUTO_START" -Value $sshx_auto_start_value -ApiToken $api_token640 641 Invoke-Step -Message "Print deployment summary" -Action {642 $space_page_url = "https://huggingface.co/spaces/$space_repo_id"643 $space_host = "$($space_repo_id -replace '/', '-').hf.space"644 $app_url = "https://$space_host"645 $health_url = "$app_url/healthz"646 647 Write-Info ""648 Write-Info "Deployment complete."649 Write-Info "Space repo: $space_repo_id"650 Write-Info "Hugging Face Space: $space_page_url"651 Write-Info "Dataset repo: $dataset_repo_id"652 Write-Info "OPENCLAW_VERSION: $openclaw_version"653 Write-Info "Space URL: $app_url"654 Write-Info "Health URL: $health_url"655 656 if ($generated_gateway_token) {657 Write-Info "Generated OPENCLAW_GATEWAY_TOKEN=$gateway_token"658 }659 if ($generated_gateway_password) {660 Write-Info "Generated OPENCLAW_GATEWAY_PASSWORD=$gateway_password"661 }662 }663}664 665try {666 Main667}668catch {669 Write-Error $_.Exception.Message670 exit 1671}672finally {673 Restore-PreviousHfLoginIfNeeded674}675 