Skip to content

feat: services add --region + insta regions#61

Merged
jwfing merged 3 commits into
mainfrom
devel
Jul 21, 2026
Merged

feat: services add --region + insta regions#61
jwfing merged 3 commits into
mainfrom
devel

Conversation

@jwfing

@jwfing jwfing commented Jul 20, 2026

Copy link
Copy Markdown
Member

insta region support

Adds the CLI surface for user-selectable service regions.

  • insta services add <type> <name> --region <slug> — sends the InstaCloud region slug (e.g. us-east) in the add-service body. Client-side guards: --region is rejected for storage; --public only for storage. Validation runs before any network / project resolution (fail-fast on a bad flag).
  • insta regions — lists the available regions from GET /regions (supports --json).
  • The region-body-building logic lives in a pure, unit-tested buildAddServiceBody(...).

Depends on the platform PR (region on addService + GET /regions). Requires a matching skills/insta/cli-reference.md update (separate PR).

Testing

Full CLI suite green — 95 tests (incl. new test/services-add-body.test.ts); typecheck clean.

🤖 Generated with Claude Code


Summary by cubic

Adds region support to the CLI so users can pick a region when creating postgres/compute services and list available regions. Also unifies option handling with --image/--port, improves help text, and keeps validation fail-fast.

  • New Features

    • insta services add <type> <name> --region <slug> for postgres/compute; --region is rejected for storage; --public only for storage. Region is sent in the request body.
    • insta regions lists regions from GET /regions and supports --json.
    • Success output now includes the service region.
  • Refactors

    • Folded region into servicesAddRequestBody alongside --image/--port; updated CLI help in services add.
    • Removed the old body builder and its test; moved region tests to test/services.test.ts.

Written for commit 432213d. Summary will update on new commits.

Review in cubic

jwfing and others added 2 commits July 20, 2026 15:43
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@jwfing jwfing left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: feat: services add --region + insta regions

Summary: A clean, well-scoped addition of user-selectable service regions — a new insta regions command and a --region flag on services add, with the body-building logic extracted into a pure, unit-tested helper. No blocking issues found.

Requirements context

No matching spec/plan found — this repo has no docs/superpowers/ or docs/specs/ directory, so I assessed against the PR description and the repo conventions in AGENTS.md / .claude/skills/developing-insta-cli/SKILL.md alone.

Findings

Critical

(none)

Suggestion

  • Functionality — src/commands/regions.ts:7-9: const { regions } = await api.request('GET', '/regions') followed by for (const r of regions) will throw a non-iterable TypeError if the platform ever returns a body without a regions array. This mirrors the existing servicesList pattern ({ services } destructure with no guard), so it's consistent with the codebase and low-risk given the platform is the sole caller — noting it only as a hardening opportunity (e.g. for (const r of regions ?? [])), not a defect.

Information

  • SW engineering — test/services-add-body.test.ts:1: Uses the test / expect API, whereas the sibling suite test/services.test.ts uses describe / it. Both are valid in vitest; flagging only for stylistic consistency across the test dir.
  • Functionality — src/commands/services.ts:52,61: buildAddServiceBody embeds branch into the returned body, but servicesAdd then re-spreads the resolved branch (opts.branch ?? p.branch) over it. The result is correct (the resolved branch always wins, and the pure function's branch behavior is deliberately unit-tested), just mildly redundant — the branch is handled in two places.
  • Process — AGENTS.md non-negotiable #4: Command/flag changes must be mirrored in skills/insta/cli-reference.md. That file lives in the insta-cloud superproject submodule (not present in this repo), and the PR body already notes the mirror update ships as a separate PR — just a reminder to land it so the agent-facing surface doc stays in sync.

Dimension coverage

  • Software engineering ✅ — new pure helper buildAddServiceBody is unit-tested, matching the repo convention of testing pure helpers while leaving I/O command wrappers (servicesList, regionsList) untested. The --public guard moving into the tested helper is a net improvement.
  • Functionality ✅ — validation is genuinely fail-fast: assertType + buildAddServiceBody run before ApiClient.load()/requireProject(), so a bad --region/--public flag errors without any network or project resolution, exactly as the PR claims. Guards (--region rejected for storage, --public only for storage) are correct and tested.
  • Security ✅ — no security-relevant risk: the region slug travels in a JSON request body (parameterized, no SQL/shell surface), nothing new is logged or returned, no auth/authorization paths change, and no dependencies are added.
  • Performance ✅ — insta regions is a single GET /regions; no loops, N+1, or hot-path work introduced.

Verdict

approved (informational — human approval via the separate approve flow). No Critical findings; the items above are all non-blocking.

@Fermionic-Lyu Fermionic-Lyu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Approved. (Relaying John-bot's approved verdict — approved with the maintainer account, since John-bot can't approve its own PR.)

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/commands/services.ts">

<violation number="1" location="src/commands/services.ts:51">
P3: An explicitly supplied empty region is not rejected for storage: `--region ""` makes `opts.region` falsy, so the guard is skipped and the request proceeds without a region. Checking for option presence instead of truthiness keeps the documented storage guard fail-fast.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/commands/services.ts Outdated
// Pure: build the POST body for `services add`, enforcing client-side guards (mirrors the platform).
export function buildAddServiceBody(type: string, name: string, opts: { branch?: string; public?: boolean; region?: string }): Record<string, unknown> {
if (opts.public && type !== 'storage') throw new Error('--public is only valid for storage services')
if (opts.region && type === 'storage') throw new Error('--region is not valid for storage services')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: An explicitly supplied empty region is not rejected for storage: --region "" makes opts.region falsy, so the guard is skipped and the request proceeds without a region. Checking for option presence instead of truthiness keeps the documented storage guard fail-fast.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/commands/services.ts, line 51:

<comment>An explicitly supplied empty region is not rejected for storage: `--region ""` makes `opts.region` falsy, so the guard is skipped and the request proceeds without a region. Checking for option presence instead of truthiness keeps the documented storage guard fail-fast.</comment>

<file context>
@@ -45,17 +45,24 @@ export function resolveComputeServiceId(services: Array<{ id: string; type: stri
+// Pure: build the POST body for `services add`, enforcing client-side guards (mirrors the platform).
+export function buildAddServiceBody(type: string, name: string, opts: { branch?: string; public?: boolean; region?: string }): Record<string, unknown> {
   if (opts.public && type !== 'storage') throw new Error('--public is only valid for storage services')
+  if (opts.region && type === 'storage') throw new Error('--region is not valid for storage services')
+  return { type, name, ...(opts.branch ? { branch: opts.branch } : {}), ...(opts.region ? { region: opts.region } : {}), public: !!opts.public }
+}
</file context>
Suggested change
if (opts.region && type === 'storage') throw new Error('--region is not valid for storage services')
if (opts.region !== undefined && type === 'storage') throw new Error('--region is not valid for storage services')

…--port)

Both PRs extended 'services add': #61 added --region + client-side region
guard; #63 (on main) added --image/--port + servicesAddRequestBody.
Resolved by folding region into servicesAddRequestBody and the servicesAdd
validation/output; dropped the now-redundant buildAddServiceBody + its test,
moved region coverage into test/services.test.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jwfing
jwfing merged commit 98fe669 into main Jul 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants