| Set-StrictMode -Version Latest |
| $ErrorActionPreference = "Stop" |
|
|
| $script_dir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path } |
| $repo_root = (Resolve-Path (Join-Path $script_dir "..")).Path |
| $hf_token_file = if ($env:HF_TOKEN_FILE) { $env:HF_TOKEN_FILE } else { Join-Path $HOME ".cache/huggingface/token" } |
| $script:RestoreHfLoginRequired = $false |
| $script:RestoreHfLoginToken = "" |
| $script:RestoreHfLoginUsername = "" |
|
|
| function Trim-Value { |
| param([AllowNull()][string]$Value) |
|
|
| if ($null -eq $Value) { |
| return "" |
| } |
| return $Value.Trim() |
| } |
|
|
| function Write-Info { |
| param([string]$Message) |
|
|
| Write-Host $Message |
| } |
|
|
| $script:BootstrapStepIndex = 0 |
|
|
| function Get-LogTimestamp { |
| return (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") |
| } |
|
|
| function Write-StepStart { |
| param([string]$Message) |
|
|
| $script:BootstrapStepIndex += 1 |
| Write-Info ("[{0}] [bootstrap step {1}] START {2}" -f (Get-LogTimestamp), $script:BootstrapStepIndex, $Message) |
| } |
|
|
| function Write-StepDone { |
| param([string]$Message) |
|
|
| Write-Info ("[{0}] [bootstrap step {1}] DONE {2}" -f (Get-LogTimestamp), $script:BootstrapStepIndex, $Message) |
| } |
|
|
| function Invoke-Step { |
| param( |
| [string]$Message, |
| [ScriptBlock]$Action |
| ) |
|
|
| Write-StepStart -Message $Message |
| & $Action |
| Write-StepDone -Message $Message |
| } |
|
|
| function Fail { |
| param([string]$Message) |
|
|
| throw $Message |
| } |
|
|
| function Prompt-Line { |
| param( |
| [string]$Prompt, |
| [string]$DefaultValue = "" |
| ) |
|
|
| if ([string]::IsNullOrEmpty($DefaultValue)) { |
| $raw = Read-Host -Prompt $Prompt |
| } else { |
| $raw = Read-Host -Prompt "$Prompt [$DefaultValue]" |
| } |
|
|
| $value = Trim-Value $raw |
| if ([string]::IsNullOrEmpty($value)) { |
| $value = $DefaultValue |
| } |
| return $value |
| } |
|
|
| function Prompt-Required { |
| param( |
| [string]$Prompt, |
| [string]$DefaultValue = "" |
| ) |
|
|
| while ($true) { |
| $value = Trim-Value (Prompt-Line -Prompt $Prompt -DefaultValue $DefaultValue) |
| if (-not [string]::IsNullOrEmpty($value)) { |
| return $value |
| } |
| Write-Host "This value is required." -ForegroundColor Red |
| } |
| } |
|
|
| function Convert-SecureStringToPlainText { |
| param([System.Security.SecureString]$SecureValue) |
|
|
| if ($null -eq $SecureValue) { |
| return "" |
| } |
|
|
| $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureValue) |
| try { |
| return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) |
| } |
| finally { |
| [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) |
| } |
| } |
|
|
| function Prompt-SecretOptional { |
| param([string]$Prompt) |
|
|
| $secure_value = Read-Host -Prompt $Prompt -AsSecureString |
| $plain_text = Convert-SecureStringToPlainText -SecureValue $secure_value |
| return Trim-Value $plain_text |
| } |
|
|
| function Prompt-SecretRequired { |
| param([string]$Prompt) |
|
|
| while ($true) { |
| $value = Trim-Value (Prompt-SecretOptional -Prompt $Prompt) |
| if (-not [string]::IsNullOrEmpty($value)) { |
| return $value |
| } |
| Write-Host "This value is required." -ForegroundColor Red |
| } |
| } |
|
|
| function Prompt-YesNo { |
| param( |
| [string]$Prompt, |
| [ValidateSet("y", "n")][string]$DefaultValue = "n" |
| ) |
|
|
| $hint = if ($DefaultValue -eq "y") { "[Y/n]" } else { "[y/N]" } |
|
|
| while ($true) { |
| $answer = Trim-Value (Read-Host -Prompt "$Prompt $hint") |
| $answer = $answer.ToLowerInvariant() |
| if ([string]::IsNullOrEmpty($answer)) { |
| $answer = $DefaultValue |
| } |
|
|
| switch ($answer) { |
| { $_ -in @("y", "yes") } { return "yes" } |
| { $_ -in @("n", "no") } { return "no" } |
| default { |
| Write-Host "Please enter y or n." -ForegroundColor Red |
| } |
| } |
| } |
| } |
|
|
| function Login-WithHfToken { |
| param([string]$Token) |
|
|
| & hf auth login --token $Token *> $null |
| if ($LASTEXITCODE -ne 0) { |
| Fail "hf auth login with token failed." |
| } |
| } |
|
|
| function Restore-PreviousHfLoginIfNeeded { |
| if (-not $script:RestoreHfLoginRequired) { |
| return |
| } |
| if ([string]::IsNullOrEmpty($script:RestoreHfLoginToken)) { |
| Write-Error "Skip restoring previous HF login because backup token is empty." |
| $script:RestoreHfLoginRequired = $false |
| return |
| } |
|
|
| $display_user = if ([string]::IsNullOrEmpty($script:RestoreHfLoginUsername)) { "unknown" } else { $script:RestoreHfLoginUsername } |
| Write-Info "Restoring previous HF login for user: $display_user" |
| & hf auth login --token $script:RestoreHfLoginToken *> $null |
| if ($LASTEXITCODE -eq 0) { |
| Write-Info "Previous HF login restored." |
| } else { |
| Write-Error "Failed to restore previous HF login. Please run: hf auth login" |
| } |
|
|
| $script:RestoreHfLoginRequired = $false |
| } |
|
|
| function New-RandomHex { |
| param([int]$Length) |
|
|
| if ($Length -le 0 -or ($Length % 2) -ne 0) { |
| Fail "Length must be a positive even number." |
| } |
|
|
| $bytes = New-Object byte[] ($Length / 2) |
| [System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes) |
| return ($bytes | ForEach-Object { $_.ToString("x2") }) -join "" |
| } |
|
|
| function Ensure-Git { |
| if (-not (Get-Command git -ErrorAction SilentlyContinue)) { |
| Fail "git is required. Please install git first." |
| } |
| } |
|
|
| function Ensure-HfCli { |
| if (Get-Command hf -ErrorAction SilentlyContinue) { |
| return |
| } |
|
|
| Write-Info "hf CLI not found. Installing via powershell -ExecutionPolicy ByPass -c `"irm https://hf.co/cli/install.ps1 | iex`" ..." |
| & powershell -ExecutionPolicy ByPass -c "irm https://hf.co/cli/install.ps1 | iex" |
| if ($LASTEXITCODE -ne 0) { |
| Fail "hf CLI install failed. Please install manually and rerun." |
| } |
|
|
| $local_bin = Join-Path $HOME ".local/bin" |
| if ((Test-Path $local_bin) -and -not (($env:PATH -split [IO.Path]::PathSeparator) -contains $local_bin)) { |
| $env:PATH = "$local_bin$([IO.Path]::PathSeparator)$env:PATH" |
| } |
|
|
| if (-not (Get-Command hf -ErrorAction SilentlyContinue)) { |
| Fail "hf CLI install failed. Please install manually and rerun." |
| } |
| } |
|
|
| function Ensure-Python3 { |
| if (-not (Get-Command python3 -ErrorAction SilentlyContinue)) { |
| Fail "python3 is required. Please install python3 first." |
| } |
| } |
|
|
| function Ensure-HuggingFaceHubPy { |
| & python3 -c "import huggingface_hub" 2>$null |
| if ($LASTEXITCODE -ne 0) { |
| Fail "python3 package 'huggingface_hub' is required. Install with: python3 -m pip install --user 'huggingface_hub[cli]'" |
| } |
| } |
|
|
| function Resolve-LatestOpenclawVersion { |
| $python_code = @' |
| import json |
| import urllib.request |
| |
| url = "https://registry.npmjs.org/openclaw/latest" |
| try: |
| with urllib.request.urlopen(url, timeout=8) as response: |
| payload = response.read().decode("utf-8", errors="replace") |
| data = json.loads(payload) |
| version = str(data.get("version", "")).strip() |
| if version: |
| print(version) |
| except Exception: |
| pass |
| '@ |
|
|
| $version_output = & python3 -c $python_code 2>$null |
| $version = Trim-Value (($version_output | Out-String)) |
| if ([string]::IsNullOrEmpty($version)) { |
| return "latest" |
| } |
| return $version |
| } |
|
|
| function Read-CurrentHfToken { |
| if (-not [string]::IsNullOrEmpty($env:HUGGINGFACE_HUB_TOKEN)) { |
| return Trim-Value $env:HUGGINGFACE_HUB_TOKEN |
| } |
| if (-not [string]::IsNullOrEmpty($env:HF_TOKEN)) { |
| return Trim-Value $env:HF_TOKEN |
| } |
| if (Test-Path $hf_token_file) { |
| return Trim-Value (Get-Content -Path $hf_token_file -TotalCount 1) |
| } |
| return "" |
| } |
|
|
| function Test-HfLoggedIn { |
| & hf auth whoami *> $null |
| return ($LASTEXITCODE -eq 0) |
| } |
|
|
| function Get-HfUsername { |
| $whoami_output = (& hf auth whoami 2>&1 | Out-String) |
|
|
| $user_match = [regex]::Match($whoami_output, "(?im)^\s*user:\s*([^\s]+)") |
| if ($user_match.Success) { |
| return Trim-Value $user_match.Groups[1].Value |
| } |
|
|
| $login_match = [regex]::Match($whoami_output, "(?im)logged in as\s+([^\s]+)") |
| if ($login_match.Success) { |
| return Trim-Value $login_match.Groups[1].Value |
| } |
|
|
| $token_from_cache = Read-CurrentHfToken |
| if (-not [string]::IsNullOrEmpty($token_from_cache)) { |
| $env:HF_API_TOKEN = $token_from_cache |
| $python_code = @' |
| from huggingface_hub import HfApi |
| import os |
| |
| token = (os.environ.get("HF_API_TOKEN") or "").strip() or None |
| api = HfApi(token=token) |
| data = api.whoami(token=token) |
| name = data.get("name", "") if isinstance(data, dict) else "" |
| print((name or "").strip()) |
| '@ |
|
|
| $name_output = & python3 -c $python_code 2>$null |
| $name = Trim-Value (($name_output | Out-String)) |
| if (-not [string]::IsNullOrEmpty($name)) { |
| return $name |
| } |
| } |
|
|
| return "" |
| } |
|
|
| function Set-SpaceVariable { |
| param( |
| [string]$SpaceRepoId, |
| [string]$Key, |
| [string]$Value, |
| [string]$ApiToken |
| ) |
|
|
| $env:SPACE_REPO_ID = $SpaceRepoId |
| $env:SPACE_VARIABLE_KEY = $Key |
| $env:SPACE_VARIABLE_VALUE = $Value |
| $env:HF_API_TOKEN = $ApiToken |
|
|
| $python_code = @' |
| from huggingface_hub import HfApi |
| import os |
| |
| token = (os.environ.get("HF_API_TOKEN") or "").strip() or None |
| api = HfApi(token=token) |
| try: |
| api.add_space_variable( |
| repo_id=os.environ["SPACE_REPO_ID"], |
| key=os.environ["SPACE_VARIABLE_KEY"], |
| value=os.environ["SPACE_VARIABLE_VALUE"], |
| ) |
| except Exception as exc: |
| key = os.environ.get("SPACE_VARIABLE_KEY", "") |
| repo_id = os.environ.get("SPACE_REPO_ID", "") |
| raise SystemExit(f"failed to set space variable {key} on {repo_id}: {exc}") |
| '@ |
|
|
| & python3 -c $python_code |
| if ($LASTEXITCODE -ne 0) { |
| Fail "failed to set space variable $Key" |
| } |
| } |
|
|
| function Set-SpaceSecret { |
| param( |
| [string]$SpaceRepoId, |
| [string]$Key, |
| [string]$Value, |
| [string]$ApiToken |
| ) |
|
|
| $env:SPACE_REPO_ID = $SpaceRepoId |
| $env:SPACE_SECRET_KEY = $Key |
| $env:SPACE_SECRET_VALUE = $Value |
| $env:HF_API_TOKEN = $ApiToken |
|
|
| $python_code = @' |
| from huggingface_hub import HfApi |
| import os |
| |
| token = (os.environ.get("HF_API_TOKEN") or "").strip() or None |
| api = HfApi(token=token) |
| try: |
| api.add_space_secret( |
| repo_id=os.environ["SPACE_REPO_ID"], |
| key=os.environ["SPACE_SECRET_KEY"], |
| value=os.environ["SPACE_SECRET_VALUE"], |
| ) |
| except Exception as exc: |
| key = os.environ.get("SPACE_SECRET_KEY", "") |
| repo_id = os.environ.get("SPACE_REPO_ID", "") |
| raise SystemExit(f"failed to set space secret {key} on {repo_id}: {exc}") |
| '@ |
|
|
| & python3 -c $python_code |
| if ($LASTEXITCODE -ne 0) { |
| Fail "failed to set space secret $Key" |
| } |
| } |
|
|
| function Set-SpaceVariableLogged { |
| param( |
| [string]$SpaceRepoId, |
| [string]$Key, |
| [string]$Value, |
| [string]$ApiToken |
| ) |
|
|
| Invoke-Step -Message "Set Space variable $Key" -Action { |
| Set-SpaceVariable -SpaceRepoId $SpaceRepoId -Key $Key -Value $Value -ApiToken $ApiToken |
| } |
| } |
|
|
| function Set-SpaceSecretLogged { |
| param( |
| [string]$SpaceRepoId, |
| [string]$Key, |
| [string]$Value, |
| [string]$ApiToken |
| ) |
|
|
| Invoke-Step -Message "Set Space secret $Key" -Action { |
| Set-SpaceSecret -SpaceRepoId $SpaceRepoId -Key $Key -Value $Value -ApiToken $ApiToken |
| } |
| } |
|
|
| function Restart-Space { |
| param( |
| [string]$SpaceRepoId, |
| [string]$ApiToken |
| ) |
|
|
| $env:SPACE_RESTART_REPO_ID = $SpaceRepoId |
| $env:HF_API_TOKEN = $ApiToken |
|
|
| $python_code = @' |
| from huggingface_hub import HfApi |
| import os |
| |
| token = (os.environ.get("HF_API_TOKEN") or "").strip() or None |
| api = HfApi(token=token) |
| try: |
| api.restart_space(repo_id=os.environ["SPACE_RESTART_REPO_ID"]) |
| except Exception as exc: |
| repo_id = os.environ.get("SPACE_RESTART_REPO_ID", "") |
| raise SystemExit(f"failed to restart space {repo_id}: {exc}") |
| '@ |
|
|
| & python3 -c $python_code |
| if ($LASTEXITCODE -ne 0) { |
| Fail "failed to restart space $SpaceRepoId" |
| } |
| } |
|
|
| function Main { |
| Invoke-Step -Message "Change directory to repository root" -Action { |
| Set-Location $repo_root |
| } |
|
|
| Write-Info "OpenClaw Hugging Face bootstrap (interactive, Windows PowerShell)" |
| Invoke-Step -Message "Check dependency git" -Action { Ensure-Git } |
| Invoke-Step -Message "Check dependency hf CLI" -Action { Ensure-HfCli } |
| Invoke-Step -Message "Check dependency python3" -Action { Ensure-Python3 } |
| Invoke-Step -Message "Check dependency python package huggingface_hub" -Action { Ensure-HuggingFaceHubPy } |
| Invoke-Step -Message "Print dependency versions" -Action { |
| & git --version |
| & hf version |
| & python3 --version |
| } |
|
|
| $hf_token_for_backup = "" |
| Invoke-Step -Message "Resolve HF login and HF_TOKEN" -Action { |
| if (-not (Test-HfLoggedIn)) { |
| Write-Info "HF CLI is not logged in." |
| $hf_token_for_backup = Prompt-SecretRequired -Prompt "HF_TOKEN (required for hf auth login)" |
| Login-WithHfToken -Token $hf_token_for_backup |
| } else { |
| $current_hf_username = Trim-Value (Get-HfUsername) |
| if ([string]::IsNullOrEmpty($current_hf_username)) { |
| $use_current_hf_user = Prompt-YesNo -Prompt "HF CLI is already logged in. Use current user?" -DefaultValue "y" |
| } else { |
| $use_current_hf_user = Prompt-YesNo -Prompt "HF CLI is already logged in as '$current_hf_username'. Use this user?" -DefaultValue "y" |
| } |
|
|
| if ($use_current_hf_user -eq "yes") { |
| $hf_token_for_backup = Trim-Value (Read-CurrentHfToken) |
| if ([string]::IsNullOrEmpty($hf_token_for_backup)) { |
| $hf_token_for_backup = Prompt-SecretRequired -Prompt "Cannot read current token. Enter HF_TOKEN" |
| Login-WithHfToken -Token $hf_token_for_backup |
| } |
| } else { |
| $script:RestoreHfLoginToken = Trim-Value (Read-CurrentHfToken) |
| if ([string]::IsNullOrEmpty($script:RestoreHfLoginToken)) { |
| Fail "Cannot backup current HF token. Ensure current token is readable before switching users." |
| } |
| $script:RestoreHfLoginRequired = $true |
| $script:RestoreHfLoginUsername = $current_hf_username |
|
|
| $switch_hf_token = Prompt-SecretRequired -Prompt "HF_TOKEN for switching HF user" |
| Login-WithHfToken -Token $switch_hf_token |
| $hf_token_for_backup = $switch_hf_token |
| } |
| } |
|
|
| if ([string]::IsNullOrEmpty($hf_token_for_backup)) { |
| Fail "HF_TOKEN is required to configure Space secret HF_TOKEN." |
| } |
| } |
|
|
| $hf_username = "" |
| Invoke-Step -Message "Resolve HF username" -Action { |
| $hf_username = Trim-Value (Get-HfUsername) |
| if ([string]::IsNullOrEmpty($hf_username)) { |
| $hf_username = Prompt-Required -Prompt "HF username (cannot parse from hf auth whoami)" |
| } |
| Write-Info "HF user: $hf_username" |
| } |
|
|
| $space_name = "" |
| $dataset_name = "" |
| Invoke-Step -Message "Collect Space and Dataset names" -Action { |
| $space_name = Prompt-Required -Prompt "Space name (without username)" -DefaultValue "openclaw-hf" |
| $dataset_name = Prompt-Required -Prompt "Dataset name (without username)" -DefaultValue "$space_name-backup" |
| } |
|
|
| $openclaw_version = "" |
| Invoke-Step -Message "Resolve and confirm OPENCLAW_VERSION" -Action { |
| $default_openclaw_version = Trim-Value $env:OPENCLAW_VERSION |
| if ([string]::IsNullOrEmpty($default_openclaw_version)) { |
| $default_openclaw_version = Resolve-LatestOpenclawVersion |
| } |
| $openclaw_version = Prompt-Required -Prompt "OPENCLAW_VERSION (press Enter to use detected latest)" -DefaultValue $default_openclaw_version |
| } |
|
|
| $space_repo_id = "$hf_username/$space_name" |
| $dataset_repo_id = "$hf_username/$dataset_name" |
|
|
| $gateway_token = "" |
| $generated_gateway_token = $false |
| Invoke-Step -Message "Collect OPENCLAW_GATEWAY_TOKEN" -Action { |
| $gateway_token = Prompt-SecretOptional -Prompt "OPENCLAW_GATEWAY_TOKEN (optional, leave empty to auto-generate 32 chars)" |
| if ([string]::IsNullOrEmpty($gateway_token)) { |
| $gateway_token = New-RandomHex -Length 32 |
| $generated_gateway_token = $true |
| Write-Info "OPENCLAW_GATEWAY_TOKEN generated automatically." |
| } |
| } |
|
|
| $gateway_password = "" |
| $generated_gateway_password = $false |
| Invoke-Step -Message "Collect OPENCLAW_GATEWAY_PASSWORD" -Action { |
| $gateway_password = Prompt-SecretOptional -Prompt "OPENCLAW_GATEWAY_PASSWORD (optional, leave empty to auto-generate 16 chars)" |
| if ([string]::IsNullOrEmpty($gateway_password)) { |
| $gateway_password = New-RandomHex -Length 16 |
| $generated_gateway_password = $true |
| Write-Info "OPENCLAW_GATEWAY_PASSWORD generated automatically." |
| } |
| } |
|
|
| $configure_llm = "no" |
| $llm_base_url = "" |
| $llm_model = "" |
| $llm_api_key = "" |
| $enable_sshx = "no" |
| $sshx_auto_start_value = "false" |
| Invoke-Step -Message "Collect custom LLM or sshx bootstrap options" -Action { |
| $configure_llm = Prompt-YesNo -Prompt "Configure custom LLM now?" -DefaultValue "n" |
| if ($configure_llm -eq "yes") { |
| $llm_base_url = Prompt-Required -Prompt "OPENCLAW_LLM_BASE_URL" |
| $llm_model = Prompt-Required -Prompt "OPENCLAW_LLM_MODEL" |
| $llm_api_key = Prompt-SecretOptional -Prompt "OPENCLAW_LLM_API_KEY" |
| if ([string]::IsNullOrEmpty($llm_api_key)) { |
| Fail "OPENCLAW_LLM_API_KEY is required when enabling custom LLM config." |
| } |
| } else { |
| $enable_sshx = Prompt-YesNo -Prompt "Set OPENCLAW_SSHX_AUTO_START=true for later sshx setup?" -DefaultValue "y" |
| } |
| } |
| if ($enable_sshx -eq "yes") { |
| $sshx_auto_start_value = "true" |
| } |
|
|
| Write-Info "" |
| Write-Info "Planned deployment configuration:" |
| Write-Info "Space repo: $space_repo_id" |
| Write-Info "Dataset repo: $dataset_repo_id" |
| Write-Info "OPENCLAW_VERSION: $openclaw_version" |
| Write-Info "OPENCLAW_GATEWAY_CONTROLUI_ALLOW_INSECURE_AUTH=false" |
| Write-Info "OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_DISABLE_DEVICE_AUTH=false" |
| Write-Info "OPENCLAW_SSHX_AUTO_START=$sshx_auto_start_value" |
| if ($configure_llm -eq "yes") { |
| Write-Info "Custom LLM config: enabled" |
| } else { |
| Write-Info "Custom LLM config: disabled" |
| } |
| $proceed_with_deploy = Prompt-YesNo -Prompt "Proceed with these settings?" -DefaultValue "y" |
| if ($proceed_with_deploy -ne "yes") { |
| Write-Info "Cancelled by user before creating/updating Space or Dataset." |
| return |
| } |
|
|
| Invoke-Step -Message "Create Space repo $space_repo_id" -Action { |
| & hf repo create $space_repo_id --repo-type space --space-sdk docker --private --exist-ok |
| if ($LASTEXITCODE -ne 0) { |
| Fail "failed to create Space repo" |
| } |
| } |
| Invoke-Step -Message "Create Dataset repo $dataset_repo_id" -Action { |
| & hf repo create $dataset_repo_id --repo-type dataset --private --exist-ok |
| if ($LASTEXITCODE -ne 0) { |
| Fail "failed to create Dataset repo" |
| } |
| } |
| Invoke-Step -Message "Upload repository to Space $space_repo_id" -Action { |
| & hf upload $space_repo_id . --repo-type space --exclude ".git/**" --exclude ".git" --commit-message "feat: deploy Gemma 4 to hf space" |
| if ($LASTEXITCODE -ne 0) { |
| Fail "failed to upload repository to Space" |
| } |
| } |
|
|
| $api_token = "" |
| Invoke-Step -Message "Resolve API token for Space configuration" -Action { |
| $api_token = Read-CurrentHfToken |
| if ([string]::IsNullOrEmpty($api_token)) { |
| $api_token = $hf_token_for_backup |
| } |
| if ([string]::IsNullOrEmpty($api_token)) { |
| Fail "unable to resolve API token for Space configuration." |
| } |
| } |
|
|
| Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_BACKUP_DATASET_REPO" -Value $dataset_repo_id -ApiToken $api_token |
| Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_VERSION" -Value $openclaw_version -ApiToken $api_token |
| Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_CONTROLUI_ALLOW_INSECURE_AUTH" -Value "false" -ApiToken $api_token |
| Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_DISABLE_DEVICE_AUTH" -Value "false" -ApiToken $api_token |
| Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_TOKEN" -Value $gateway_token -ApiToken $api_token |
| Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_GATEWAY_PASSWORD" -Value $gateway_password -ApiToken $api_token |
| Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "HF_TOKEN" -Value $hf_token_for_backup -ApiToken $api_token |
|
|
| if ($configure_llm -eq "yes") { |
| Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_LLM_BASE_URL" -Value $llm_base_url -ApiToken $api_token |
| Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_LLM_MODEL" -Value $llm_model -ApiToken $api_token |
| Set-SpaceSecretLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_LLM_API_KEY" -Value $llm_api_key -ApiToken $api_token |
| } |
|
|
| Set-SpaceVariableLogged -SpaceRepoId $space_repo_id -Key "OPENCLAW_SSHX_AUTO_START" -Value $sshx_auto_start_value -ApiToken $api_token |
|
|
| Invoke-Step -Message "Print deployment summary" -Action { |
| $space_page_url = "https://huggingface.co/spaces/$space_repo_id" |
| $space_host = "$($space_repo_id -replace '/', '-').hf.space" |
| $app_url = "https://$space_host" |
| $health_url = "$app_url/healthz" |
|
|
| Write-Info "" |
| Write-Info "Deployment complete." |
| Write-Info "Space repo: $space_repo_id" |
| Write-Info "Hugging Face Space: $space_page_url" |
| Write-Info "Dataset repo: $dataset_repo_id" |
| Write-Info "OPENCLAW_VERSION: $openclaw_version" |
| Write-Info "Space URL: $app_url" |
| Write-Info "Health URL: $health_url" |
|
|
| if ($generated_gateway_token) { |
| Write-Info "Generated OPENCLAW_GATEWAY_TOKEN=$gateway_token" |
| } |
| if ($generated_gateway_password) { |
| Write-Info "Generated OPENCLAW_GATEWAY_PASSWORD=$gateway_password" |
| } |
| } |
| } |
|
|
| try { |
| Main |
| } |
| catch { |
| Write-Error $_.Exception.Message |
| exit 1 |
| } |
| finally { |
| Restore-PreviousHfLoginIfNeeded |
| } |
|
|