config/cloud-build-defaults.json feeds an ORCA_CLOUD_BUILD_DEFAULTS define in main; packaged
builds read no shell env. ORCA_BUILD_BILLING_API_URL / ORCA_BUILD_CLOUD_SANDBOX_URL override at
build time, ORCA_BILLING_API_URL / ORCA_CLOUD_SANDBOX_URL at run time. Public endpoints only.
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.
The browser-extension preload was a main-build Rollup input, so it could be
split into shared CJS chunks that a sandboxed preload cannot require. Build it
with the other guest preloads as a self-contained bundle, and share the
one-byte unminified output options between the preload build and sandboxed
bundles so the extension preload stays one-byte in V8.
Co-authored-by: Neil <neil@stably.ai>
Request the project on the shared issue node fields and map it in
mapRawIssueForWorkspace, so list/search rows carry the project the same
way issue detail already did. Detail now reuses the shared mapping.
Co-authored-by: Neil <neil@stably.ai>
The Codex config line scanner only treated exactly three quotes as the
multiline closer, so a value like '''printf 'ok'''' left the scanner
inside the string and later tables (e.g. [projects."..."]) were missed
when writing project trust. Match toml_parser: a run of 3-5 quotes
closes the string, with up to two quotes belonging to the content.
Co-authored-by: Neil <neil@stably.ai>
Claude reports deferred categories (MCP tools, system tools loaded on
demand) that sit outside the used total, but summarizeContextUsage
dropped the flag, so the popover listed them as window percentages next
to real usage and the rows summed to well over 100%.
Keep the deferred flag on each summary row and render deferred rows in
their own group under a divider, with token counts instead of a share of
the window and a note that they are not counted in the used total.
Fixes#39878
Co-authored-by: Neil <neil@stably.ai>
Link underlines in Native Chat, the markdown preview and the rich markdown
editor sat 2px below the baseline, so descenders (g, y, p, j) crossed them and
skip-ink broke the line into dashes. Use a 0.25em offset that scales with font
size and zoom, and override the shared renderer's underline-offset-2 in Native
Chat.
Fixes#40217
Co-authored-by: Neil <neil@stably.ai>
Claude echoes "Set model to Opus 5.5" without the "Claude" vendor prefix,
and never echoes the picker-only " alias" suffix or a raw "claude-" id
prefix. The confirmation observer required every picker-label token, so a
successful switch resolved to unknown and showed "Could not verify the
model change". Normalize the expected label before matching; context
tokens such as 1M are still required.
Fixes#40058
Co-authored-by: Neil <neil@stably.ai>
When a dashboard card has no live PTY (e.g. chat-session tabs), the agent
dialog previously showed only the "preview unavailable" notice. It now also
renders the card's stored last user/agent messages, unclamped and scrollable,
below the notice. The rendering is extracted into AgentCardLastMessages and
shared with the kanban card, which keeps its line clamps.
Fixes#40144
Co-authored-by: Neil <neil@stably.ai>
* fix(diff): persist inline / side-by-side diff view via the Default Diff View setting
The file diff and combined diff toolbars toggled inline vs side-by-side only
in local component state (plus a session-only module preference for the
combined diff), so switching worktrees or agent threads reopened the diff in
the saved inline default.
The toggle now writes the existing diffDefaultView setting, and both viewers
derive sideBySide directly from it. The per-view cache and module memory no
longer carry a separate sideBySide value.
Fixes#40241
Co-authored-by: Wooseong Kim <2222333+innocarpe@users.noreply.github.com>
* test(diff): drop the removed sideBySide field from the cached combined-diff view
---------
Co-authored-by: Neil <neil@stably.ai>
* fix(terminal): don't restart every dead saved tab when a worktree opens; log how the daemon exited
Opening a worktree mounted every saved terminal tab that had no PTY, and each
hidden mount started a fresh shell or agent. With many finished agent tabs this
started dozens of agents at once and could exhaust a host's process limit.
Saved tabs with no PTY anywhere and nothing queued to start now wait until
they are shown; the existing capped idle warm-up still admits up to four.
The main process now records the daemon's exit code or signal and names it in
the respawn log line.
Fixes#39166
* fix(daemon): forget a predecessor's exit when a replacement daemon launches
The plain-shell readiness test polled with vi.waitFor (1s default budget)
for reconcileConfig and the spawn env. Under CPU load the spawn takes over
a second and the test failed with 'expected undefined to be defined'.
Await an explicit reconcile-started signal and the spawn itself, and move
cleanup to onTestFinished so the gate is released and spies/env restored
even when a regressed spawn blocks until the test timeout.
Fixes#40078
Co-authored-by: Jerry Wu <haoyuwu@andrew.cmu.edu>
The native chat split action required the source agent-session tab to carry
a TUI agent tag, so sessions without one (e.g. untagged or non-TUI agents)
could not be split and the tour's split step stalled. Any agent-session tab
in a known group is now a valid split source.
Co-authored-by: Neil <neil@stably.ai>
The sticky External Ports header used hover:bg-accent/50, a translucent
background that let scrolled port rows show through on hover. Blend the
accent into the popover color so the hover state stays opaque.
Fixes#40056
Host session-tab snapshots rebuild native chat tabs without the
client-owned focus visit, so Cmd+J recents ranked chats last and showed
their creation time.
Fixes#39841
* 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
* test(vm): pin file saves in a recipe-created Orca server workspace (#11762)
* test(vm): wait for the save round trip, let the app reconnect itself, edit a plain-text file
* test(vm): say why the recipe save spec needs a longer timeout
* refactor: group renderer workspace ownership and navigation
* refactor: use the defining WSL rewrite store identifier
* refactor: route new upstream consumers to workspace owners
* refactor: consolidate connection owner test imports
* refactor: preserve upstream review-owner test retirement
* feat(release): publish a server-only Linux tarball for orca serve
Each release now also uploads orca-server-linux-x64.tar.gz and
orca-server-linux-arm64.tar.gz (orcad slot from the qualified template, the
pinned Node, and an orca-ide launcher) plus orca-server-sha256sums.txt, so a
Linux host can run orca serve without the desktop package.
The tarballs are packed and smoke-tested (serve --recipe-json, then pair a
second profile) on both architectures, including bare ubuntu:24.04 and
debian:12-slim containers. Upload runs only after the release is published
and nothing depends on it, so it cannot hold the desktop release.
* fix(release): keep the server tarball's launcher env out of its terminals; skip refs that predate it
- The launcher runs the CLI with ELECTRON_RUN_AS_NODE=1, as the packaged app does, and the CLI strips it
before starting orcad; ORCA_APP_EXECUTABLE and ORCA_SERVE_RUNTIME are cleared.
- Ship Node's LICENSE beside the runtime.
- Skip packing on release refs that predate the scripts, and upload only when both tarballs passed.
- Run the PR smoke when the CLI's serve-runtime selection changes; document service install.
- 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.
Sign out of Claude/Codex on a host now runs that agent's logout against the
login launches there use, after a confirm dialog, instead of deleting the
host's saved Orca account. The host check asks the CLI in that same login.
Starting Claude or Codex on a runtime host where it isn't signed in holds the
launch behind an inline card. Sign in with browser runs the unmodified CLI login
on the host; this computer forwards the browser's localhost callback to it over
a narrowly scoped tunnel, so the token never leaves the host. Adds a verdict-only
host check, agent sign-out in the host menu, and paste/device-code fallbacks.
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.
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.