Commit Graph
623 Commits
Author SHA1 Message Date
Neil adc417cae5 feat(cloud): acceptance read-asleep access (operator member removal, private prune) and phone protocol path, by W9 2026-11-10 03:54:00 -08:00
Neil 3f2b8ead4e Merge pull request #228 from nwparker/cloud/w9-eval
feat(cloud): acceptance — run actions + ports (m4air UI), read-while-asleep (live E2EE), gap rows
2026-11-10 03:51:42 -08:00
Neil f88c09c7fa Merge pull request #211 from nwparker/cloud/w2-squad-archive
fix(cloud): archive from the team list really stops the sandbox (DS-01 P0, DS-09)
2026-11-10 03:47:46 -08:00
Neil c14e875adc Merge pull request #225 from nwparker/fix/ds-34-44-billing-polish
fix(billing): DS-34 billing polish + DS-44 nits
2026-11-10 03:42:47 -08:00
Neil b199587d7e feat(cloud): desktop run actions + ports checks (W9D_ONLY=run-actions)
- local.run-actions: autoRunAfterSetup after a good setup and not after a failed one, Run button,
  one trust prompt, Stop -> Stopped, menu Restart replaces the tab, Cmd+Opt+Enter start/restart
- run.nonconcurrent: echo-loop started in B stops A's
- run.ports: ORCA_PORT/ORCA_PORT_COUNT/CONDUCTOR_PORT per terminal, distinct blocks, stable across
  an app restart, served locally; cloud half: the action in the VM reachable here via auto-forward
- run.cloud-resume: action back after Sleep/wake and after Restart sandbox
2026-11-10 03:42:31 -08:00
Neil 29cdd2cb99 feat(cloud): acceptance read-while-asleep (live, E2EE, no wake) plus access/phone rows (owner-reported) 2026-11-10 03:42:31 -08:00
Neil 322ba5eabb feat(cloud): acceptance catalog rows for run actions and per-workspace ports (gap 4) 2026-11-10 03:42:31 -08:00
Neil c5199433a9 Merge pull request #214 from nwparker/cloud/w6-secret-request
feat(cloud): agent secret requests: orcad RPC, orca secret request, orca-env (contract §3)
2026-11-10 03:42:02 -08:00
Neil 6fa10c836b Merge remote-tracking branch 'private/cloud/integration' into cloud/w2-squad-archive
# Conflicts:
#	src/renderer/src/components/orca-cloud/cloud-workspace-actions.ts
2026-11-10 03:40:01 -08:00
Neil 01d2482a3a fix(billing): one billing store, skeleton, plurals, plans focus and billing nits (DS-34, DS-44)
DS-34:
- One billing store (billing-summary-store) replaces the summary, the hook's local state and the
  Run-on picker cache; it keeps the last good result through a failed read and still drops answers
  from before a team or account switch (DS-17).
- Skeleton while Plan & billing loads.
- '{{count}} sandbox hours left' and '{{count}} sandbox hours over the included amount this month'
  as i18n plurals; no bare 'hours'; the unreachable 100% branch is gone.
- Usage warning driven by usageWarningPercent ('Your team has used {{percent}}% of this month's
  sandbox hours.'), in Settings, the plans page and the account menu.
- capTooHigh states the maximum ('The spend cap can be at most {{max}}.'), from offers.maxSpendCapCents.
- Plans dialog focuses its heading on open, so Tab reaches the interval toggle before the cards.
- Payment notice uses InlineError; the build card's overage buttons land on the overage section.
- Account menu names the team once and adds the hours-left line.

DS-44: warning tone at 90%+, '$' as an input prefix, neutral paid check, 24px dialog close hit
area, no <p> inside the CheckoutPanel <dl>.
2026-11-10 03:39:21 -08:00
Neil e604bd4f39 Merge pull request #226 from nwparker/cloud/u22-cpu-fairuse
feat(sandbox-control): internal per-session CPU + operator fair-use report (U22)
2026-11-10 03:38:55 -08:00
Neil e02edd279f Merge remote-tracking branch 'private/cloud/integration' into cloud/w6-secret-request
# Conflicts:
#	cloud/apps/sandbox-control/image/vm-scripts.generated.ts
2026-11-10 03:34:32 -08:00
Neil d76cb62c57 fix(sandbox-control): keep preview URLs on for the dev Worker (preview aliases 404ed) (#224) 2026-11-10 03:34:07 -08:00
Neil f8e362259a fix(cloud): harden agent secret requests (review of #214)
- Agent and worktree come from the terminal orcad verifies from launch
  evidence (verifiedCallerTerminalHandle, shared with turn-sender); the
  terminalHandle param is gone and a worktree hint is kept only when the
  host knows it.
- secrets.* are accepted, and their events sent, only on cloud orcad
  (ORCA_IS_CLOUD=1 + ORCA_SANDBOX_ID); already-set never reads orcad's env.
- touchRequest emits secrets.requestUpdated; natural expiry emits
  secrets.requestSettled {status: expired}.
- orca-env skips the control plane's reserved names and prefixes, with a
  test that reads them from secrets.ts.
- reason drops bidi controls and turns C0/C1 controls into spaces.
2026-11-10 03:34:04 -08:00
Neil 43aa595ee7 feat(sandbox-control): internal per-session CPU tracking and fair-use report (U22)
Customers keep flat sandbox hours. Each stopped session's activeCpuDurationMs
(from Vercel's stop response or GET session) is stored in a new session_cpu
table (migration 0042), idempotent per session. Recording is best-effort and
never blocks suspend, stop or usage reporting; a 5-minute cron sweep retries
recent sessions still missing CPU. Operator-only GET /v1/internal/fair-use
reports per-account 30-day utilisation sum(active_cpu_ms)/sum(wall_ms*vcpus)
with fairUseFlag above 60%. Nothing reaches usage_outbox, billing or clients.
2026-11-10 03:34:00 -08:00
Neil 0f8ab90314 Merge pull request #222 from nwparker/cloud/w6-agent-sources
W6: agent Source per person (/v1/agent-sources) + per-agent credential names
2026-11-10 03:31:03 -08:00
Neil bc7e012e6e Merge pull request #219 from nwparker/cloud/agents-a6
feat(cloud): this computer's Agent API Keys never reach an Orca Cloud VM; save each as a personal Cloud secret (A6)
2026-11-10 03:27:21 -08:00
Neil 9b56250956 feat(cloud): agent Source per person (GET/PUT /v1/agent-sources, offer answers, owner block) — 'Your sign-in' keeps that agent's credentials out of the sandbox session live; shared credential-names module + Worker mirror (migration 0041) 2026-11-10 03:21:22 -08:00
Neil 8102e770dc fix(cloud): the registry edit can no longer label a workspace archived; tests for asleep archive (no wake) and creating/suspending refusals 2026-11-10 03:18:45 -08:00
Neil 86ccf4eb29 fix(cloud): read snapshot lists chats from orcad's session store (the local socket can't stream subscribeStatus)
Live on dev the first capture sealed zero sessions: agentSession.subscribeStatus needs a streaming
transport and the unix socket refuses it, and worktree.ps lists only agents live right now. The
collector now reads orcad's own session records (agent-session-journal.db, read-only): provider,
name and last turn, open tabs first; live worktree.ps rows override status; history still comes
from agentSession.history, with the stored last turn as fallback.
2026-11-10 03:10:34 -08:00
Neil c392a487a1 Merge remote-tracking branch 'private/cloud/integration' into cloud/w2-squad-archive
# Conflicts:
#	cloud/apps/sandbox-control/src/index.ts
#	src/renderer/src/components/cloud-workspaces/CloudWorkspacesHome.tsx
#	src/renderer/src/i18n/locales/en.json
2026-11-10 03:09:00 -08:00
Neil 7dbd33a1ad Merge remote-tracking branch 'private/cloud/integration' into cloud/w6-secret-request
# Conflicts:
#	cloud/apps/sandbox-control/image/provision-golden.sh
#	cloud/apps/sandbox-control/image/vm-scripts.generated.ts
2026-11-10 03:05:52 -08:00
Neil e3748c9725 Merge remote-tracking branch 'private/cloud/integration' into cloud/w2-squad-archive
# Conflicts:
#	src/renderer/src/i18n/locales/en.json
2026-11-10 02:57:28 -08:00
Neil 81577b1ac7 feat(cloud): agent secret requests (secrets.request RPC, orca secret request, orca-env)
orcad keeps agent-initiated secret requests in memory with the contract's
limits (3 pending, 10/hour, 15 min TTL, touch capped at 60 min, dedupe per
name), derives the agent from the calling terminal, and announces
secrets.requested on runtime.clientEvents (replayed on attach; phones get
status only). The CLI waits on it and prints the D4 reload hint; the VM
ships orca-env and makes zsh read the session env hook.
2026-11-10 02:55:15 -08:00
Neil dbe94611c5 fix(cloud): team-list archive runs the lifecycle first (409 while starting or mid-transition, never a label on a running sandbox); confirm before archiving a teammate's running workspace 2026-11-10 02:48:51 -08:00
Neil 49ce098274 Merge remote-tracking branch 'private/cloud/integration' into cloud/sleeping-read-snapshot
# Conflicts:
#	src/renderer/src/components/cloud-workspaces/CloudWorkspacesHome.fixture.tsx
#	src/renderer/src/i18n/locales/en.json
2026-11-10 02:39:02 -08:00
Neil dd4baa98ed fix(cloud): security review of A6: offer and save only keys the proxy swaps; no desktop keys over SSH into a cloud workspace; orcad on a cloud VM drops carried keys
- 'Save as personal Cloud secret' is offered, and accepted by main, only for names the egress proxy
  swaps (a shared list the control-plane test holds equal to the proxy's); anything else would sit
  on the VM in full, so main answers not_swappable.
- SSH launches into an Orca Cloud workspace (orca-* aliases or an 'orca ssh-proxy' ProxyCommand
  surfaced through ~/.ssh/config Includes) get no desktop keys.
- Defense in depth on the VM: orcad with ORCA_IS_CLOUD=1 drops a carried keyEnv.
2026-11-10 02:37:29 -08:00
Neil 519f6f6c9b fix(billing): spell out price formats per DS-18
Line items: '{{seats}} x {{price}} per seat, billed yearly' / 'per seat per month'
(plural keys); totals '{{total}} per year' / 'per month'; Worker plan labels
'$50 per seat per month' and '$480 per seat, billed yearly'. Drops /mo, /yr,
/year and /seat/month strings.
2026-11-10 02:27:14 -08:00
Neil 6fb8497a1a Merge remote-tracking branch 'private/cloud/integration' into cloud/sleeping-read-snapshot
# Conflicts:
#	cloud/apps/sandbox-control/image/vm-scripts.generated.ts
#	mobile/src/cloud/cloud-control-plane-client.ts
#	mobile/src/i18n/en-runtime-required.json
#	mobile/src/i18n/locales/en.json
#	src/renderer/src/components/cloud-workspaces/CloudWorkspaceRow.tsx
#	src/renderer/src/components/cloud-workspaces/CloudWorkspacesHome.tsx
2026-11-10 02:21:17 -08:00
Neil 264f30f8a3 fix(cloud): archive from the team list really stops the sandbox (Sleep → archive with Undo, or the control-plane archive); archive never runs after a failed sleep (DS-01, DS-09) 2026-11-10 02:19:03 -08:00
Neil ebec244447 Merge pull request #203 from nwparker/cloud/agents-gaps2
feat(cloud): swap COPILOT_GITHUB_TOKEN and GOOGLE_API_KEY at egress; routines run all six image agents; AWS keys marked stored on workspace
2026-11-10 02:16:56 -08:00
Neil df8927b7f5 fix(cloud): security review: Copilot token limited to Copilot's GitHub endpoints; routine summaries are final messages with session secrets redacted; untrusted context capped
- COPILOT_GITHUB_TOKEN on api.github.com: GET /user and GET /copilot_internal/* only (normalized
  paths; dot or encoded segments refused); the Copilot API hosts are unchanged. It resolves like
  an env variable (personal beats team): it is one person's GitHub identity.
- Routine summaries for opencode (JSON events), cursor (JSON result) and copilot (--silent) are the
  agent's final message, and every summary has the session's secret values replaced before it can
  be posted as a comment or PR body.
- Webhook/GitHub context in a routine prompt is capped at 48 KiB (compact, then cut), so a prompt
  passed as one argv entry stays under Linux's 128 KiB limit.
- A test fails if an agent credential is neither swapped nor marked 'Stored on workspace'.
2026-11-10 02:13:11 -08:00
Neil e35ff0844a feat(cloud): COPILOT_GITHUB_TOKEN and GOOGLE_API_KEY swapped at egress; routines run all six image agents; AWS keys marked stored on workspace
- COPILOT_GITHUB_TOKEN: placeholder in the VM, swapped on api.github.com (Bearer or token form, next to
  the workspace token's own route) and on the Copilot API hosts (left open for Copilot's own session
  token). GOOGLE_API_KEY: swapped on generativelanguage.googleapis.com and aiplatform.googleapis.com
  (Vertex express). A credential may now route to several hosts.
- Routines accept claude, codex, opencode, gemini, cursor and copilot; the in-VM runner has a
  headless command for each (checked against a local stand-in model: prompts starting with '-' stay
  prompts). The editor picks the agent from a list.
- AWS_* keys (SigV4, signed in the VM) and Bedrock API keys can't be swapped: the secrets UI marks
  them 'Stored on workspace' with the reason, in the list, the .env preview, the effective view and
  the editor.
- Gemini's auth method is seeded for GOOGLE_API_KEY too (vertex-ai with GOOGLE_GENAI_USE_VERTEXAI);
  headless Gemini refuses to start without one.
2026-11-10 02:08:00 -08:00
Neil 209d658b03 Merge pull request #202 from nwparker/cloud/status-rate
feat(cloud): one overage constant ($1/h); workspaces show sandbox hours, not dollars
2026-11-10 01:57:47 -08:00
Neil d4653c15d3 feat(cloud): one overage constant (ORCA_CLOUD_OVERAGE_CENTS_PER_HOUR, $1) for billing and the control plane; workspaces show sandbox hours, not per-workspace dollars (desktop list, phone status) 2026-11-10 01:52:05 -08:00
Neil 8550787232 docs(cloud): region/size AFTER benchmarks — wake p95 5.85 s in pdx1 2026-11-10 01:45:21 -08:00
Neil 2920f1c173 feat(cloud): acceptance image.agents, agent.keys-swap (no model), sub.size at 8/16 (U18); more-agents owner-reported 2026-11-10 01:45:21 -08:00
Neil 1095b509fc fix(cloud): Copilot CLI sign-in works in cloud workspaces (GitHub placeholder no longer overrides /login)
Copilot prefers GH_TOKEN/GITHUB_TOKEN over a stored /login. In Orca Cloud those hold the workspace
GitHub App placeholder, so every Copilot start said 'Resource not accessible by integration' and a
user who signed in could never use it. A wrapper drops the two placeholders for Copilot only, unless
BYOK is configured (no GitHub sign-in needed; gh in Copilot's shell keeps working).
2026-11-10 01:33:29 -08:00
Neil dc0bf820ea feat(billing): overage $1.00 per sandbox hour (interim); plans.ts is the single source (setup script, e2e and spend-cap math read it); new Stripe TEST price 2026-11-10 01:26:39 -08:00
Neil f1aa875edc docs(cloud): checkpoints verified independently by W9 (host path + real git tests) 2026-11-10 01:21:08 -08:00
Neil c9c0a0c65e feat(cloud): acceptance records owner-reported results (import-external); checkpoints capped until independent run 2026-11-10 01:20:19 -08:00
Neil f6b6c5141c feat(cloud): acceptance create-bench (host CPU/size/region), wake-split region + CPU per wake, bench-summary 2026-11-10 01:20:19 -08:00
Neil f9cc0f0c89 docs(cloud): agent caps lifted only by the user's own e2e session (no gateway runs) 2026-11-10 01:20:19 -08:00
Neil 63b6999dee feat(cloud): pdx1 default region, iad1 fallback, golden per region; Standard = 8 vCPU / 16 GB (U17, U18) (#194)
* feat(cloud): pdx1 default region with iad1 fallback and one golden per region; Standard is 8 vCPU / 16 GB (U17, U18)

- golden_images and environment_builds record their region (0040, backfilled iad1); rotation,
  git-source builds, smoke and activation run per region; lifecycle picks the region's golden.
- New creates default to pdx1; a create with no pinned region falls back to iad1 automatically on a
  capacity/provider error (VERCEL_FALLBACK_REGIONS). Until pdx1 has an image, creates use iad1.
- Environment builds boot and smoke in their own region; workspaces from a build boot there.
- One size: Standard = 8 vCPU / 16 GB (ORCA_CLOUD_SANDBOX_SPEC). Legacy 'large' requests map to
  standard; 0040 rewrites existing large rows.

* merge cloud/integration (ORCA_CLOUD_SANDBOX_SPEC landed in #196)
2026-11-10 01:07:56 -08:00
Neil b22512a759 Merge pull request #196 from nwparker/cloud/standard-8vcpu-copy
feat(cloud): one sandbox size (8 vCPU · 16 GB, 1×): billing and copy
2026-11-10 01:00:13 -08:00
Neil c997f9cf3c fix(cloud): orcad and its terminals trust the egress proxy's CA (Gemini CLI hung in every cloud terminal)
Hosts with credential rules (model APIs, api.github.com) are answered by Vercel's egress proxy with a
certificate from its CA. Vercel's command env trusts it (NODE_USE_SYSTEM_CA, NODE_EXTRA_CA_CERTS,
SSL_CERT_FILE) but orcad starts under env -i, so Node clients in terminals used Node's bundled roots:
Gemini CLI retried forever ('This is taking a bit longer') while the same call from a command
returned at once. Found on the live proof of the new agents; NODE_USE_SYSTEM_CA=1 in the terminal
fixed it there (1 s to the provider's answer).
2026-11-10 00:57:32 -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 0ca83ef860 feat(sandbox-control): dev control plane also trusts staging auth sandbox tokens
Staging sign-in now works end to end in dev without a dev operator key on the user's machine.
Same account ids as billing dev (which trusts staging already); never honored when SANDBOX_ENV=prod;
a staging key cannot pass as the prod issuer.
2026-11-10 00:46:50 -08:00
Neil 64fbff83f1 Merge pull request #190 from nwparker/cloud/agents-in-image
feat(cloud): OpenCode, Gemini CLI, Cursor agent and Copilot CLI in the image; their keys swapped at egress
2026-11-10 00:33:06 -08:00
Neil 4286eb9cfc fix(cloud): no swappable key reaches the VM unrouted; Cursor's exchange reply passes only the access token
Security review: a Copilot BYOK key without a usable base URL (or with one from another scope) had
no route, so it went to the VM as itself. Every swappable name now becomes a placeholder, routed or
not, and the Copilot pair resolves like the other agent keys (shared beats personal, as a pair).
The Cursor exchange reply is parsed whatever its content type and cut down to accessToken; headers
(set-cookie) are not passed. opencode.ai is not allowlisted (anonymous share uploads).
2026-11-10 00:24:34 -08:00