Initial GESIS OpenCode installer

This commit is contained in:
aseimel
2026-06-29 19:36:31 +02:00
commit cf0a5e515d
14 changed files with 1656 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
# Local SSH key used only by Codex for pushing this repository.
.ssh/
# Build/download leftovers.
*.download
*.tmp
bin/
obj/
# Local editor and OS metadata.
.vs/
.vscode/
Thumbs.db
Desktop.ini
+84
View File
@@ -0,0 +1,84 @@
#Requires -Version 5.1
$ErrorActionPreference = "Stop"
$sourcePath = Join-Path $PSScriptRoot "GesisOpenCodeInstaller.cs"
$outputPath = Join-Path $PSScriptRoot "GESIS-OpenCode-Installer.exe"
$logoPath = Join-Path $PSScriptRoot "GESIS Logo Blau EN.jpg"
$signetPath = Join-Path $PSScriptRoot "GESIS Signet Blau_transp.png"
$iconPath = Join-Path $PSScriptRoot "GESIS-OpenCode-Installer.ico"
$manifestPath = Join-Path $PSScriptRoot "app.manifest"
$cscPath = Join-Path $env:WINDIR "Microsoft.NET\Framework64\v4.0.30319\csc.exe"
if (-not (Test-Path -LiteralPath $cscPath)) {
throw "Could not find the .NET Framework C# compiler at $cscPath"
}
if (-not (Test-Path -LiteralPath $logoPath)) {
throw "Could not find logo file: $logoPath"
}
if (-not (Test-Path -LiteralPath $signetPath)) {
throw "Could not find signet file: $signetPath"
}
if (-not (Test-Path -LiteralPath $manifestPath)) {
throw "Could not find application manifest: $manifestPath"
}
Add-Type -AssemblyName System.Drawing
$pngBytes = [System.IO.File]::ReadAllBytes($signetPath)
$image = [System.Drawing.Image]::FromFile($signetPath)
try {
$width = [Math]::Min($image.Width, 255)
$height = [Math]::Min($image.Height, 255)
}
finally {
$image.Dispose()
}
$stream = [System.IO.File]::Open($iconPath, [System.IO.FileMode]::Create)
try {
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.Write([UInt16]0)
$writer.Write([UInt16]1)
$writer.Write([UInt16]1)
$writer.Write([Byte]$width)
$writer.Write([Byte]$height)
$writer.Write([Byte]0)
$writer.Write([Byte]0)
$writer.Write([UInt16]1)
$writer.Write([UInt16]32)
$writer.Write([UInt32]$pngBytes.Length)
$writer.Write([UInt32]22)
$writer.Write($pngBytes)
$writer.Flush()
}
finally {
$stream.Dispose()
}
$compilerArgs = @(
"/target:winexe",
"/platform:x64",
"/optimize+",
"/win32icon:$iconPath",
"/win32manifest:$manifestPath",
"/out:$outputPath",
"/resource:$logoPath,GesisLogo",
"/resource:$iconPath,GesisIcon",
"/reference:System.dll",
"/reference:System.Core.dll",
"/reference:System.Drawing.dll",
"/reference:System.Web.Extensions.dll",
"/reference:System.Windows.Forms.dll",
$sourcePath
)
& $cscPath $compilerArgs
if ($LASTEXITCODE -ne 0) {
throw "Compilation failed with exit code $LASTEXITCODE"
}
Write-Host "Built $outputPath"
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.
File diff suppressed because it is too large Load Diff
+169
View File
@@ -0,0 +1,169 @@
#Requires -Version 5.1
[CmdletBinding()]
param(
[switch]$ConfigOnly,
[switch]$SkipDesktopInstall,
[switch]$SilentDesktopInstall,
[string]$GitHubToken = $env:GITHUB_TOKEN,
[string]$ConfigPath = (Join-Path $env:USERPROFILE ".config\opencode\opencode.json")
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$repo = "anomalyco/opencode"
$windowsAssetName = "opencode-desktop-win-x64.exe"
$releaseApiUrl = "https://api.github.com/repos/$repo/releases/latest"
$baseUrl = "https://ai-openwebui.gesis.org/api"
function Write-Step {
param([string]$Message)
Write-Host ""
Write-Host "==> $Message" -ForegroundColor Cyan
}
function ConvertFrom-SecureStringToPlainText {
param([Parameter(Mandatory = $true)][securestring]$SecureString)
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
try {
[Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
}
finally {
if ($bstr -ne [IntPtr]::Zero) {
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
}
}
}
function Invoke-GitHubGet {
param([Parameter(Mandatory = $true)][string]$Uri)
$headers = @{
"Accept" = "application/vnd.github+json"
"User-Agent" = "GESIS-OpenCode-Installer"
}
if (-not [string]::IsNullOrWhiteSpace($GitHubToken)) {
$headers["Authorization"] = "Bearer $GitHubToken"
}
Invoke-RestMethod -Uri $Uri -Headers $headers -Method Get
}
function Install-OpenCodeDesktop {
if ($SkipDesktopInstall -or $ConfigOnly) {
Write-Host "Skipping OpenCode Desktop installation."
return
}
if (-not [Environment]::Is64BitOperatingSystem) {
throw "This installer expects 64-bit Windows because OpenCode publishes a Windows x64 desktop installer."
}
Write-Step "Finding latest OpenCode Desktop release"
$release = Invoke-GitHubGet -Uri $releaseApiUrl
$asset = $release.assets | Where-Object { $_.name -eq $windowsAssetName } | Select-Object -First 1
if ($null -eq $asset) {
throw "Could not find $windowsAssetName in the latest $repo release ($($release.tag_name))."
}
Write-Host "Latest release: $($release.tag_name)"
Write-Host "Downloading: $($asset.name)"
$downloadPath = Join-Path $env:TEMP $asset.name
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $downloadPath -Headers @{ "User-Agent" = "GESIS-OpenCode-Installer" }
Write-Step "Starting OpenCode Desktop installer"
if ($SilentDesktopInstall) {
$process = Start-Process -FilePath $downloadPath -ArgumentList "/S" -Wait -PassThru
}
else {
$process = Start-Process -FilePath $downloadPath -Wait -PassThru
}
if ($process.ExitCode -ne 0) {
throw "OpenCode Desktop installer exited with code $($process.ExitCode)."
}
}
function New-GesisOpenCodeConfig {
param([Parameter(Mandatory = $true)][string]$ApiKey)
[ordered]@{
'$schema' = 'https://opencode.ai/config.json'
enabled_providers = @('gesis')
disabled_providers = @('zen', 'opencode')
provider = [ordered]@{
gesis = [ordered]@{
npm = '@ai-sdk/openai-compatible'
name = 'GESIS AI Server'
options = [ordered]@{
baseURL = $baseUrl
apiKey = $ApiKey
}
models = [ordered]@{
'gemma3:27b' = @{ name = 'Gemma 3 27B' }
'gpt-4.1' = @{ name = 'GPT-4.1' }
'gpt-4.1-mini' = @{ name = 'GPT-4.1 Mini' }
'llama4:latest' = @{ name = 'Llama 4 Latest' }
'o4-mini' = @{ name = 'O4 Mini' }
'de-fr' = @{ name = 'De-Fr Translation' }
'de-ru' = @{ name = 'De-Ru Translation' }
'en-de' = @{ name = 'En-De Translation' }
'en-fr' = @{ name = 'En-Fr Translation' }
'en-ru' = @{ name = 'En-Ru Translation' }
'pdf-extractor' = @{ name = 'PDF Extractor' }
'gpt-5' = @{ name = 'GPT-5' }
'gpt-5-mini' = @{ name = 'GPT-5 Mini' }
'gpt-oss:120b' = @{ name = 'GPT-OSS 120B' }
'gpt-oss:latest' = @{ name = 'GPT-OSS Latest' }
}
}
}
}
}
function Write-OpenCodeConfig {
Write-Step "Configuring GESIS AI Server"
$secureApiKey = Read-Host "Enter your personal GESIS AI Server API key" -AsSecureString
$apiKey = ConvertFrom-SecureStringToPlainText -SecureString $secureApiKey
if ([string]::IsNullOrWhiteSpace($apiKey)) {
throw "API key cannot be empty."
}
$configDirectory = Split-Path -Parent $ConfigPath
New-Item -Path $configDirectory -ItemType Directory -Force | Out-Null
if (Test-Path -LiteralPath $ConfigPath) {
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$backupPath = "$ConfigPath.backup-$timestamp"
Copy-Item -LiteralPath $ConfigPath -Destination $backupPath -Force
Write-Host "Existing config backed up to: $backupPath"
}
$config = New-GesisOpenCodeConfig -ApiKey $apiKey
$json = $config | ConvertTo-Json -Depth 20
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($ConfigPath, $json, $utf8NoBom)
Write-Host "OpenCode config written to: $ConfigPath"
}
try {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Install-OpenCodeDesktop
Write-OpenCodeConfig
Write-Step "Done"
Write-Host "OpenCode Desktop is installed and configured for the GESIS AI Server."
}
catch {
Write-Host ""
Write-Host "Installation failed: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
+52
View File
@@ -0,0 +1,52 @@
# GESIS OpenCode Desktop Installer
This folder contains a Windows GUI installer for OpenCode Desktop that configures the GESIS AI Server provider.
The installer:
- downloads the latest Windows x64 OpenCode Desktop release from `anomalyco/opencode`
- starts the official OpenCode Desktop installer
- asks each user for their personal GESIS AI Server API key
- checks the key against the GESIS AI Server before installing
- shows all models available to that key in a checkbox grid with every model selected by default
- writes only the selected models into the OpenCode config
- writes the OpenCode config to `%USERPROFILE%\.config\opencode\opencode.json`
- restricts OpenCode to the GESIS provider with `enabled_providers`
- explicitly disables known Zen/OpenCode default provider IDs
- backs up an existing config before replacing it
## Install
For normal users, distribute and run:
`GESIS-OpenCode-Installer.exe`
They paste their personal GESIS API key, click **Check API key**, choose which available models they want to use in OpenCode from the checkbox grid, and click **Install selected models**.
The installer starts compact for API-key entry, then maximizes automatically after models are found so the model grid is visible. The main action buttons stay fixed at the bottom of the window, and only the content area scrolls as a fallback for high Windows text scaling or very large model sets.
## Rebuild the EXE
Open PowerShell in this folder and run:
```powershell
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\Build-GuiInstaller.ps1
```
The older PowerShell installer is kept as an administrator fallback:
```powershell
.\Install-OpenCode-GESIS.ps1
```
## Files
- `GESIS-OpenCode-Installer.exe` is the GUI installer for distribution.
- `GesisOpenCodeInstaller.cs` is the GUI installer source.
- `Build-GuiInstaller.ps1` rebuilds the GUI installer.
- `app.manifest` keeps the installer DPI-aware on Windows.
- `GESIS Logo Blau EN.jpg` and `GESIS Signet Blau_transp.png` are embedded into the EXE when it is rebuilt.
- `Install-OpenCode-GESIS.ps1` is the PowerShell fallback installer.
- `opencode.gesis.template.json` is a safe template with no personal API key.
- `opencode.json` mirrors the template and no longer contains a real API key.
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="GESIS.OpenCode.Installer"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">system</dpiAwareness>
</windowsSettings>
</application>
</assembly>
+67
View File
@@ -0,0 +1,67 @@
{
"$schema": "https://opencode.ai/config.json",
"enabled_providers": [
"gesis"
],
"disabled_providers": [
"zen",
"opencode"
],
"provider": {
"gesis": {
"npm": "@ai-sdk/openai-compatible",
"name": "GESIS AI Server",
"options": {
"baseURL": "https://ai-openwebui.gesis.org/api",
"apiKey": "REPLACE_WITH_PERSONAL_API_KEY"
},
"models": {
"gemma3:27b": {
"name": "Gemma 3 27B"
},
"gpt-4.1": {
"name": "GPT-4.1"
},
"gpt-4.1-mini": {
"name": "GPT-4.1 Mini"
},
"llama4:latest": {
"name": "Llama 4 Latest"
},
"o4-mini": {
"name": "O4 Mini"
},
"de-fr": {
"name": "De-Fr Translation"
},
"de-ru": {
"name": "De-Ru Translation"
},
"en-de": {
"name": "En-De Translation"
},
"en-fr": {
"name": "En-Fr Translation"
},
"en-ru": {
"name": "En-Ru Translation"
},
"pdf-extractor": {
"name": "PDF Extractor"
},
"gpt-5": {
"name": "GPT-5"
},
"gpt-5-mini": {
"name": "GPT-5 Mini"
},
"gpt-oss:120b": {
"name": "GPT-OSS 120B"
},
"gpt-oss:latest": {
"name": "GPT-OSS Latest"
}
}
}
}
}
+67
View File
@@ -0,0 +1,67 @@
{
"$schema": "https://opencode.ai/config.json",
"enabled_providers": [
"gesis"
],
"disabled_providers": [
"zen",
"opencode"
],
"provider": {
"gesis": {
"npm": "@ai-sdk/openai-compatible",
"name": "GESIS AI Server",
"options": {
"baseURL": "https://ai-openwebui.gesis.org/api",
"apiKey": "REPLACE_WITH_PERSONAL_API_KEY"
},
"models": {
"gemma3:27b": {
"name": "Gemma 3 27B"
},
"gpt-4.1": {
"name": "GPT-4.1"
},
"gpt-4.1-mini": {
"name": "GPT-4.1 Mini"
},
"llama4:latest": {
"name": "Llama 4 Latest"
},
"o4-mini": {
"name": "O4 Mini"
},
"de-fr": {
"name": "De-Fr Translation"
},
"de-ru": {
"name": "De-Ru Translation"
},
"en-de": {
"name": "En-De Translation"
},
"en-fr": {
"name": "En-Fr Translation"
},
"en-ru": {
"name": "En-Ru Translation"
},
"pdf-extractor": {
"name": "PDF Extractor"
},
"gpt-5": {
"name": "GPT-5"
},
"gpt-5-mini": {
"name": "GPT-5 Mini"
},
"gpt-oss:120b": {
"name": "GPT-OSS 120B"
},
"gpt-oss:latest": {
"name": "GPT-OSS Latest"
}
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
# GESIS OpenCode Installer Source
This folder contains the source and rebuild materials for `GESIS-OpenCode-Installer.exe`.
To rebuild on Windows:
```powershell
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\Build-GuiInstaller.ps1
```
The built EXE embeds the GESIS logo assets and writes a user-specific OpenCode configuration after probing the GESIS AI Server for models available to the user's API key.