Commit Graph
420 Commits
Author SHA1 Message Date
Neil 16f598ee6a Merge pull request #35 from nwparker/cloud/w2-lifecycle
feat(cloud): workspace lifecycle API (wake, restart, status, archive) + desktop service
2026-11-09 05:06:27 -08:00
Neil e180ab330f Merge pull request #39 from nwparker/cloud/w5-mcp
feat(sandbox-control): hosted MCP server with OAuth 2.1 (DCR + PKCE) over the public API
2026-11-09 05:06:07 -08:00
Neil 30d9684148 Merge remote-tracking branch 'private/cloud/integration' into cloud/w2-lifecycle
# Conflicts:
#	cloud/apps/sandbox-control/src/index.ts
#	cloud/apps/sandbox-control/src/sandbox-provider.ts
#	cloud/apps/sandbox-control/src/store.ts
#	cloud/apps/sandbox-control/src/vercel-sandbox-api.ts
#	cloud/apps/sandbox-control/test/fake-vercel.ts
#	src/main/hosted-sandbox/hosted-sandbox-driver.ts
#	src/main/hosted-sandbox/hosted-sandbox-recipe.ts
2026-11-09 05:05:53 -08:00
Neil d360b916f9 fix(mcp): grant list shows the effective end for grants minted before 0028 2026-11-09 05:05:27 -08:00
Neil 00a881f14b fix(mcp): grants are visible, revocable and bounded — tie to approving key, /v1/oauth-grants, 90-day family end, replay-safe mint, member removal, purge, per-IP token limit (migration 0028) 2026-11-09 05:04:16 -08:00
Neil 24b8b9c1a4 fix(cloud): public API wake shares the W2 single-flight wake; tests use the sandbox wake route 2026-11-09 05:03:34 -08:00
Neil 557b13b108 fix(cloud): a failed adopted wake goes back to sleeping (resume_failed) instead of staying resuming 2026-11-09 05:02:59 -08:00
Neil cb340de62e fix(cloud): adopted wakes run the full boot (secrets, policy, repo token); stale-wake threshold above live boots; trim cached archive state
# Conflicts:
#	cloud/apps/sandbox-control/src/lifecycle.ts
2026-11-09 05:02:59 -08:00
Neil 0533b5cd9f fix(cloud): review fixes for wake/restart/archive races, output budget, archived compat, OOM dedupe, scheduler handoff
# Conflicts:
#	cloud/apps/sandbox-control/src/index.ts
#	cloud/apps/sandbox-control/src/lifecycle.ts

# Conflicts:
#	cloud/apps/sandbox-control/src/index.ts
2026-11-09 05:02:55 -08:00
Neil 5c1e87e093 test(cloud): desktop client drives the new lifecycle routes against the real handler 2026-11-09 05:02:28 -08:00
Neil 6f5007648e fix(cloud): archive capture skips non-repository directories 2026-11-09 05:02:27 -08:00
Neil eea640c9e7 feat(cloud): desktop Orca Cloud workspace service (status, restart, archive, wake progress, OOM notices) and preload API 2026-11-09 05:02:26 -08:00
Neil c250505f75 feat(cloud): wake (single-flight, long-poll), restart, status metrics, archive/unarchive on the sandbox control plane
# Conflicts:
#	cloud/apps/sandbox-control/src/index.ts

# Conflicts:
#	cloud/apps/sandbox-control/src/env.ts
#	cloud/apps/sandbox-control/src/index.ts
#	cloud/apps/sandbox-control/test/fake-vercel.ts
2026-11-09 05:02:20 -08:00
Neil 1ec420ea77 feat(sandbox-control): golden image on a Vercel Managed Image (64 GB disk) with orca CLI, rg, tmux, vim, git-lfs and headless Chrome (#40)
W9 F4/F5. The build starts from vercel/sandbox/node:24 (Ubuntu) instead of the deprecated node24
runtime, so sandboxes cloned from the golden get 64 GB instead of 32 GB. The bundle's orca-cli.cjs
becomes /opt/orca/bin/orca (ORCA_USER_DATA_PATH defaults to orcad's data dir); a pinned Google Chrome
.deb provides headless Chrome and orcad gets ORCA_BROWSER_EXECUTABLE. Live smoke of the built image:
64G disk, all tools on PATH, orca status reaches orcad, chrome headless renders, create 2.3 s, orcad
2.1 s, resume 2.0 s.
2026-11-09 05:02:05 -08:00
Neil 7e80fbf9d3 Merge remote-tracking branch 'private/cloud/integration' into cloud/w6-control-plane
# Conflicts:
#	cloud/apps/sandbox-control/src/lifecycle.ts
#	cloud/apps/sandbox-control/test/fake-vercel.ts
2026-11-09 04:59:28 -08:00
Neil 0aa88e6182 fix(sandbox-control): review fixes — proxy rechecks a key's host at send time, refresh claims the row before the policy and writes are generation-ordered, bounded refresh fan-out, URL/model values without control chars, exact Codex host match 2026-11-09 04:56:41 -08:00
Neil a13e17cd46 feat(mcp): read_session tool (rendered agent screen) 2026-11-09 04:53:59 -08:00
Neil a4ff3f5dcb docs(api): MCP connection guide and /v1/oauth-approvals in OpenAPI 2026-11-09 04:53:58 -08:00
Neil 56688adfe1 fix(mcp): consent checkboxes post as grant so they never shadow the original scope 2026-11-09 04:53:57 -08:00
Neil 36ef481da6 feat(sandbox-control): hosted MCP server (Streamable HTTP) over the public API, with OAuth 2.1 (DCR, PKCE S256, refresh rotation, RFC 8707/9728/8414/7009) and desktop approval codes 2026-11-09 04:53:56 -08:00
Neil d0565bb871 fix(sandbox-control): a base URL only routes a model key from the same secret scope (no org-key exfil via a member's personal base URL) 2026-11-09 04:52:04 -08:00
Neil 1b322192a2 fix(sandbox-control): review fixes — user text as --flag=value, claim-token message settle (no blind re-send), revoke workspace tokens on toggle-off and provider stops, rate limit + audit first message 2026-11-09 04:51:14 -08:00
Neil b697905497 feat(sandbox-control): revoke a departed member's API keys (operator route for auth) 2026-11-09 04:51:14 -08:00
Neil 05661537cf feat(sandbox-control): session screen endpoint; seed Claude Code's bypass-mode acknowledgement so API prompts are not swallowed 2026-11-09 04:51:13 -08:00
Neil 664badba77 feat(sandbox-control): public /v1 API — org API keys (hashed, scoped), audit log, rate limits, projects, workspaces lifecycle, agent messages, sessions, in-VM workspace tokens, OpenAPI + docs 2026-11-09 04:51:12 -08:00
Neil 9aeb73d20d wip(cloud): public API foundation (keys, audit, workspaces, messages, openapi) 2026-11-09 04:51:10 -08:00
Neil 4851f6c4e2 feat(cloud): agents just work in Orca Cloud — provider presets, host-scoped model-key egress swap, live secret refresh, managed env, redaction
Control plane (cloud/apps/sandbox-control):
- Provider presets as secrets: AI_GATEWAY_API_KEY (Vercel AI Gateway) derives Claude Code + Codex env;
  custom ANTHROPIC_BASE_URL/OPENAI_BASE_URL (https, public host only) + *_MODEL. Provider hosts are
  allowlisted per workspace from its agent connection (migration 0026 egress_allow_hosts, additive).
- Egress placeholder swap is host-scoped per credential (SECRET@host) incl. ai-gateway.vercel.sh and
  custom hosts; staged rollout SECRETS_EGRESS_PLACEHOLDERS=accounts:<ids> (or on/off).
- GET /v1/secrets/effective, POST /v1/secrets/:scope/batch, POST /v1/sandboxes/:id/env/refresh; every
  secret write refreshes running sessions of that owner (no restart, no rebuild).
- VM: orca-sandbox-env writes a tmpfs-only session env file re-read by every new shell
  (/etc/profile.d hook); Codex gets a managed provider block when OPENAI_BASE_URL is set; managed env
  ORCA_IS_CLOUD, ORCA_ROOT_PATH/WORKTREE_PATH/WORKSPACE_PATH/WORKSPACE_NAME/DEFAULT_BRANCH/PORT +
  CONDUCTOR_* aliases. image/patch-golden-image.ts re-images scripts in ~10s.
- Redaction: pairing offer read via the files API (Vercel retains command stdout), log tails strip
  injected values/token shapes, runningOrcad no longer prints the offer, no GitHub placeholder for
  non-github.com repos.
Desktop: token-pattern + injected-value redaction for logs, crash reports, daemon log, emulator probe,
relayed worker spans.

Live (Vercel, W6 worker, placeholders on): org-shared gateway key, real Claude Code 2.1.319 and Codex
0.166.0 fixed+committed code through the swap; SSE long stream 978 chunks/25s and streamed tool_use
intact; real key absent from VM disk, tmpfs and every process env; secret edit visible in a new
shell 0.6s after PUT.
2026-11-09 04:49:15 -08:00
Neil 178eaf4ec8 feat(sandbox-control): warm VM pool (SANDBOX_POOL_SIZE); idempotent resume of a running sandbox; github_not_connected before provisioning (#36)
- pool.ts: N standard VMs booted from the current golden with egress denied; create claims one atomically
  (DELETE..RETURNING), applies the caller policy + full lease in parallel, bills from the claim; cron and
  each claim refill; recycled at 20 min, on golden change, pool off or kill switch; fallback to a fresh VM.
- F1: orca-sandbox-start leaked the start-lock fd into orcad, so a second start (resume of a running
  sandbox, retried create) waited 60 s and 502'd. Children now close fd 9; the Worker also reads the
  serving orcad's ready line without the lock (fixes VMs on older images).
- F2: a github.com repo with no App token and no anonymous access fails 409 github_not_connected before
  any VM work.
2026-11-09 04:45:39 -08:00
Neil e232ea8580 fix(sandbox-control): allow github.com by default so public repos clone without a GitHub App install (#34) 2026-11-09 04:31:59 -08:00
Neil 6d3b2260f0 Merge remote-tracking branch 'private/nwparker/vercel-driver' into cloud/core-sync 2026-11-09 04:24:40 -08:00
Neil 148567dbd3 perf(cloud): parallel boot prep, policy at create, clone alongside orcad, warmed V8 compile cache; Server-Timing phases (#31)
* feat(sandbox-control): dev-only shareable GitHub connect link

* perf(cloud): parallel boot prep, policy at create, clone alongside orcad, warmed V8 compile cache; phase timings (Server-Timing)
2026-11-09 04:20:09 -08:00
Neil 04a3fd27b4 feat(sandbox-control): dev-only shareable GitHub connect link (#30) 2026-11-09 04:09:43 -08:00
Neil ba7db6d219 fix(sandbox-control): read the orgRole claim that Orca Cloud auth mints (#29)
Auth mints the live org role as orgRole on sandbox tokens (same claim as billing
tokens, stablyai/orca-cloud#695); the verifier read org_role, so admins would
never have been recognized.
2026-11-09 04:07:04 -08:00
Neil fbeeaf44c2 Merge remote-tracking branch 'private/nwparker/vercel-driver' into cloud/integration
# Conflicts:
#	cloud/apps/billing/src/entitlements.ts
#	cloud/apps/billing/src/index.ts
#	cloud/apps/billing/src/plans.ts
#	cloud/apps/billing/src/seats.ts
#	cloud/apps/billing/src/store.ts
#	cloud/apps/billing/src/stripe.ts
#	cloud/apps/billing/src/usage.ts
#	cloud/apps/billing/src/webhook.ts
#	cloud/apps/billing/test/billing-flow.test.ts
#	cloud/apps/billing/test/seats-grace.test.ts
#	cloud/docs/accounts-billing-design.md
#	config/scripts/ci/unit-selection/check-test-file-runners.mjs
#	src/main/billing/billing-client.ts
#	src/renderer/src/components/billing/plan-billing-fixtures.ts
#	src/renderer/src/components/billing/plans/TeamPlanCard.tsx
#	src/renderer/src/components/billing/team/TeamMembersSection.tsx
#	src/renderer/src/components/billing/team/TeamMembersView.fixture.tsx
#	src/renderer/src/components/billing/team/TeamMembersView.tsx
#	src/renderer/src/i18n/locales/en.json
#	src/renderer/src/main.tsx
#	src/shared/orca-billing.ts
2026-11-09 04:06:58 -08:00
Neil dc71ad438b Merge remote-tracking branch 'private/nwparker/accounts-billing' into cloud/integration 2026-11-09 04:06:35 -08:00
Neil 8dde71250d feat(cloud): self-rotating golden images (refresh before expiry, release builds, smoke-gated atomic swap); Orca Cloud gated on the sandbox capability (#28) 2026-11-09 03:28:58 -08:00
Neil a2b91b9d47 chore(cloud): dev golden image rebuilt with the secret-store start script (#27) 2026-11-09 03:03:47 -08:00
Neil 9922e32a68 feat(cloud): Orca Cloud in the desktop end to end (provider, lease scheduler, upsell, dogfood) (#26)
* feat(sidebar): replace footer Settings and Help icons with an account menu

* fix: keep account menu header on primitive spacing; move focus-read allowance

* fix(sidebar): address account menu review findings

* feat(billing): Cloudflare Worker for Stripe checkout, portal, webhooks, entitlements and usage (#7)

Test-mode-only foundation for paid Orca plans: hosted Checkout/Portal,
signed + idempotent Stripe webhooks that re-read subscriptions, a D1 ledger
for sandbox usage with overage-only Billing meter events, and entitlement
checks for the desktop and the sandbox control plane.

* feat(billing): Plan & billing in the Orca account settings and account menu (#9)

Shows the signed-in account's plan, sandbox hours used and left, and opens
hosted Stripe Checkout (Upgrade) or the Customer Portal (Manage billing) in
the browser. Main mints a short-lived billing token from Orca Cloud auth and
only opens checkout.stripe.com / billing.stripe.com URLs. Hidden until
ORCA_BILLING_API_URL is set; the account menu item is gated on the 'billing'
cloud capability and registers through a local adapter that mirrors the
upcoming account menu API.

* feat(billing): plans and prices from config, opt-in Stripe Tax, real account menu

- Worker: BILLING_PLANS JSON overrides the plan catalog (labels, display price,
  hours, limits); entitlements return the plan list so the desktop shows no
  hardcoded prices. STRIPE_AUTOMATIC_TAX=true adds automatic_tax and tax id
  collection to Checkout (default off). Setup script takes prices from env.
- Desktop: register Plan & billing through the sidebar account menu
  (merged nwparker/sidebar-account-menu) and drop the local adapter.
- Register the billing Worker's tests with the test-runner check.

* feat(billing): Team pricing, opt-in overage, Stripe test-mode e2e, dev deploy (#18)

* feat(billing): Team-only pricing, opt-in overage with spend cap, live Stripe test-mode e2e

- Catalog: Team $50/seat/mo or $480/seat/yr, 60 Standard h/seat/month pooled
  (monthly windows on annual plans), Large 2x, 3 running/seat, 15-min idle sleep;
  Enterprise is contact-only. All numbers/labels in BILLING_PLANS defaults.
- Overage is opt-in (adds the metered item), $0.75/h, monthly spend cap (default
  $25, admin-raisable) enforced in the meter outbox; 80%/100% usage warnings.
- Checkout: plan/interval/seats with adjustable quantity; portal configuration var.
- Workers reject fetch redirect 'error': use 'manual'. Log route errors.
- scripts/stripe-test-setup.ts creates the test catalog + portal configuration;
  scripts/e2e-test-mode.ts drives Checkout (headless, test card), overage, meter,
  cap, annual, test-clock renewal, payment failure and cancel.
- Desktop: Team/Enterprise cards with interval + seats, usage warnings, overage
  toggle + cap; split into copy/offers/usage modules.

* feat(billing): dev deployment config, dev operator keys, return page

- wrangler.dev.jsonc for orca-billing-dev (workers.dev, dev D1, test-mode prices).
- BILLING_DEV_JWKS (issuer orca-billing-dev-test) accepted only when BILLING_ENV
  is not prod, for e2e runs until auth mints billing tokens.
- GET /return: static 'return to Orca' page for Checkout/Portal redirects.
- Design doc: final pricing, dev URL and resources for the control plane.

* feat(billing): team seats follow membership, payment grace + suspend signal, Team UI

Worker
- Seats = org members from Orca Cloud auth (single source of truth; pending invites
  never count; min 1): auth pushes POST /v1/internal/seats, billing pulls
  /v1/internal/billing/org-members at Checkout and in a reconcile cron, fails closed
  (503) if auth is configured but unreachable. No token claim carries a count.
- Proration: adds always_invoice, removals create_prorations (Stripe default).
- Billing admin actions require a token minted in the last 6 minutes.
- Payment failure: past_due_since (migration 0003); new starts stop at once;
  after 96 h (paymentGraceHours) reason payment_grace_expired + suspendRunning on
  check/usage, and GET /v1/internal/suspensions for the control plane.
- Portal config: monthly<->annual + cancel only (seats follow membership).
- e2e: seat add/remove proration, grace expiry -> suspend -> pay -> resume.

Desktop
- Team section + account menu item: members/roles, invite, change role, remove
  with confirm, revoke invites (owners/admins, auth role rules mirrored).
- Payment issue banner with suspension date and Update payment method.

* feat(billing): in-app plans page (#22)

A pricing/plans page reachable from the account menu ("Plan & billing"), the
Settings plan section ("Choose a plan" / "Compare plans"), and any upsell via
openPlansPage(). Everything comes from the billing service's offers: Team
monthly/annual (with the computed annual saving), pooled hours, Large weight,
concurrency, idle sleep, opt-in overage with spend cap, and Enterprise contact.

- States: choose (admin), locked (member), current plan with usage, payment
  failure (status-first), checkout in progress, loading and failure with retry.
- Seats are read-only: one per team member (billing re-reads the count).
- Shared card shell keeps both cards' footers level; sliding interval toggle and
  price fade respect reduced motion; dialog opens without a pre-focused button.
- Worker offers gain per-seat cents and the Large weight for totals.
- Copy matches the marketing /cloud promises: agents keep running, wake in
  seconds, secrets never stored in the VM.

* wip(cloud): Orca Cloud built-in provider wiring

* feat(cloud): no-plan upsell opens the plans page

* feat(cloud): Orca Cloud dogfood fixes (provider persistence, picker label, any-input activity, idle override)

* fix(cloud): live dogfood fixes (snapshot already-deleted, agent egress wildcards, golden image id) + results

* fix(cloud): i18n keys, typed dev JWK, verdict typing

* feat(cloud): billing caps from billing (maxConcurrentSandboxes, per-member), userId on usage; concurrency copy

* feat(cloud): golden image can pin a released orca-server tarball (--release), source build stays the fallback

* fix(cloud): async dev key read, runtime localization catalog
2026-11-09 02:59:02 -08:00
Neil 576b4684f7 feat(billing): peak-seat billing and abuse limits (#25)
- Seats billed = the period's peak membership: adds above paid seats are charged now
  (always_invoice); removals never credit mid-period and only lower the quantity inside
  seatTrueDownHours of renewal (proration none), so remove/re-add churn can't dodge or
  double-charge. The cron applies deferred decreases from the last pushed count.
- Included hours and caps come from billed seats; per-member concurrency cap
  (member_concurrency_limit); usage attributed to the member who started it.
- Start check returns billed `seats` and the derived caps for the control plane.
- Desktop shows when paid seats drop at renewal; proration copy updated.
- Design doc: seat-fairness decision with the GitHub/Cursor/Slack/Linear comparison.
2026-11-09 02:34:43 -08:00
OrcaWinandOrcaWin a163b9fc5b test: remove low-value copy, inventory, and runner assertions (#40282)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-09 10:25:23 +00:00
Neil 0744798c98 fix(cloud): bind GitHub App installations to Orca accounts; kill switch, caps, rate limit; orphan sweep and retention (#24)
Security (B1): repo tokens were minted for any repo.url where the app was installed. Now an
installation must be bound to the caller's account (signed single-use connect state + OAuth proof
that the installer owns the account or is an org admin), tokens are scoped to the one repo and the
binding is re-checked on cached tokens. Operator binding route for support/dev.

Guardrails (B3/G4): D1 kill switch + static flag refuse create/resume/rollover and drain running
sandboxes; global running cap; 3/seat per-account backstop; per-account create rate limit.

Retention (B4/B6): hourly orphan sweep (stop, then delete after grace; partial listings delete
nothing), 30-day deletion after cancel/unpaid with a T-7 warning hook, 90-day idle retention,
104-day provider snapshot expiry backstop, repo_url tombstoned on destroy.
2026-11-09 02:19:25 -08:00
Neil ad6646c303 feat(cloud): org/personal/repo secret store with envelope encryption and session-start injection (#23)
D1 secrets table (migration 0003), AES-256-GCM per-secret DEK wrapped by SECRETS_KEK with
(scope, owner, name) AAD and key-id rotation; write-only /v1/secrets CRUD with org owner/admin
checks; precedence-resolved injection into orcad's env at every boot (no disk, no rebuild);
optional egress placeholder swap for api.anthropic.com / api.openai.com via the forwardURL proxy.
2026-11-09 02:19:24 -08:00
Neil 53d00d1985 fix(cloud): GitHub App setup page, dev-account billing bypass, live push results (#21)
* fix(cloud): GitHub App manifest page uses a visible submit button

* feat(cloud): dev operator accounts bypass billing outside prod; GitHub App push results
2026-11-09 02:19:24 -08:00
Neil 6130c4d793 feat(cloud): GitHub App repo tokens + billing dev wiring for the sandbox control plane (#20)
* feat(cloud): GitHub App installation tokens for sandbox git (manifest flow, minter, policy refresh)

* feat(cloud): billing dev wiring — shared control-plane token via service binding, grace-expired suspensions, standard/large only
2026-11-09 02:19:24 -08:00
Neil 018c986c34 feat(cloud): dev deployment of the sandbox control plane (dev operator keys, dev egress credential) (#17) 2026-11-09 02:19:23 -08:00
Neil a4d6079510 fix(cloud): live Vercel Pro findings (bundle download, rehearsal cap) + results (#16)
* fix(cloud): provision bundle download no longer overwrites its source; shortened session deadline for staging rehearsals

* docs(cloud): live Vercel Pro results
2026-11-09 02:19:23 -08:00
Neil a91ae681f5 feat(cloud): 24h rollover, idle stop and agent auto-resume for Orca Cloud sandboxes (#13)
* feat(cloud): hosted session lease scheduler — 24h rollover, idle stop, agent auto-resume

* refactor: parse restart offers without casts
2026-11-09 02:19:23 -08:00
Neil b846bf40e6 feat(cloud): golden image build (orcad + agent CLIs, identity wipe, kept snapshot) (#12) 2026-11-09 02:19:22 -08:00
Neil c2ebfd00aa feat(cloud): sandbox control-plane Worker (white-label Vercel) (#11)
* feat(cloud): sandbox control-plane Worker (Vercel behind an interface, entitlements, usage, egress proxy)

* ci: collect sandbox-control tests
2026-11-09 02:19:22 -08:00
Neil e7989e6d6e docs(cloud): white-label Vercel sandbox driver design (#8) 2026-11-09 02:19:21 -08:00