From 3f6765acc85853f0814c31b66175d95b39dcd2c2 Mon Sep 17 00:00:00 2001 From: jwfing Date: Fri, 2 Oct 2026 14:09:16 -0700 Subject: [PATCH] feat(compute): accept --cpu 16 (new 16vcpu-16gb rung) The platform adds a 16 vCPU / 16 GB shared-cpu rung and raises the paid compute ceiling to 16/16. Mirror the provider grid locally: CPU_SIZES and both --cpu help strings now list 1, 2, 4, 6, 8, 16. Co-Authored-By: Claude Opus 5.5 --- src/commands/compute.ts | 2 +- src/index.ts | 4 ++-- test/limits.test.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/compute.ts b/src/commands/compute.ts index 1c70074..91d4f2f 100644 --- a/src/commands/compute.ts +++ b/src/commands/compute.ts @@ -663,7 +663,7 @@ export const fmtMb = (mb: number) => (mb >= 1024 && mb % 512 === 0 ? `${mb / 102 // serializes as null — the server then sees {cpu: null} instead of the user seeing an error. // Enforces the provider grid the help text advertises: the server would reject 100 anyway, but a // value the client KNOWS is invalid should fail locally, matching what --help promises. -const CPU_SIZES = [1, 2, 4, 6, 8] +const CPU_SIZES = [1, 2, 4, 6, 8, 16] export function parseCpu(raw: string): number { const n = Number(raw) if (!CPU_SIZES.includes(n)) throw new Error(`invalid cpu: ${raw} (provider sizes: ${CPU_SIZES.join(', ')})`) diff --git a/src/index.ts b/src/index.ts index 4789eae..6667547 100644 --- a/src/index.ts +++ b/src/index.ts @@ -400,7 +400,7 @@ compute.command('scale [count] [service]').description('Set a compute service sa .option('--json').option('--branch ', 'branch (default: current)') .action(guard((count, service, o) => computeCmd.computeScale(count, service, o))) compute.command('limits [service]').description("Show or set a compute service's resource ceiling (any plan within the free cap; raising above it needs a paid plan). --memory is the dial; cpu derives from it unless --cpu is given. Billing is actual usage — the ceiling caps what the app may burn, it is not a price") - .option('--memory ', 'memory ceiling, e.g. 512mb or 1gb').option('--cpu ', 'vCPU ceiling override (provider sizes: 1, 2, 4, 6, 8)') + .option('--memory ', 'memory ceiling, e.g. 512mb or 1gb').option('--cpu ', 'vCPU ceiling override (provider sizes: 1, 2, 4, 6, 8, 16)') .option('--json').option('--branch ', 'branch (default: current)').action(guard((service, o) => computeCmd.computeLimits(service, o))) compute.command('always-on [service]').description('Set a compute service always-on (mode: on|off). on = machines never scale to zero; off = scale-to-zero (the default for new compute services; refused on a worker, port 0). All plans; billing is actual usage either way') .option('--json').option('--branch ', 'branch (default: current)').action(guard((mode, service, o) => computeCmd.computeAlwaysOn(mode, service, o))) @@ -493,7 +493,7 @@ for (const type of ['redis', 'mysql', 'mongodb'] as const) { .option('--json').option('--branch ', 'branch (default: current)') .action(guard((service, o) => managedDb.managedStatus(type, service, o))) g.command('limits [service]').description(`Show or set a ${type} service's resource ceiling (any plan within the free cap; raising above it needs a paid plan). --memory is the dial; cpu derives from it unless --cpu is given. Billing is actual usage — the ceiling caps what the database may burn, it is not a price`) - .option('--memory ', 'memory ceiling, e.g. 512mb or 1gb').option('--cpu ', 'vCPU ceiling override (provider sizes: 1, 2, 4, 6, 8)') + .option('--memory ', 'memory ceiling, e.g. 512mb or 1gb').option('--cpu ', 'vCPU ceiling override (provider sizes: 1, 2, 4, 6, 8, 16)') .option('--json').option('--branch ', 'branch (default: current)') .action(guard((service, o) => computeCmd.serviceLimits(type, service, o))) g.command('volume [service]').description(`Show, attach, or grow a ${type} service's data volume (the image's data directory). No flag: size and the plan cap (any plan). --size on a volumeless service ATTACHES one (any plan up to its own plan cap; a size above the free cap is paid); on a volume-bearing one it grows (paid plans; grow-only once attached — a provisioned disk cannot shrink). A managed database's volume cannot be deleted — remove the service instead. Billing is actual data stored — the size is a cap, not a price`) diff --git a/test/limits.test.ts b/test/limits.test.ts index 5e4c620..2a38d7b 100644 --- a/test/limits.test.ts +++ b/test/limits.test.ts @@ -45,10 +45,10 @@ import { parseDbCpu, parseDbMemory, fmtMib, alwaysOnArgs, alwaysOnLine, alwaysOn describe('parseCpu (compute --cpu override)', () => { it('accepts exactly the provider grid the help text advertises', () => { - for (const n of [1, 2, 4, 6, 8]) expect(parseCpu(String(n))).toBe(n) + for (const n of [1, 2, 4, 6, 8, 16]) expect(parseCpu(String(n))).toBe(n) }) it('throws locally on junk AND on off-grid sizes instead of deferring to the server', () => { - for (const raw of ['abc', '', '-2', '1.5', 'two', '3', '100']) { + for (const raw of ['abc', '', '-2', '1.5', 'two', '3', '12', '32', '100']) { expect(() => parseCpu(raw), raw).toThrow(/invalid cpu/) } })