Skip to content

Devel#33

Merged
jwfing merged 4 commits into
mainfrom
devel
Jul 14, 2026
Merged

Devel#33
jwfing merged 4 commits into
mainfrom
devel

Conversation

@jwfing

@jwfing jwfing commented Jul 14, 2026

Copy link
Copy Markdown
Member

Summary by cubic

Add compute lifecycle controls and show "Next:" action hints after key operations to guide follow-ups. Sends Insta-Hints to the API to receive suggestions and updates compute command help.

  • New Features

    • Compute lifecycle: insta compute start|stop|suspend|status [service]. Resolves the target compute by name or the sole compute service; prints desired vs live state; supports --json; mutating calls honor approvals.
    • Next actions: prints "Next:" suggestions after project create, services add, deploy, and branch create. Maps ops like service.add, deploy, secrets.set, metrics, logs, and approvals.approve; unknown ops fall back to reason-only. Enabled by adding the Insta-Hints: 1 header.
  • Bug Fixes

    • Metrics/logs hints render with the compute target so the suggested commands are runnable.

Written for commit 80da15e. Summary will update on new commits.

Review in cubic

jwfing added 4 commits July 13, 2026 17:25
Adds resolveComputeServiceId (services.ts) — resolve by name, or the
sole compute service in the project when name is omitted — and four
lifecycle subcommands wired into the existing `compute` group:
start/stop/suspend (mutating, via rawRequest + handleApproval, gated
for future-proofing) and status (plain read via request).
feat(nextactions): send Insta-Hints and render Next: affordance

@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.

2 issues found across 10 files

Heads up: you’re close to your included review allowance. Set a flex budget so reviews don’t pause.

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/util.ts">

<violation number="1" location="src/util.ts:40">
P3: `NextAction.args` is typed as `Record<string, unknown>`, so property accesses like `a.branch` and `a.type` in the `OP_COMMAND` handlers are completely unchecked. A call-site typo (e.g., `{brnach: 'main'}` instead of `{branch: 'main'}`) would silently produce a wrong placeholder command rather than a compile error. Consider using a per-op discriminated union or at least documenting the expected shape per op so callers get editor feedback on valid property names.</violation>
</file>

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

<violation number="1" location="src/commands/compute.ts:72">
P3: `insta compute status` without `[service]` prints the opaque service ID even when the sole compute service has a name. Derive the name from the already-fetched `services` list so status output stays readable and consistent with lifecycle commands.</violation>
</file>

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

Re-trigger cubic

Comment thread src/util.ts
return false
}

export type NextAction = { op: string; reason: string; args?: Record<string, unknown>; gated?: boolean }

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: NextAction.args is typed as Record<string, unknown>, so property accesses like a.branch and a.type in the OP_COMMAND handlers are completely unchecked. A call-site typo (e.g., {brnach: 'main'} instead of {branch: 'main'}) would silently produce a wrong placeholder command rather than a compile error. Consider using a per-op discriminated union or at least documenting the expected shape per op so callers get editor feedback on valid property names.

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

<comment>`NextAction.args` is typed as `Record<string, unknown>`, so property accesses like `a.branch` and `a.type` in the `OP_COMMAND` handlers are completely unchecked. A call-site typo (e.g., `{brnach: 'main'}` instead of `{branch: 'main'}`) would silently produce a wrong placeholder command rather than a compile error. Consider using a per-op discriminated union or at least documenting the expected shape per op so callers get editor feedback on valid property names.</comment>

<file context>
@@ -37,6 +37,34 @@ export function handleApproval(res: { status: number; body: any }): boolean {
   return false
 }
 
+export type NextAction = { op: string; reason: string; args?: Record<string, unknown>; gated?: boolean }
+
+// Neutral op → an `insta` command string. Unknown ops fall back to reason-only (no crash).
</file context>

Comment thread src/commands/compute.ts
const id = resolveComputeServiceId(services, serviceName)
const r = await api.request('GET', `/projects/${p.projectId}/services/${id}/state`)
if (opts.json) return printJson(r)
info(`compute ${serviceName ?? id}: desired=${r.desiredState} live=${r.state}`)

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: insta compute status without [service] prints the opaque service ID even when the sole compute service has a name. Derive the name from the already-fetched services list so status output stays readable and consistent with lifecycle commands.

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

<comment>`insta compute status` without `[service]` prints the opaque service ID even when the sole compute service has a name. Derive the name from the already-fetched `services` list so status output stays readable and consistent with lifecycle commands.</comment>

<file context>
@@ -41,3 +42,32 @@ function printDomain(r: any, json?: boolean): void {
+  const id = resolveComputeServiceId(services, serviceName)
+  const r = await api.request('GET', `/projects/${p.projectId}/services/${id}/state`)
+  if (opts.json) return printJson(r)
+  info(`compute ${serviceName ?? id}: desired=${r.desiredState}  live=${r.state}`)
+}
</file context>
Suggested change
info(`compute ${serviceName ?? id}: desired=${r.desiredState} live=${r.state}`)
info(`compute ${services.find((s: { id: string; name: string }) => s.id === id)?.name ?? id}: desired=${r.desiredState} live=${r.state}`)

@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 — compute lifecycle controls + "Next:" action hints

Summary: Adds insta compute start|stop|suspend|status [service] and server-driven "Next:" hints after key operations; the diff is tight, well-scoped, and the pure logic is properly unit-tested — no blocking issues found.

Requirements context

No matching spec/plan found — this repo has no docs/superpowers/ (nor docs/specs/) directory, and no DEVELOPMENT.md/CONTRIBUTING.md. Assessed against the PR description (cubic summary) and the existing code conventions in src/ alone.


Critical

(none)

Suggestion

Functionality — state-field casing diverges between the two read paths. src/commands/compute.ts:58 reads res.body.service?.desired_state (snake) + res.body.state from POST /services/{id}/{verb}, while src/commands/compute.ts:72 reads r.desiredState (camel) + r.state from GET /services/{id}/state. These are two different endpoints so different shapes are plausible — and the nested service object already uses snake_case elsewhere (s.machine_count, services.ts:62), which makes desired_state reasonable. But nothing (no test, no spec) pins either shape, so a single wrong field name would silently print desired=undefined with no failure. Recommend confirming both field names against the platform API contract, or adding a light smoke assertion.

Security — secrets.set hint interpolates the value directly. src/util.ts:46 renders insta secrets set ${a.name} ${a.value}. If the control-plane ever populates args.value with a real secret, it would be echoed to stdout (and into shell history / CI logs when copied). Low blast radius since the value is server-controlled, but secrets should never be printed — suggest always emitting a <value> placeholder regardless of args.

Software engineering — status vs. lifecycle label inconsistency. computeStatus prints serviceName ?? id (compute.ts:72), so when the name is omitted it shows the raw service id, whereas lifecycle prints the resolved res.body.service?.name ?? id (compute.ts:58). Minor UX inconsistency; consider surfacing the resolved name in status too.

Information

  • Testing (positive). Pure helpers are well covered — resolveComputeServiceId has 5 cases including the ambiguity/none/not-found branches (test/services.test.ts:46-65) and nextActionsLines has 5 including unknown-op fallback and empty input (test/util.test.ts:25-56). Leaving the I/O command wrappers (lifecycle/computeStatus) untested matches the existing repo convention (servicesAdd, deploy are untested too), so this is consistent, not a gap.
  • Functionality. Insta-Hints: 1 (src/api.ts:59) is now sent on every request, including the unauthenticated /auth/refresh. Benign — renderNextActions(undefined) no-ops when a response carries no nextActions, so existing output is unchanged — just noting the header is global rather than per-command.
  • Performance. No concerns. Each lifecycle/status call does one extra GET /services to resolve the id, matching the existing pattern in servicesRemove/scale/upgrade. No N+1, no unbounded loops, no blocking work on a hot path.
  • Security. Aside from the secrets.set note above: no auth/authorization checks were changed, no new dependencies, and mutating calls still route through rawRequest + handleApproval, so approval gating is preserved (compute.ts:56).

Verdict

approved (informational — zero Critical findings; the three Suggestions are non-blocking). Posted as a COMMENT; explicit GitHub approval remains a separate human action.

@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.)

@jwfing jwfing merged commit 4e2b6cd into main Jul 14, 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