# SeibertGPT – Einrichtung für opencode (Windows). Quelle: https://gpt.seibert.ai/clients # Der Key wird nur lokal abgefragt und landet in deinem Benutzerprofil, nie in einer Datei; gesendet wird er nur an das Gateway. & { $ErrorActionPreference = 'Stop' Write-Host 'SeibertGPT: Einrichtung für opencode' if (-not ([bool](Get-Command opencode -ErrorAction SilentlyContinue) -or [bool](Get-ChildItem "$env:LOCALAPPDATA\Programs" -Filter '*opencode*' -ErrorAction SilentlyContinue))) { Write-Host 'opencode scheint nicht installiert zu sein. Download: https://opencode.ai/download' $ans = Read-Host 'Trotzdem fortfahren? (j/N)' if ($ans -notmatch '^[jJyY]$') { return } } $targetDir = [Environment]::ExpandEnvironmentVariables('%USERPROFILE%\.config\opencode') New-Item -ItemType Directory -Force -Path $targetDir | Out-Null do { $secure = Read-Host -AsSecureString 'SeibertGPT-API-Key (beginnt mit sgpt_)' $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure) try { $key = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr).Trim() } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } if (-not $key.StartsWith('sgpt_')) { Write-Host 'Das ist kein SeibertGPT-Key. Keys findest du unter https://gpt.seibert.ai/konto/keys' } } until ($key.StartsWith('sgpt_')) [Environment]::SetEnvironmentVariable("SEIBERTGPT_API_KEY", $key, "User") $env:SEIBERTGPT_API_KEY = $key Write-Host 'Key als Benutzer-Umgebungsvariable SEIBERTGPT_API_KEY gespeichert (in deinem Windows-Benutzerprofil).' $sgptOcMajor = 0; try { $sgptOcVer = ((& opencode --version 2>$null) -join ' '); if ($sgptOcVer -match '(\d+)') { $sgptOcMajor = [int]$Matches[1] } } catch {}; if ($sgptOcMajor -ge 2) { $sgptPrevEap = $ErrorActionPreference; $ErrorActionPreference = 'Continue'; try { & opencode service set env SEIBERTGPT_API_KEY $key 2>&1 | Out-Null } catch {} finally { $ErrorActionPreference = $sgptPrevEap } } $target = Join-Path $targetDir 'opencode.json' $ours = @' { "$schema": "https://opencode.ai/config.json", "model": "seibertgpt/deepseek-v41-flash-fast", "small_model": "seibertgpt/deepseek-v41-flash-fast", "provider": { "seibertgpt": { "npm": "@ai-sdk/openai-compatible", "name": "SeibertGPT", "options": { "baseURL": "https://api.gpt.seibert.ai/v1", "apiKey": "{env:SEIBERTGPT_API_KEY}" }, "models": { "deepseek-v41-flash": { "name": "Standard mit Denkmodus", "tool_call": true, "attachment": true, "limit": { "context": 1000000, "output": 32000 } }, "deepseek-v41-flash-fast": { "name": "ohne Denkmodus – schnell", "tool_call": true, "attachment": true, "limit": { "context": 1000000, "output": 32000 } }, "deepseek-v41-flash-low": { "name": "Denkaufwand niedrig", "tool_call": true, "attachment": true, "limit": { "context": 1000000, "output": 32000 } }, "deepseek-v41-flash-high": { "name": "Denkaufwand hoch", "tool_call": true, "attachment": true, "limit": { "context": 1000000, "output": 32000 } }, "deepseek-v41-flash-max": { "name": "Denkaufwand maximal", "tool_call": true, "attachment": true, "limit": { "context": 1000000, "output": 32000 } } } } } } '@ $mergePaths = @() $mergePaths += ,@('provider','seibertgpt') $absentPaths = @() $absentPaths += ,@('$schema') $absentPaths += ,@('model') $absentPaths += ,@('small_model') function Get-JsonPath($obj, $path) { foreach ($p in $path) { if ($null -eq $obj -or -not ($obj.PSObject.Properties.Name -contains $p)) { return $null }; $obj = $obj.$p }; return ,$obj } function Set-JsonPath($obj, $path, $value) { for ($i = 0; $i -lt $path.Count - 1; $i++) { $p = $path[$i] if (-not ($obj.$p -is [System.Management.Automation.PSCustomObject])) { $obj | Add-Member -NotePropertyName $p -NotePropertyValue ([pscustomobject]@{}) -Force } $obj = $obj.$p } $obj | Add-Member -NotePropertyName $path[-1] -NotePropertyValue $value -Force } $utf8 = New-Object System.Text.UTF8Encoding($false) $raw = $null if (Test-Path -LiteralPath $target) { $raw = Get-Content -Raw -Encoding UTF8 -LiteralPath $target } if ([string]::IsNullOrWhiteSpace($raw)) { [IO.File]::WriteAllText($target, $ours + "`r`n", $utf8) Write-Host "Config angelegt: $target" } else { $existing = $null # PowerShell 7 liest JSON mit Kommentaren, beim Zurückschreiben gingen sie verloren: vorher erkennen (Strings ausgeblendet). if (($raw -replace '"(?:[^"\\]|\\.)*"', '""') -notmatch '//|/\*') { try { $existing = $raw | ConvertFrom-Json } catch { $existing = $null } } if ($existing -isnot [System.Management.Automation.PSCustomObject]) { $side = [IO.Path]::ChangeExtension($target, $null).TrimEnd('.') + '.seibertgpt.json' [IO.File]::WriteAllText($side, $ours + "`r`n", $utf8) Write-Host "Deine Config enthält Kommentare und wurde nicht verändert. Unsere liegt daneben: $side – übernimm den Block 'seibertgpt' von Hand." } else { Copy-Item -LiteralPath $target -Destination ("$target.bak-" + (Get-Date -Format 'yyyyMMdd-HHmmss')) $oursObj = $ours | ConvertFrom-Json foreach ($p in $mergePaths) { $v = Get-JsonPath $oursObj $p; if ($null -ne $v) { Set-JsonPath $existing $p $v } } foreach ($p in $absentPaths) { $v = Get-JsonPath $oursObj $p; if ($null -ne $v -and $null -eq (Get-JsonPath $existing $p)) { Set-JsonPath $existing $p $v } } [IO.File]::WriteAllText($target, ($existing | ConvertTo-Json -Depth 50) + "`r`n", $utf8) Write-Host "Config ergänzt: $target (Sicherung daneben: *.bak-...)" } } [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 try { Invoke-WebRequest -UseBasicParsing -TimeoutSec 15 -Uri 'https://api.gpt.seibert.ai/v1/models' -Headers @{ Authorization = "Bearer $key" } | Out-Null Write-Host 'Verbindung ok.' } catch { $code = 'keine Antwort' if ($_.Exception.Response) { $code = [int]$_.Exception.Response.StatusCode } if ($code -eq 401) { Write-Host 'Der Key wurde abgelehnt – ist er gesperrt? Siehe https://gpt.seibert.ai/konto/keys' } elseif ($code -eq 403) { Write-Host 'Zugriff verweigert – IP-Bindung oder kein aktiver Plan. Siehe https://gpt.seibert.ai/konto/keys' } else { Write-Host "Gateway nicht erreichbar ($code). Einrichtung ist trotzdem fertig." } } Write-Host 'Starte opencode neu und wähl mit /models „SeibertGPT“.' Write-Host 'Fertig.' }