| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- #!/usr/bin/env pwsh
- # fleet-worker.ps1 - run a cheap headless Claude Code worker on a non-Anthropic model (PowerShell).
- #
- # Thin launcher: points Claude Code (`claude -p`) at any Anthropic-compatible
- # endpoint (default: z.ai / GLM) via env, inside an ISOLATED config dir, then
- # runs it. The result is a headless agent with Claude Code's full tool harness
- # but a cheaper "grunt" brain. See ../SKILL.md.
- #
- # Usage: fleet-worker.ps1 [-Help] [claude-flags...] "PROMPT"
- # Output: whatever `claude -p` emits (text, or --output-format json/stream-json)
- # Exit: 0 ok; 1 worker/API error; 5 missing dep / no key resolved
- #
- # Config (env, all optional - defaults target the z.ai GLM Coding Plan):
- # FLEET_WORKER_CONFIG_DIR isolated CLAUDE_CONFIG_DIR (default ~/.fleet-worker/cfg)
- # FLEET_WORKER_BASE_URL Anthropic-compatible endpoint (default z.ai)
- # FLEET_WORKER_MODEL main model (default GLM-5.2)
- # FLEET_WORKER_SMALL_MODEL background model (default GLM-4.5-Air)
- # FLEET_WORKER_EFFORT seeded effortLevel (default high)
- # Key resolution order (the key is never printed):
- # 1. ANTHROPIC_AUTH_TOKEN (already set) -> used as-is
- # 2. FLEET_WORKER_KEYRING_SERVICE + FLEET_WORKER_KEYRING_KEY -> `keyring get svc key`
- # 3. ZHIPU_API_KEY / GLM_API_KEY -> used as-is
- #
- # Examples:
- # ./fleet-worker.ps1 "List the TODOs under src/ and summarize them"
- # ./fleet-worker.ps1 --output-format json "Refactor utils.py"
- $ErrorActionPreference = 'Stop'
- if ($args.Count -ge 1 -and ($args[0] -eq '-Help' -or $args[0] -eq '--help' -or $args[0] -eq '-h')) {
- Get-Content $PSCommandPath | Select-Object -Skip 1 |
- ForEach-Object { if ($_ -match '^#') { $_ -replace '^# ?', '' } else { return } }
- exit 0
- }
- # Auth isolation (LOAD-BEARING; see references/fleet-worker-spec.md sec 4): a dedicated
- # config dir => the worker inherits no host Claude.ai OAuth account, so our token
- # is the only credential and actually reaches the endpoint (else 401).
- $cfg = if ($env:FLEET_WORKER_CONFIG_DIR) { $env:FLEET_WORKER_CONFIG_DIR } `
- else { Join-Path $HOME '.fleet-worker/cfg' }
- New-Item -ItemType Directory -Force -Path $cfg | Out-Null
- $settings = Join-Path $cfg 'settings.json'
- if (-not (Test-Path $settings)) {
- $effort = if ($env:FLEET_WORKER_EFFORT) { $env:FLEET_WORKER_EFFORT } else { 'high' }
- "{ ""hooks"": {}, ""effortLevel"": ""$effort"" }" | Set-Content -Path $settings -Encoding utf8
- }
- $env:CLAUDE_CONFIG_DIR = $cfg
- # Resolve the API key (never printed). .Trim() strips trailing CRLF from `keyring get`.
- function Resolve-GlmKey {
- if ($env:ANTHROPIC_AUTH_TOKEN) { return $env:ANTHROPIC_AUTH_TOKEN }
- if ($env:FLEET_WORKER_KEYRING_SERVICE -and $env:FLEET_WORKER_KEYRING_KEY -and (Get-Command keyring -ErrorAction SilentlyContinue)) {
- $k = (keyring get $env:FLEET_WORKER_KEYRING_SERVICE $env:FLEET_WORKER_KEYRING_KEY 2>$null)
- if ($k) { return ($k | Out-String).Trim() }
- }
- if ($env:ZHIPU_API_KEY) { return $env:ZHIPU_API_KEY }
- if ($env:GLM_API_KEY) { return $env:GLM_API_KEY }
- return $null
- }
- $key = Resolve-GlmKey
- if (-not $key) {
- Write-Error @'
- fleet-worker: no API key resolved. Provide one of:
- - $env:ANTHROPIC_AUTH_TOKEN = '<key>'
- - $env:FLEET_WORKER_KEYRING_SERVICE / FLEET_WORKER_KEYRING_KEY (uses `keyring get`)
- - $env:ZHIPU_API_KEY = '<key>' (or GLM_API_KEY)
- '@
- exit 5
- }
- if (-not (Get-Command claude -ErrorAction SilentlyContinue)) {
- Write-Error "fleet-worker: 'claude' (Claude Code) not found on PATH"; exit 5
- }
- $env:ANTHROPIC_BASE_URL = if ($env:FLEET_WORKER_BASE_URL) { $env:FLEET_WORKER_BASE_URL } else { 'https://api.z.ai/api/anthropic' }
- $env:ANTHROPIC_AUTH_TOKEN = $key
- $env:ANTHROPIC_DEFAULT_OPUS_MODEL = if ($env:FLEET_WORKER_MODEL) { $env:FLEET_WORKER_MODEL } else { 'GLM-5.2' }
- $env:ANTHROPIC_DEFAULT_SONNET_MODEL = $env:ANTHROPIC_DEFAULT_OPUS_MODEL
- $env:ANTHROPIC_DEFAULT_HAIKU_MODEL = if ($env:FLEET_WORKER_SMALL_MODEL) { $env:FLEET_WORKER_SMALL_MODEL } else { 'GLM-4.5-Air' }
- claude -p --model sonnet --permission-mode bypassPermissions @args
- exit $LASTEXITCODE
|