fix(hetzner): update deprecated server types to cx23/cpx22 gen (#1983)

* fix(hetzner): update deprecated cx22/cpx21 server types to cx23/cpx22

Hetzner deprecated the entire cx*2 and cpx*1 server lines on Jan 1, 2026.
New orders fail with "server type is deprecated". Updates to the current
gen3 CX and gen2 CPX lines (cx23, cx33, cx43, cx53, cpx22, cpx32).

Also shows the server type picker by default instead of requiring --custom,
so users can choose their instance size on every deploy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(zeroclaw): append autonomy config instead of overwriting onboard output

zeroclaw onboard generates a complete config with required fields like
default_temperature. Our setup was overwriting that with a partial config
missing required fields, causing a crash loop on startup. Now appends
the security/shell settings instead so onboard's fields are preserved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: fix biome formatting in agent-setup.ts

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Agent: pr-maintainer

---------

Co-authored-by: spawn-bot <spawn-bot@openrouter.ai>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
This commit is contained in:
A 2026-02-27 00:20:31 -08:00 committed by GitHub
parent 3e0b35e23d
commit d8131c3df6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 24 additions and 23 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@openrouter/spawn",
"version": "0.11.1",
"version": "0.11.2",
"type": "module",
"bin": {
"spawn": "cli.js"

View file

@ -146,9 +146,10 @@ describe("Hetzner --custom prompts", () => {
restoreEnv("HETZNER_LOCATION", savedLocation);
});
it("promptServerType should return default without --custom", async () => {
it("promptServerType should return default in non-interactive mode", async () => {
delete process.env.HETZNER_SERVER_TYPE;
delete process.env.SPAWN_CUSTOM;
process.env.SPAWN_NON_INTERACTIVE = "1";
const { promptServerType, DEFAULT_SERVER_TYPE } = await import("../hetzner/hetzner");
const result = await promptServerType();
expect(result).toBe(DEFAULT_SERVER_TYPE);

View file

@ -276,32 +276,32 @@ export interface ServerTypeTier {
export const SERVER_TYPES: ServerTypeTier[] = [
{
id: "cx22",
label: "2 vCPU \u00b7 4 GB RAM \u00b7 40 GB (~\u20AC3.29/mo)",
id: "cx23",
label: "cx23 \u00b7 2 vCPU \u00b7 4 GB \u00b7 40 GB (~\u20AC3.49/mo, EU only)",
},
{
id: "cx32",
label: "4 vCPU \u00b7 8 GB RAM \u00b7 80 GB (~\u20AC5.39/mo)",
id: "cx33",
label: "cx33 \u00b7 4 vCPU \u00b7 8 GB \u00b7 80 GB (~\u20AC6.49/mo, EU only)",
},
{
id: "cx42",
label: "8 vCPU \u00b7 16 GB RAM \u00b7 160 GB (~\u20AC14.49/mo)",
id: "cx43",
label: "cx43 \u00b7 8 vCPU \u00b7 16 GB \u00b7 160 GB (~\u20AC14.49/mo, EU only)",
},
{
id: "cx52",
label: "16 vCPU \u00b7 32 GB RAM \u00b7 320 GB (~\u20AC28.49/mo)",
id: "cx53",
label: "cx53 \u00b7 16 vCPU \u00b7 32 GB \u00b7 320 GB (~\u20AC28.49/mo, EU only)",
},
{
id: "cpx21",
label: "3 AMD vCPU \u00b7 4 GB RAM \u00b7 80 GB (~\u20AC4.35/mo)",
id: "cpx22",
label: "cpx22 \u00b7 3 AMD vCPU \u00b7 4 GB \u00b7 80 GB (~\u20AC5.49/mo)",
},
{
id: "cpx31",
label: "4 AMD vCPU \u00b7 8 GB RAM \u00b7 160 GB (~\u20AC7.59/mo)",
id: "cpx32",
label: "cpx32 \u00b7 4 AMD vCPU \u00b7 8 GB \u00b7 160 GB (~\u20AC9.49/mo)",
},
];
export const DEFAULT_SERVER_TYPE = "cx22";
export const DEFAULT_SERVER_TYPE = "cx23";
// ─── Location Options ────────────────────────────────────────────────────────
@ -343,10 +343,6 @@ export async function promptServerType(): Promise<string> {
return process.env.HETZNER_SERVER_TYPE;
}
if (process.env.SPAWN_CUSTOM !== "1") {
return DEFAULT_SERVER_TYPE;
}
if (process.env.SPAWN_NON_INTERACTIVE === "1") {
return DEFAULT_SERVER_TYPE;
}

View file

@ -381,8 +381,11 @@ export async function setupZeroclawConfig(runner: CloudRunner, _apiKey: string):
`source ~/.spawnrc 2>/dev/null; export PATH="$HOME/.cargo/bin:$PATH"; zeroclaw onboard --api-key "\${OPENROUTER_API_KEY}" --provider openrouter`,
);
// Write autonomy config — equivalent to Claude Code's dangerouslySkipPermissions
const config = `[security]
// Patch autonomy settings into the config generated by `zeroclaw onboard`.
// We append rather than overwrite so we keep the fields onboard wrote
// (api_key, default_provider, default_model, default_temperature, etc.).
const patch = `
[security]
autonomy = "full"
supervised = false
allow_destructive = true
@ -390,7 +393,8 @@ allow_destructive = true
[shell]
policy = "allow_all"
`;
await uploadConfigFile(runner, config, "$HOME/.zeroclaw/config.toml");
const patchB64 = Buffer.from(patch).toString("base64");
await runner.runServer(`printf '%s' '${patchB64}' | base64 -d >> ~/.zeroclaw/config.toml`);
logInfo("ZeroClaw configured for autonomous operation");
}

View file

@ -1,4 +1,4 @@
export HCLOUD_TOKEN="test-token-hetzner"
export HETZNER_SERVER_NAME="test-srv"
export HETZNER_SERVER_TYPE="cx22"
export HETZNER_SERVER_TYPE="cx23"
export HETZNER_LOCATION="fsn1"