diff --git a/src/index.ts b/src/index.ts index 72be940..a466a2b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -136,7 +136,7 @@ svc.command('add [type] [name]').description('Provision a service on demand (ass .option('--image ', 'compute only: run this container image at creation') .option('--port ', 'compute only: port the image listens on (default 8080)') .option('--always-on', 'compute only: create as always-on — never scales to zero (all plans; billing is actual usage either way)') - .option('--volume ', 'compute only: attach a persistent /data volume of this many whole Gi (also attachable later: `insta compute volume --size `; any plan may attach at the default 1; larger sizes are paid and plan-capped). Volume services keep 1 machine and stop (cold wake) instead of suspend when idle') + .option('--volume ', 'compute only: attach a persistent /data volume of this many whole Gi (also attachable later: `insta compute volume --size `; any plan may attach at the default 10 (the free cap, on every plan); larger sizes are paid and plan-capped). Volume services keep 1 machine and stop (cold wake) instead of suspend when idle') .option('--json') .action(guard(async (type, name, o) => { const a = await resolveServiceArgs(type, name, serviceArgsDeps(o.json), o) @@ -233,7 +233,7 @@ compute.command('restart [service]').description("Restart a compute service by r .option('--json').option('--branch ', 'branch (default: current)').action(guard((service, o) => computeCmd.computeRestart(service, o))) compute.command('status [service]').description("Show a compute service's desired vs. live state") .option('--json').option('--branch ', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStatus(service, o))) -compute.command('limits [service]').description("Show or set a compute service's resource ceiling (paid plans). --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") +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('--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 = default scale-to-zero. All plans; billing is actual usage either way') @@ -243,7 +243,7 @@ const execCmd = compute.command('exec [service]').description("Run a one-shot co // Declared from the same list splitExecArgs uses to find where the CLI's own arguments stop, so a // new option cannot reach the CLI surface while the split still reads it as part of the command. for (const [flags, description] of computeCmd.EXEC_OPTIONS) execCmd.option(flags, description) -compute.command('volume [service]').description("Show, attach, grow, or delete a compute service's persistent /data volume. No flag: print size, mount path, and the plan cap (any plan). --size on a volumeless service ATTACHES one (any plan at the default 1Gi; larger is paid and plan-capped; the disk mounts at /data on the next deploy); on a volume-bearing one it grows (paid plans; grow-only — a provisioned disk cannot shrink). --delete DESTROYS the disk and ALL its data immediately (no detach, no undo; billing stops now, and suspend fast-wake + scale-out return). Billing is actual data stored — the size is a cap, not a price") +compute.command('volume [service]').description("Show, attach, grow, or delete a compute service's persistent /data volume. No flag: print size, mount path, and the plan cap (any plan). --size on a volumeless service ATTACHES one (any plan at the default 10Gi, the free cap; larger is paid and plan-capped; the disk mounts at /data on the next deploy); on a volume-bearing one it grows (paid plans; grow-only — a provisioned disk cannot shrink). --delete DESTROYS the disk and ALL its data immediately (no detach, no undo; billing stops now, and suspend fast-wake + scale-out return). Billing is actual data stored — the size is a cap, not a price") .option('--size ', 'new size in whole Gi, e.g. 10 (must be ≥ the current size)') .option('--delete', 'destroy the volume and ALL its data (irreversible; download anything you need first)') .option('--json').option('--branch ', 'branch (default: current)').action(guard((service, o) => computeCmd.computeVolume(service, o))) @@ -256,7 +256,7 @@ db.command('url').description('Print the postgres connection string (DSN) — ba db.command('connect').description("Open an interactive psql session on the postgres service (needs psql on PATH; gated: secrets.read). A suspended instance wakes on connect — the first prompt can take a few seconds. Exits with psql's own exit code") .option('--branch ', 'branch (default: current)').option('--group ', 'postgres service name (default: the sole/default one)') .action(guard((o) => dbCmd.dbConnect(o))) -db.command('limits').description("Show or set a postgres service's resource ceiling (paid plans; insta-db-backed only). Moves both directions") +db.command('limits').description("Show or set a postgres service's resource ceiling (any plan within the free cap, paid above it; insta-db-backed only). Moves both directions") .option('--cpu ', "vCPU ceiling, e.g. 2 or 2500m").option('--memory ', "memory ceiling, e.g. 4Gi") .option('--json').option('--branch ', 'branch (default: current)').option('--group ', 'postgres service name (default: the sole/default one)') .action(guard((o) => dbCmd.dbLimits(o))) diff --git a/test/volume.test.ts b/test/volume.test.ts index ce65db1..a0cb39a 100644 --- a/test/volume.test.ts +++ b/test/volume.test.ts @@ -35,8 +35,9 @@ describe('servicesAddRequestBody --volume', () => { it('omits volumeGib when the flag is absent (no volume attached)', () => { expect(servicesAddRequestBody('compute', 'api', 'main', {})).not.toHaveProperty('volumeGib') }) - // The free-plan rule: any plan may pass 1 (the default size) — and larger values just forward; - // the backend enforces paid/cap, so no client-side plan check exists to test against. + // The free-plan rule: any plan may pass a size up to the free cap (the platform's sizeless default, + // 10Gi) — and larger values just forward; the backend enforces paid/cap, so no client-side plan + // check exists to test against. it('forwards any whole size unjudged — the backend owns the paid/cap gate', () => { expect(servicesAddRequestBody('compute', 'api', 'main', { volume: '100' })).toMatchObject({ volumeGib: 100 }) })