* fix(native-chat): hold an automatic continue until the chat's account has usage again
The automatic continue after a usage limit sent at the cut's reported reset
without looking at the account, so it could send into a still-spent weekly
window. Each sweep pass now attributes the chat's launch account (the host's
launchAccountHome) to Orca's polled reading taken in that same home, and holds
the send until the latest spent window's reset (+15 s). The hold is derived
each pass, never saved, only grows for one cut and account, and waits up to two
minutes for a reading taken since that reset before falling back to the reset
it has. A spent window with no known reset stops the automatic continue for that
cut; on System Default, where Orca can't tell which login a reading saw, a fresh
reading with room releases both. Rows on desktop and phone show the held time
through an optional continueAt; older clients keep the cut's time.
* fix(native-chat): attribute usage holds once per account and retire them with their scope
- C1/X7: launch home resolved once per provider and reading once per (provider, home) per pass; narrow usageReading accessor replaces getState().
- X8: forget() drops the hold; hidden-chat caches are pruned while the setting is off; readState stores nothing for an unattributed chat.
- X3/C3: launch and reading homes compared in canonical form (~, dot segments, async realpath, bounded cache).
- X4/C2: a hold belongs to its scope (canonical home + billing kind) and retires when it changes.
- X2: a launch whose provider has no reading yet asks once and waits within the two-minute window.
- X5: attribution runs before the overdue check, so a restart keeps the account's later reset.
- X6: the launch account is re-attributed right before each send; beforeRun refuses a changed attribution.
- C5: cold chats publish when their continue time moves.
- X1/C4: WSL launches keep the cut's own reset (no hold).
* fix(native-chat): gate held continues on an account scope token and stop reviving stale cuts
- C6: a hold extends only with a spent window that had begun by the cut's reset.
- X6-R2, X10, P1-1: a synchronous account scope token (selection, launch env, reading home and
provenance) is captured at attribution; send() re-resolves only when it moved, memoized per
token, and beforeRun compares live and captured tokens. Opening a chat drops only cold-cut caches.
- X11: production tick() test at N=300 and 10N=3000 counts resolver and reader calls.
- X2-R2: the bootstrap wait starts when a pass first sees the due send without a reading.
- X9: canonical homes are resolved once per account per pass; the unbounded-lifetime cache is gone.
- C5-R2: unloaded chats have no status push path, so the cold continueAt publication is removed.
* fix(native-chat): separate continue eligibility from current spending and bind sends to their attribution's sources
- X12: a cut's eligible anchor (its reset, an established hold, or a covering window) takes the
24 h overdue test; once eligible, every currently spent window holds the send.
- X13/P1-2, X6-R3: the account owner returns attributions with a synchronous source witness
(settings snapshot identity, cached login-shell capture revision, reading-source identity);
Claude billing comes from the launch's own env composition. A result whose sources moved while
it resolved is discarded; send() and beforeRun bind to the attribution's own witness and
supersede without spending an attempt.
- CI-1: the scope-token type assertion is gone with the token.
* fix(native-chat): keep a covering hold beside spent windows of unknown reset
- X12-R4 / C7: rebuilding the covering anchor skips spent windows whose reset, and so start, is
unknown; the eligible branch still refuses on them.
- E1-R4: the preparation-change and suspended-attribution race tests run on a Claude chat
through the real host send, mutation and accepted settlement.
* refactor(native-chat): move the usage-limit continue status into its own wire module
The merge with main put agent-session-wire.ts one line over the 300-line limit.
* fix(native-chat): read the shell capture revision lazily so module mocks without it still load
Tests that main added mock login-shell-environment without the revision accessor, so binding it at module load failed.
* fix(native-chat): release a usage hold on fresh room for any account without stranding the cut
- QA-1: room in a fresh attributed reading newer than the last spent evidence (spentSeenAt)
releases the hold and clears an unknown reset for every account; the System Default-only
branch and identityKnown are gone.
- QA-1b: the release pulls heldUntil down to that reading instead of clearing it, and an
unknown-reset hold anchors on its last evidence, so a release over a day after the cut sends.
* fix(native-chat): release an expired usage hold from its room reading and ask for readings while a reset is unknown
- R6-1 / QA-1b-R6: a release sets heldUntil to the room reading itself, so an expired finite
hold followed by an unknown reset no longer strands the cut.
- R6-2: the usage poller idles while Orca is unfocused with no viewer, so an unknown reset asks
for a non-forced reading at most every 10 minutes through the existing refresh.
* fix(native-chat): bound unknown-reset readings per account and honor the failure backoff
- R7-1 / X-R7-1: the rate-limit service owns the automatic-read cadence: a read waits while the
provider's last reading or admitted automatic read is within the asked interval, so held chats
on one account cause at most one unknown-reset read per 10 minutes.
- R7-2: automatic reads wait out the poller's failure backoff (shared failureRetryDue) and start
its clock; forced refreshes are unchanged.
* fix(rate-limits): scope automatic usage-read admission to the selected account
- R8-1 / X-R8-1: an admitted automatic read counts toward the cadence only for the account whose
reading source the service held then, so a switch never lets one account's read delay another's.
- Prunes the flaky-test-pattern baseline: service-refresh-orchestration no longer reads the wall clock.
* fix(native-chat): keep a usage-reading request retryable until the service starts it, and show the last known reset while one is unknown
* fix(native-chat): show no automatic continue while a chat waits on an unknown reset, since fresh room still releases it
* fix(native-chat): publish no continue time for a cancelled or stopped cut while its account's reset is unknown
* fix(native-chat): refuse a stale startup-dialog card choice and add a card for the multi-server MCP dialog
* fix(native-chat): drop casts from the startup-dialog guard
* fix(native-chat): refuse a startup card choice until the screen model has applied all received output
* fix(native-chat): refuse a clipped MCP server list and guard restored startup cards
* fix(native-chat): allow one startup card choice per screen so a second client's keys can't hit the next dialog
* build(mobile): upgrade to Expo SDK 58 and React Native 0.88
Expo 58 drops Zod from @expo/cli, which clears the last Zod 3 advisory
(GHSA-mrhx-c7xc-m3w5) in mobile along with its local patch and override.
- Expo 55 -> 58, React Native 0.83 -> 0.88, React 19.3, gesture-handler 3,
webview 14, reanimated 4.7, worklets 0.13 (SDK 58 bundled versions,
pinned below today's batch to respect minimumReleaseAge).
- Port the react-native and react-native-webview patches unchanged; drop
expo-constants, expo-notifications, @expo/cli, expo-router, zod and
query-string patches plus the zod/query-string/xcode>uuid overrides,
which upstream fixed or no longer need.
- iOS minimum rises to 16.4 (Expo 58 / RN 0.88 requirement).
- Migrate to RN 0.88 strict types: instance ref types, NamedStyles,
AppState.currentState, list header/footer nulls.
- Replace removed runtime APIs: InteractionManager -> idle callback with a
macrotask fallback; StyleSheet.absoluteFillObject -> absoluteFill;
FileHandle.readBytes -> readBytesSync (it became async).
- Resolve react-native/asset-registry for shared assets in Metro and alias
the old registry path for react-native-svg in the desktop mobile-web bundle.
- Reduce the iOS scene plugin to the reconnect override; Expo 58's template
now ships the scene delegate itself.
* fix(mobile): bridge react-native-svg web imports and libsodium runtime for RN 0.88
- Share react-native-svg web shims between the mobile-web build and its render
checks: map the old asset-registry path to react-native-web's registry and stub
the Android-only touch-sound TurboModule.
- Patch react-native-libsodium 1.7.0 to read the JSI runtime from the bridge proxy;
RN 0.88 removed RCTCxxBridge.runtime.
* fix(mobile): use Expo 58's legacy promise resolver for audio permissions
* fix(mobile): skip null handles in the RPC recording timer shims for RN 0.88 types
* style(mobile): format MobilePRSidebar after rebase
* fix(mobile): name RN 0.88 text input refs for declarations; allow queued back in stack render check
- Type text input refs with an exported interface so declaration emit can name hook results
(RN 0.88 aliases TextInputInstance to an unexported class).
- Expo Router 58 drains back() after a commit; check the interrupted push's exit from the
frame it starts, bounded to three frames of lag.
* chore(mobile): justify the text input handle interface for React Doctor
* chore(mobile): use a nameable intersection alias for text input refs
* fix(mobile): use sync expo-file-system writes, copies and moves on Expo 58
Expo 58 made File.write/copy/move and FileHandle.writeBytes return promises.
Our callers never awaited them, so failures escaped their try/catch and the
store's tmp-then-move and PDF writes could race their close or rename.
* build(mobile): raise the page bundle budget to 10 MiB for Expo 58
Expo 58 adds about 310 KB to the page: expo-router (+258 KB, now carrying
React Navigation, net about +110 KB) and Reanimated 4.7 (+152 KB). Main had
85 KB of headroom left. 10 MiB still stays within the 10 MiB per-asset contract.
* fix(mobile): drop the window-metrics seed RN 0.88 removed from Android
RN 0.88 no longer holds window metrics: DeviceInfoModule reads the activity's
WindowMetrics on demand and setWindowDisplayMetrics is gone, so MainActivity
no longer compiled. Layout scale still comes from the screen metrics we reseed.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
A keyboard's mic button switches to a separate voice IME, which closes the keyboard and opens the voice panel about 250 ms later. The page read every Android keyboard close as Back and blurred the field at once, so the voice IME's text had nowhere to go. Blur only once the keyboard stays closed for a second; a reopen within that window keeps focus.
* test: remove 60 low-value cases and orphaned conversion fixtures
* docs(ci): list supported Windows SSH host cells
* test: recognize direct Windows orcad server entry
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(native-chat): answer Claude/Codex folder-trust dialog from a chat card
* fix(native-chat): show a chat card for Claude/Codex startup menus
* fix(native-chat): keep startup-menu cards holding Send; drop hand-typed identify retries
Startup-menu cards now hold the composer like the folder-trust card, so collapsing one can't free a Send whose Return would pick the highlighted choice.
The hand-typed agent probe retries and agentless hold are left out; Orca-launched panes already know their agent, and hand-typed native Claude identification predates this fix.
* fix(native-chat): read the whole screen for a tall startup dialog's heading
* fix(native-chat): drop the unreachable cwd prompt from startup-menu reasons
* fix(native-chat): show startup-menu warning text and give its choices no default
A startup-menu card now carries the dialog's body (Claude's bypass, API key, MCP and import warnings) under its heading, and its choices render as equals on desktop and mobile so Orca never nudges a consent choice. Long mobile option labels wrap inside their button.
---------
Co-authored-by: Kooooojun <edisonhuang1122@gmail.com>
* fix(mobile): show Loading for a new Tasks search instead of the previous search's rows
A new filter or search with no kept rows kept the same provider's rows on screen until the host's read landed, so a slow host looked like search did nothing. Only a re-read of the same list now stands on its rows; desktop already shows its load skeleton here.
* test(mobile): re-record Tasks list goldens for the new-filter spinner
* fix(mobile): hold Tasks paging while a new filter loads
* test(mobile): type the new-search spinner test's GitHub row fully
The phone's stale-resize filter took the binary scrollback frame's seq as
its layout high-water mark, but that seq counts output bytes, not layout
changes. A Desktop/Phone toggle on a terminal with little output then
looked older than the mark and was dropped, so the phone never resized
and kept showing the old mode. Seed the mark from the subscribed frame's
layout seq and leave scrollback out of it.
Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>
* fix(native-chat): show session skill argument hints in the picker
Claude Code reports argument-hint on skill commands. The native chat skill row kept only the name and description, while built-in commands in the same picker still showed their hint.
* fix(native-chat): keep a skill's hint before Claude classifies its catalog
Before the first stream init, Claude lists skills as unclassified commands.
A scanned skill of the same name replaces that row and dropped its hint.
Fold the three hint tests into one shared-layer test and show a skill hint
in the picker fixture.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* feat(mobile): pick the PR glyph from PR state
Workspace rows always drew the open-PR glyph and only changed its color,
and the PR tab's state badge had no glyph. Both now show merged, closed and
draft glyphs, from one prStateIcon mapping that the details sheet and task
rows also use.
* feat(mobile): show the PR state on the session header's source-control button
The button always drew a branch glyph. When the worktree's catalog row has a
linked PR it now draws that PR's state glyph in its state colour, read from
the host list's worktree.ps query in its own component.
* fix(mobile): read the header's PR state from the catalog cache only
Opening a session must not request worktree.ps before its first paint, so the
source-control button reads what the host list last loaded instead of
fetching it.
* feat(appearance): let app chrome follow the terminal theme
Add an "App Chrome Appearance" setting (Default / Match Terminal) next to
Left Sidebar Appearance. In match-terminal mode the terminal theme's
background/foreground are written as document-root CSS variables
(--bg-titlebar, --background/--card/--popover/..., both sidebar token
families), so the tab strip, status bar, side panels, full-page views and
popovers all follow the terminal instead of the app theme. Left-sidebar
modes still win because they scope their own variables below the root.
The terminal color pair and token derivation move into
terminal-surface-colors.ts and are shared with the sidebar resolver.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(status-bar): configurable usage format template
Add Settings → Appearance → Status Bar → "Usage format": a template that
replaces the built-in per-provider usage text when non-empty. Placeholders
cover {provider}, {plan}, the 5h/7d/fable/30d windows as percentages
(following Used/Remaining), {x.reset} countdowns, {x.resetAt} clock times
and Gemini {buckets}; "[...]" groups drop out when a placeholder inside is
empty so one template works across providers with different windows.
Whitespace is rendered as authored (whitespace-pre).
Persisted as PersistedUIState.statusBarUsageFormat with a byProvider
override map reserved for later; the RPC UI-update schema gains the
optional field.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(appearance): document touched functions; surface usage format in search
Add one-line JSDoc to every function this branch adds or edits so the
review docstring gate passes. Include the usage-format entry in the
Status Bar section's search match so searching "template" or
"placeholder" no longer hides the parent row, and mention popovers in
the App Chrome Appearance descriptions since the setting styles them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(appearance): let file editors follow the terminal theme in match-terminal mode
With App Chrome Appearance = Match Terminal, the tab strip, status bar and
side panels took the terminal palette but every file pane kept the stock app
theme: Monaco (code, plain text, diffs, notebooks, markdown source) was
hard-wired to `vs`/`vs-dark`, and the markdown preview / rich editor painted
the fixed `--editor-surface` with GitHub-colored hljs tokens.
- `terminal-editor-palette.ts` derives an editor palette from the active
terminal theme (background/foreground/cursor/selection + syntax roles mapped
onto the ANSI slots) and builds a Monaco theme (`orca-terminal`) from it;
light/dark is rated by the terminal background, so a light terminal theme
under a dark OS setting still gets light styling.
- match-terminal chrome variables now include `--editor-surface` and
`--syntax-*`; the hljs stylesheets read those ahead of their defaults.
- `useEditorSurfaceAppearance` / `useMonacoEditorTheme` replace the inline
`isDark ? 'vs-dark' : 'vs'` computations; the diff-section chain passes the
Monaco theme name instead of a dark flag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbWbChctXeMvaR2zdbFY99
(cherry picked from commit dc85fadee0a2664adbf55a49dd3c97c9b10fc111)
* fix(status-bar): honor the usage template in compact usage mode
ProviderSegment only rendered a user template on the verbose branch, so
switching usage mode to compact silently fell back to the built-in
tightest-window label. A non-empty template now replaces the built-in
text in both modes; the mini bar stays verbose-only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbWbChctXeMvaR2zdbFY99
* docs(appearance): document remaining functions touched by the diff
Adds one-line JSDoc to the editor surfaces, diff viewers, palette helpers
and UI-slice entry points this branch modifies so the diff's docstring
coverage clears the pre-merge threshold.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbWbChctXeMvaR2zdbFY99
* fix(editor): keep Monaco theme registration and preview clock out of render
The upgraded oxlint React rules flag reassigning a module variable during
render and calling Date.now() inside useMemo. Move the terminal Monaco
theme's signature cache into ensureTerminalMonacoTheme() and pin the
usage-format preview clock with a lazy useState initializer.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbWbChctXeMvaR2zdbFY99
* localization: complete Brazilian Portuguese catalogs
* fix(i18n): localize remaining hard-coded UI copy and complete Simplified Chinese coverage
Route the English literals and shared English labels that ignored the UI
language through the existing catalog: host labels, plugin cards and consent,
CLI and SSH errors, the checks pill, browser profile labels, shortcut groups,
app and context menus, and the macOS computer-use permission window. Shared
labels are translated where they render, so src/shared stays English for
mobile, CLI and older paired hosts.
- en.json gains 314 keys bootstrapped from inline fallbacks; four duplicate
"Unassigned" keys collapse into translateUnassignedLabel()
- zh gains 337 entries and refreshes existing ones; the other nine locales get
the newly extracted keys
- joinSentences ends a CJK sentence that has no final stop with 。 before the
next one
- the desktop caller passes the computer-use helper its locale; orcad and the
CLI stay Electron-free
- three files the copy pushed past max-lines each shed a focused module
* test: expect labeled roles in the editable context menu
The edit menu now passes explicit Cut, Copy and Select All labels so the roles render in the UI language; the upstream template assertion still expected bare roles.
* fix(i18n): key translated memos on the UI language without bare void reads
Upstream's React Compiler ratchet rejects `void language;`, which the compiler drops, and treats a react-hooks lint suppression as a bailout. The two host-label hooks now pass the language through readUiLanguageMemoInput so it stays a real memo input. ContextualTourOverlay drops its language key: getContextualTour is a static lookup, and step copy is localized at render.
* fix(i18n): translate editor theme settings
* Fix reactive localization and catalog extraction
* Fix combined localization validation
* Localize nested import failures and refine catalogs
* Handle older nested import responses
* Fix localized merge prompts and quota windows
* Address localization and runtime review feedback
* Keep host search and configuration examples usable
* Preserve configured names in add-project host selector
* Preserve host label origins across views
* Use localized fallback for missing local host
* Preserve custom names and refresh localized host labels
* Refresh task host labels without repeating searches
* Preserve Portuguese mobile tab translations
* Address localization review feedback
* fix(status-bar): import window visibility interval from its new path (#40951)
---------
Co-authored-by: lisi <lisi.see@bytedance.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: marlico77 <marlonssoficial@gmail.com>
Co-authored-by: x-Ai <5061489+x-Ai@users.noreply.github.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
Reverts #40592 (12e809c755). The session bar goes back to the scrolling strip of tab cells, the + menu goes back to the action sheet, and the header subtitle shows the tab count again.
* Show Source Control menu rows on one line with a short status
* Keep Push and Force Push clickable; force push shows remote-only commits it replaces
* Match Force Push description to remote-only commits; list review blockers exhaustively
* Show short statuses for every blocked review action
* fix(mobile): tell Android users which WebView to update when it is too old
The page shell needs androidx's DOCUMENT_START_SCRIPT:1, which stable
WebView only reports from Chromium 101; the comments claimed 83/88.
Name the required WebView and the one installed, and how to switch it.
* fix(mobile): read the WebView provider through the shell module index
Tests stub the module index; a direct file import loaded expo-modules-core unstubbed.
* fix(mobile): save the downloaded desktop page on Android 7
Below API 26, expo-file-system 55 moves a directory with File.copyTo, which
creates an empty directory, so committing a downloaded page build always
failed with cache-write-failed. Copy the tree recursively and delete the
source there instead.
* fix(mobile): remove a partial copy when an Android 7 page move fails
* Show phone option preview thumbnails with a full-height viewer
* Use typed renderer host queries in preview interaction coverage
* Register phone preview viewer labels in the mobile catalog
* Keep phone preview thumbnails within the compact frame
* Count supplementary wide characters in phone option previews
* Keep the readable option preview subscribed to theme changes
* Correct mobile preview test typing and positional page identity
* Explain the immutable answer identity used to reset preview scrolling
* Preserve native preview text and measure thumbnail bounds
* fix(mobile): measure preview text at its intrinsic web width
* chore(mobile): document the web-only intrinsic width boundary
* feat(mobile): show the open tab as one pill with a tabs sheet
The phone copied desktop's tab strip, which fits about three tabs cut to
~95 pt and hides a tab that needs you behind an edge dot. The bar now shows
only the tab you're in, at full width, with the tab count. Tapping it opens
a sheet of every tab grouped by what needs you, with each tab's state and
last activity; swiping it steps to the next tab. The + sheet shows agents as
a grid above Terminal, Browser and Markdown note, and the header names the
branch instead of the tab count.
* feat(mobile): pair the tab count with + and open tab actions from the pill
The count and its chevron inside the pill read like a menu and hid the
"another tab needs you" dot. The count now shares a capsule with +, the
way phone browsers put the tab-count button beside new tab, and tapping
the pill opens the tab's own actions.
* feat(mobile): give the tab count its own button beside +
The shared capsule made each half a small target. The count is now a
round nav button like +, lined up under the header's buttons.
* feat(mobile): draw the tab bar as the strip's square cells
The rounded pill and round buttons read as a different control from the
strip people know. The open tab is now the strip's raised, underlined cell
from the screen edge, with the count and + as square cells in the same
row, which also gives them 46x44 pt targets.
* fix(mobile): keep a hairline after the tab bar's last cell in the top bar
* refactor: finish terminal and Mobile defining-owner imports
* fix: retain completion coordinator type binding
* refactor: consolidate direct terminal tree imports
* refactor(renderer): import typography from defining owners
* refactor(mobile): group host catalog credentials descriptors and connection history
* refactor(mobile): import RPC sender and result types from defining owners
* refactor(mobile): colocate push delivery with registration operations
* refactor(mobile): point push recordings at delivery owner
* fix(i18n): update permission and mobile task translations
* fix(i18n): retain community Portuguese pagination copy
Adopt the matching translations from #39124, also carried by #40456.
Co-authored-by: marlico77 <marlonssoficial@gmail.com>
---------
Co-authored-by: marlico77 <marlonssoficial@gmail.com>