Skip to content

Commit 8798a45

Browse files
jwfingclaude
andcommitted
fix(cli): address PR #55 review feedback
- register --branch on compute start/stop/suspend/status (was consumed by LifeOpts but never registered → "unknown option") and on services scale/upgrade (now accept opts.branch ?? p.branch) - branchMerge: default target to opts.into ?? p.branch (drop hardcoded 'main'); guard the created/skipped destructure against error bodies - dedup: export q() from services.ts and reuse it in compute.ts typecheck + build clean; 79 tests pass; --branch verified on compute + scale. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 814ed51 commit 8798a45

4 files changed

Lines changed: 19 additions & 18 deletions

File tree

src/commands/branch.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,13 @@ export async function branchDelete(name: string): Promise<void> {
4343
export async function branchMerge(source: string, opts: { into?: string } = {}): Promise<void> {
4444
const api = await ApiClient.load()
4545
const p = await requireProject()
46-
const target = opts.into ?? p.branch ?? 'main'
46+
const target = opts.into ?? p.branch
47+
if (!target) throw new Error('no target branch — pass --into <branch> (or link a branch first)')
4748
const res = await api.rawRequest('POST', `/projects/${p.projectId}/branches/${encodeURIComponent(target)}/merge`, { from: source })
4849
if (handleApproval(res)) return
49-
const { created, skipped } = res.body as {
50-
created: Array<{ type: string; name: string }>
51-
skipped: Array<{ type: string; name: string; reason: string }>
50+
const { created = [], skipped = [] } = (res.body ?? {}) as {
51+
created?: Array<{ type: string; name: string }>
52+
skipped?: Array<{ type: string; name: string; reason: string }>
5253
}
5354
info(`merged ${source}${target}: ${created.length} created, ${skipped.length} skipped`)
5455
for (const c of created) info(` + ${c.type}/${c.name}`)

src/commands/compute.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApiClient, requireProject } from '../api.js'
22
import { info, printJson, handleApproval } from '../util.js'
3-
import { resolveComputeServiceId } from './services.js'
3+
import { resolveComputeServiceId, q } from './services.js'
44

55
type Opts = { branch?: string; group?: string; json?: boolean }
66

@@ -51,7 +51,7 @@ async function lifecycle(verb: 'start' | 'stop' | 'suspend', serviceName: string
5151
const api = await ApiClient.load()
5252
const p = await requireProject()
5353
const branch = opts.branch ?? p.branch
54-
const { services } = await api.request('GET', `/projects/${p.projectId}/services${branch ? `?branch=${encodeURIComponent(branch)}` : ''}`)
54+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`)
5555
const id = resolveComputeServiceId(services, serviceName)
5656
const res = await api.rawRequest('POST', `/projects/${p.projectId}/services/${id}/${verb}`)
5757
if (handleApproval(res)) return
@@ -67,7 +67,7 @@ export async function computeStatus(serviceName: string | undefined, opts: LifeO
6767
const api = await ApiClient.load()
6868
const p = await requireProject()
6969
const branch = opts.branch ?? p.branch
70-
const { services } = await api.request('GET', `/projects/${p.projectId}/services${branch ? `?branch=${encodeURIComponent(branch)}` : ''}`)
70+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`)
7171
const id = resolveComputeServiceId(services, serviceName)
7272
const r = await api.request('GET', `/projects/${p.projectId}/services/${id}/state`)
7373
if (opts.json) return printJson(r)

src/commands/services.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { info, printJson, handleApproval, renderNextActions } from '../util.js'
55
export const SERVICE_TYPES = ['postgres', 'storage', 'compute'] as const
66
export type ServiceType = (typeof SERVICE_TYPES)[number]
77

8-
function q(branch?: string): string {
8+
export function q(branch?: string): string {
99
return branch ? `?branch=${encodeURIComponent(branch)}` : ''
1010
}
1111

@@ -106,12 +106,12 @@ export async function servicesSetAccess(type: string, name: string, access: stri
106106
}
107107

108108
// insta services scale compute <name> <number> [region]
109-
export async function servicesScale(type: string, name: string, number: string, region: string | undefined, _opts: { json?: boolean }): Promise<void> {
109+
export async function servicesScale(type: string, name: string, number: string, region: string | undefined, _opts: { json?: boolean; branch?: string }): Promise<void> {
110110
assertType(type, ['compute'])
111111
const machineCount = parseCount(number)
112112
const api = await ApiClient.load()
113113
const p = await requireProject()
114-
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(p.branch)}`)
114+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(_opts.branch ?? p.branch)}`)
115115
const id = resolveServiceId(services, type, name)
116116
const res = await api.rawRequest('POST', `/projects/${p.projectId}/services/${id}/scale`, { machineCount, region })
117117
if (handleApproval(res)) return
@@ -120,11 +120,11 @@ export async function servicesScale(type: string, name: string, number: string,
120120
}
121121

122122
// insta services upgrade <compute|postgres> <name> <new-spec>
123-
export async function servicesUpgrade(type: string, name: string, spec: string, _opts: { json?: boolean }): Promise<void> {
123+
export async function servicesUpgrade(type: string, name: string, spec: string, _opts: { json?: boolean; branch?: string }): Promise<void> {
124124
assertType(type, ['compute', 'postgres'])
125125
const api = await ApiClient.load()
126126
const p = await requireProject()
127-
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(p.branch)}`)
127+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(_opts.branch ?? p.branch)}`)
128128
const id = resolveServiceId(services, type, name)
129129
const res = await api.rawRequest('POST', `/projects/${p.projectId}/services/${id}/upgrade`, { spec })
130130
if (handleApproval(res)) return

src/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ svc.command('remove <type> <name>').description('Remove a service and destroy it
105105
svc.command('set-access <type> <name> <access>').description('Set a storage service bucket access mode (access: public|private)')
106106
.option('--json').action(guard((type, name, access, o) => services.servicesSetAccess(type, name, access, o)))
107107
svc.command('scale <type> <name> <number> [region]').description('Set a compute service machine count (paid plans only)')
108-
.option('--json').action(guard((type, name, number, region, o) => services.servicesScale(type, name, number, region, o)))
108+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((type, name, number, region, o) => services.servicesScale(type, name, number, region, o)))
109109
svc.command('upgrade <type> <name> <spec>').description('Change a compute/postgres service spec (paid plans only)')
110-
.option('--json').action(guard((type, name, spec, o) => services.servicesUpgrade(type, name, spec, o)))
110+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((type, name, spec, o) => services.servicesUpgrade(type, name, spec, o)))
111111

112112
// ---- secrets (seam) ----
113113
const sec = program.command('secrets').description('Fetch the credential bundle (secret seam) into .env')
@@ -134,13 +134,13 @@ compute.command('check-domain <host>').description("Show a custom domain's cert
134134
compute.command('remove-domain <host>').description('Detach a custom domain (gated: deploy)')
135135
.option('--branch <b>').option('--group <g>').action(guard((host, o) => computeCmd.removeDomain(host, o)))
136136
compute.command('start [service]').description('Bring a compute service online (persistent — re-enables auto-wake)')
137-
.option('--json').action(guard((service, o) => computeCmd.computeStart(service, o)))
137+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStart(service, o)))
138138
compute.command('stop [service]').description('Take a compute service offline; traffic will NOT wake it until `start`')
139-
.option('--json').action(guard((service, o) => computeCmd.computeStop(service, o)))
139+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStop(service, o)))
140140
compute.command('suspend [service]').description('Suspend a compute service (RAM snapshot); stays down until `start`')
141-
.option('--json').action(guard((service, o) => computeCmd.computeSuspend(service, o)))
141+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeSuspend(service, o)))
142142
compute.command('status [service]').description("Show a compute service's desired vs. live state")
143-
.option('--json').action(guard((service, o) => computeCmd.computeStatus(service, o)))
143+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStatus(service, o)))
144144

145145
// ---- manifest ----
146146
program.command('manifest').description('Print an agent-legible view of the project environments').option('--json').action(guard((o) => manifest(o)))

0 commit comments

Comments
 (0)