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>
* perf(mobile): let newer phone shells fetch the language catalog from the desktop instead of downloading all of them
* fix(mobile): hash only the buildId fields so phone readers can recompute it
* fix(mobile): use the catalog chunk when the generation still has it
* fix(desktop): give catalog reads their own read-slot budget
Download progress counted inflated asset bytes, so the caption read
"x of 12.9 MB" while about 4.3 MB of brotli copies travelled. Progress now
counts what the reader moves: each brotli copy where one is read, raw bytes
otherwise, and nothing for reused assets. The first total before any
progress uses the same rule.
Feed only listed agents waiting on you, so a phone with agents busy on the
desktop showed none of them. The section now lists agents that need you
first, then working ones, still capped at three with a link to the Agents
tab.
On the phone, Codex's Standard/Fast speed was a Speed row opening a
list while Claude's Fast mode was a switch. A Fast-only speed now uses
the same switch row; more speeds, or a lone Flex, keep the list. The
lone-Fast rule moves to shared code so desktop and mobile follow one
rule.
* feat(mobile): create a worktree per repository from an empty folder workspace
A folder workspace with no attached worktrees lists one card per
repository in its project group, as desktop's empty state does. Tapping
one creates a worktree named after the folder, attached to it, in place;
a taken name or a setup choice opens the new-workspace composer with the
repo, the name and the folder parent filled in. Shown only when the host
creating it supports exact-name creation.
* chore(mobile): merge the folder repo read's execution-host imports
* fix(mobile): folder creates keep their repository until the folder shows them
Every create from a folder's empty state, direct or through the
composer, holds its repository from admission until the folder lists
the new worktree, so a lost reply, a remount or a reopened form can't
start a second one. The composer and toasts belong to the folder
screen, stay on the folder's host, and say nothing once it's left. A
relayed server's repository read holds no desktop event stream, and a
failed read can be retried.
* test(mobile): a folder create resent after a lost reply carries the same mutation id
* fix(mobile): folder creates keep their name, and a left or replaced form shows and holds nothing
* fix(mobile): pause folder rows under the create form; a lost folder create is checked, never resent as another
* fix(mobile): a folder card never resends a form's create, and one form owns the folder screen at a time
* fix(mobile): a folder setup choice resends only its own unconfirmed create, and the newest form silences older ones
* test(mobile): declare the submit hook's folder launch in its recording fixture
* fix(mobile): a create refused on a resend after a lost reply tries no other name and stays unconfirmed
* fix(mobile): a replayed refusal after an agent-launch fallback stops the retry, and the composer says it may have been created
* test(mobile): type the replayed refusal reply in the retry test
* ci: retrigger checks
* fix(mobile): localize the folder and uncertain-create messages in the workspace composer
* perf(mobile): load the terminal engine and the session dock only when needed
Opening a session parsed xterm (with its WebGL addon) and the wide-layout
dock's Source Control and Files panels, even for chat sessions on phones.
The page's terminal now imports its engine when the first terminal mounts,
and the dock lazy-loads its panels behind a frame that paints at once.
The page build anchors lazy modules that share boot code the way it already
anchors routes, so the new lazy chunks don't split the boot chunks.
* fix(mobile): show the terminal start error when replaying queued commands throws
Extract shared state/helpers into leaf modules (pure moves, re-exports kept)
so import/no-cycle can run at full depth with type-only imports ignored.
120 src + 8 mobile cycles -> 0. 10 suppressions remain on the browserManager
singleton hub, which needs DI to break.
iOS emptied Library/Caches under storage pressure, and Android's cacheDir is
cleared by Clear cache, cleaner apps and low storage. Each purge cost a full
foreground download of the page build on the next open. Builds now live in
Application Support (excluded from backup) on iOS and filesDir on Android
(kept off device transfers), and the old cache folder moves over once.
* fix(mobile): stop reading a tab's name as its agent's terminal title
The host publishes a terminal tab's name (custom name, quick-command
label or agent session name) in place of its live title. Mobile fed
that name to the shared tab-agent resolver as title evidence, so a
finished Claude tab named "Agy status bar item" was read as a reused
Antigravity pane. Desktop resolves from the raw title and shows Claude.
Fixes#40084
Co-authored-by: Wenhao <4804785+Manho@users.noreply.github.com>
* fix(mobile): re-render a terminal tab when only its name changes
---------
Co-authored-by: Wenhao <4804785+Manho@users.noreply.github.com>
Files past the LCS cell budget fell back to prefix/suffix diffing, so two
edits at the ends of a 450-line file showed every line as rewritten. Use
jsdiff's Myers diff bounded by edit count for those files, keeping the
prefix/suffix fallback for mass rewrites.
* fix(mobile): keep the selected GitHub project when switching projects
Picking another GitHub Project on the phone snapped back to the first one.
A remembered desktop Board view made the pick throw before it committed,
and a committed pick wrote picker rows (title, summary) into settings,
which the host's strict schema refused, so the next hydration restored
the old project.
Commit only identity fields, ask for a view when the remembered one is
not a table, keep the candidate project's views out of the active list
until it commits, drop late view replies from an earlier pick, and key
Browse rows by project identity.
Co-authored-by: Eng. Mahmoud Bek ElNemer <tt21913@gmail.com>
* fix(mobile): keep github.com implicit in project refs and error on projects with no table view
---------
Co-authored-by: Eng. Mahmoud Bek ElNemer <tt21913@gmail.com>
* feat(mobile): announce dictation to VoiceOver through the shell
* feat(mobile): speak dictation from the host, so leaving the session and the pill's toasts are announced too
* fix(mobile): say dictation outcomes where they are known, and re-read a repeated live message
* fix(mobile): leave a setup refusal to its setup sheet instead of reading the raw code
* fix(mobile): say cancelled when a kept recording is discarded
* perf(native-chat): keep streaming chats from re-projecting their whole transcript
Each stage of the streaming transcript pipeline (reducer merge, question
pass and receipts, message projection, desktop list fold) keeps its
previous input and output and re-derives only revised or appended rows,
falling back to the existing full projection whenever another row could
change. Desktop folds through the phone's fold units, now shared, and live
trims batch by a bounded slack so appends keep row positions.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* perf(native-chat): reuse appended subagent rows and batched revisions
Appended rows in chats with subagent rows extend their turn chunk when
earlier turn inputs are unchanged; batch merges and multi-row revisions
do one pass each; rows without journal positions keep in-place reuse.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* perf(native-chat): look up subagent chunks once per appended batch
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(native-chat): pin the live trim slack
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(mobile): smart rail keys for the terminal agent's state, with Shift/Ctrl/Alt latches
* fix(mobile): cancel key presses only when the key row really moves
* fix(mobile): keep Smart rail on through Reset Defaults and finish two-write keys
* fix(mobile): only a finger scrolling the key row cancels its presses
* fix(mobile): hold the smart group until the tap's press lands, and drop clicks on keys that moved
* refactor(mobile): simplify the smart rail touch hook and layout read
* chore(mobile): allowlist the Shift, Ctrl and Alt key names
* feat(mobile): Codex async question keys on the smart rail
* fix(mobile): drop the Codex Always key, whose key differs by approval
Codex binds "don't ask again" to p for a command-prefix rule and a for session and file approvals (0.136 through 0.166). The permission hook doesn't say which one is on screen.
* Fork Codex replies from the current history after rewind
* Strengthen Codex fork preparation failure coverage
* Preserve Codex fork compatibility and original chat guidance
* Explain when Codex cannot start for a fork