Commit Graph
16 Commits
Author SHA1 Message Date
Neil 51ace4d05f feat(billing): one-time Orca Cloud trial (N11) and its desktop surfaces (T1)
Billing Worker:
- trials + trial_claims (migration 0005): 2 sandbox hours per new team, no card, no Stripe.
- POST /v1/billing/trial grants it (idempotent, any member); grantTrial/trialOffer exported for
  the setup session. offers.trial on GET entitlements only when this caller could still claim it.
- Abuse limits: once per team, Orca user, normalized verified email, GitHub user (token claim)
  and GitHub owner (POST /v1/internal/trial/github from the binding; a reused identity revokes),
  disposable-domain blocklist, 3 grants per IP per day. Keys stored as SHA-256 hashes.
- Entitlement trial {includedSeconds, usedSeconds, remainingSeconds, exhausted}; metered from
  usage_events, concurrency 1, never overage; trial_used_up (suspendRunning) / trial_unavailable.
- Any subscription ends the trial; unused trial hours lapse.
- e2e: trial path (grant, no Stripe customer, concurrency, metering to used up, once per user,
  plan ends it) with cleanup of the run's abuse keys.

Desktop: trial_used_up / trial_unavailable classify as 'plan'; copy in billing, phone and CLI;
"Trial" badge, TrialPlanSummary in Plan & billing and the plans page strip, account menu row
"Trial · {{count}} sandbox hours left" (Choose plan for owners/admins); billingClaimTrial IPC
and claimOrcaCloudTrial() for the composer.
2026-11-10 06:20:22 -08:00
Neil dd34314dc0 feat(billing): bill overage by the minute, put sandboxes to sleep at the cap (U22, U24)
- Overage stays $1.00 per sandbox hour (ORCA_CLOUD_OVERAGE_CENTS_PER_HOUR) and is now billed by
  the minute: a per-minute metered TEST price (unit_amount_decimal = rate / 60 to 12 decimals,
  transform_quantity divide_by 60, round up), created the same way by stripe-test-setup.ts.
  capSeconds rounds the cap down to whole minutes and spentCents mirrors the invoice, so the
  cap math matches Stripe. The meter still counts seconds.
- Opting in re-prices an overage item still on an older price (e.g. $0.75 / h) instead of adding
  a second item on the same meter, and removes any extra stale one.
- Alerts at 75%, 90% and 100% of included hours (warnAtPercent).
- New top-level entitlement.suspendRunning: payment grace expired, or at the limit (out of hours
  with overage off, or at the spend cap). The start check and usage answers carry it, so the
  control plane puts running sandboxes to sleep (snapshot kept, never deleted). Payment fields and
  /v1/internal/suspensions stay payment-only, so no data-retention clock starts at a cap.
- Copy (desktop billing panel, plan card, build sheet, phone, CLI): "billed by the minute" after
  the rate; at the limit "Running sandboxes go to sleep and new ones can't start. Nothing is
  deleted, and your files are safe."
2026-11-10 04:33:07 -08:00
Neil 52e8dd431c fix(cli): design-squad copy nits (404 wording, cloud env build help) 2026-11-10 03:34:06 -08:00
Neil f5d327f502 fix(cli): Couldn't wake state for a failed wake (glossary update) 2026-11-10 02:37:52 -08:00
Neil 90a60ed16a fix(cli): exhaustive error switches, typed test template 2026-11-10 02:37:19 -08:00
Neil 7316a18fc1 feat(cli): orca cloud glossary copy, workspace delete, routine list/run (DS-25, DS-36 CLI)
- workspace destroy -> delete (destroy kept as a hidden alias)
- glossary states (Starting/Running/Asleep/Waking/Couldn't start/Archived/Deleting); list columns
  ID NAME STATE REPO BRANCH LAST ACTIVE; raw statuses and codes only under --json
- error copy: resume_failed wake, 409 busy, out of sandbox hours vs spend cap, team owner/admin,
  Try again in N seconds; no VM/organization wording; whoami prints team:
- --size dropped from workspace create and worktree create --on cloud; show prints
  Sandbox size from ORCA_CLOUD_SANDBOX_SPEC
- orca cloud routine list | run <id-or-name> [--wait]
- control plane: public workspace view adds repoBranch and lastActivityAt
2026-11-10 02:26:14 -08:00
Neil ff12245a82 feat(cloud): one sandbox size (8 vCPU · 16 GB, 1×) — billing counts every size 1×, plans/usage/run-on/env/CLI/phone copy from ORCA_CLOUD_SANDBOX_SPEC, size pickers removed 2026-11-10 00:54:28 -08:00
Neil a8179682e6 feat(cli): always show cloud wake, sleep and --on cloud create progress
W10 wake-visibility P1s. stderr '- …' lines (NDJSON phase events with
--progress json; --json defaults to none; stdout keeps only the result):
- wake: 'Waking <ws>...', one 'Still waking (Ns)…' line at 10 s,
  '<name> is awake (took Ns).', or, when the API answers still waking
  after its wait, '<name> is still waking. Check with: …' (exit 0, status
  waking kept in the result)
- sleep: 'Putting <ws> to sleep...' / '<name> is asleep (took Ns).'
- worktree create --on cloud: 'Still starting (Ns)…' at 10 s and
  'Workspace <id> is running (took Ns).'
Lifecycle handler moved to cloud-lifecycle.ts; shared helper cloud-progress.ts.
2026-11-09 23:14:14 -08:00
Neil 84d68eb0c8 test(cli): no casts in the --on cloud dispatch tests 2026-11-09 21:11:02 -08:00
Neil 70e9b2a6c4 feat(cli): orca worktree create --on cloud[:<project>] [--env] creates an Orca Cloud workspace (private build); clear plan/at-cap/payment/sign-in errors; API accepts a team environment 2026-11-09 21:08:55 -08:00
Neil 04bcdbe8f4 fix(cloud-integration): lint green after w5-cli (#112)
- --on cloud reads origin through @orca/process-host runProcessSync
- isCloudAgent guard replaces agent casts; credentials and API error bodies read through jsonFields
- client's generic response boundary carries a SAFETY note; test fixtures typed (vi.fn<typeof fetch>)
2026-11-09 15:52:08 -08:00
Neil 0af3774c35 fix(cli): name the vmCliEnabled toggle when a workspace token is rejected
Turning in-workspace CLI access off revokes every workspace token, so the
in-VM CLI sees 401, not 403 vm_cli_disabled. Say so and point at the
setting first (verified on a real VM).
2026-11-09 15:28:40 -08:00
Neil 31d9699af5 fix(sandbox-control): let VMs reach the control plane their workspace token names
Workspace tokens tell the in-VM orca cloud CLI to call publicOrigin(env), but
that host was only reachable when EGRESS_EXTRA_HOSTS listed it (previews did,
the dev Worker did not), so every in-VM call failed with 'fetch failed'.
extraEgressHostsFor(env) now always adds the public API host. The CLI's
cloud_unreachable hint inside a VM names the egress allowlist.
2026-11-09 15:20:42 -08:00
Neil 0a319f53ef fix(cli): orca cloud messages <workspace> [<id>] instead of message status (positional ambiguity) 2026-11-09 14:47:14 -08:00
Neil f00deaf079 feat(cli): cloud target adapter for worktree create --on (hooked up on the --on branch) 2026-11-09 14:47:14 -08:00
Neil 6fa1115887 feat(cli): orca cloud commands (whoami, login, workspace lifecycle, message, sessions, projects)
Private build. Talks HTTPS to the Orca Cloud public API, never to the Orca
runtime, so it works inside a VM with no desktop app. Credentials:
ORCA_CLOUD_TOKEN (+ ORCA_CLOUD_API_URL) -> ~/.config/orca-cloud/credentials.json
(written at boot in VMs when vmCliEnabled, or by orca cloud login, 0600).
--json prints { ok, schemaVersion: 1, result }; API failures map to stable
cloud_* codes with next steps (vm_cli_disabled, own_workspace, scopes, 401).
2026-11-09 14:47:14 -08:00