* 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>
* 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>
* perf(github): use the desktop's PR fallback rule on the phone and forward refreshes
* fix(github): keep a merged fallback PR while the phone has no head
* refactor: import journal queue state from defining owners
* refactor(shared): organize execution and automation owners
* fix: retain type imports used by surviving test cases
* refactor: finish work item owners and refresh validation metadata
* test: infer reconnect status fixture type
* test(claude): resolve source files beside same-named directories
* test(runtime): group repository creation mock registrations
Shows CI result lines in the chat that opened or pushed to a pull request. They're hidden in the terminal overlay and on the phone until the phone app gets the setting.
* fix(tasks): confirm a lost Tasks comment by author on GitLab and GitHub REST reads
Only GitHub GraphQL's viewerDidAuthor marked the viewer's comments, so on GitLab,
the GitHub REST fallbacks (including issues with more than 100 comments) and the
gh view fallbacks the phone kept an unconfirmed draft even after the comment
posted. Those reads now match the login of the account that made them, and an
explicit PR refresh reads comments uncached.
* fix(mobile): settle an unconfirmed comment only on one posted after the send
A refresh of an issue with more than 100 comments reads comments the first
load never showed, so an older identical comment by the same account looked
new and could clear the draft.
* refactor(gitlab): share the glab viewer read and skip it on Checks polling
* test(mobile): pin the clock in the unconfirmed comment test
An unconfirmed send settled as posted when the refreshed thread had any new
comment with the same text, so another person's identical comment cleared the
draft. The host now passes GitHub's viewerDidAuthor, and the phone settles only
on a comment the viewer wrote. Without it (GitLab, REST fallbacks, older hosts)
the draft stays with the check-the-thread notice.
* Upload GitHub images when pasted or dropped
Keep image bytes out of issue and review bodies by uploading from the owning composer and inserting hosted attachment URLs.
Co-authored-by: lydiassssz <60514233+lydiassssz@users.noreply.github.com>
* Preserve GitHub image intake across editor and thread states
* Keep image placeholder boundaries and ordinary HTML paste intact
* Match the native replace overload in the image projection fixture
* Use typed element queries in the image intake fixture
* Narrow textarea elements at the fixture boundary
* Show failed GitHub draft images as filename links
* Keep GitHub draft attachment links current across updates
* Supply the repository address in the attachment preview fixture
---------
Co-authored-by: lydiassssz <60514233+lydiassssz@users.noreply.github.com>
* feat(checks): show when each check ran and how long it took
Check rows in the right-sidebar Checks panel now show how long a
finished check took and how long ago it finished (or started, while it
runs), with exact start and finish times on hover. GitHub check runs,
legacy commit statuses and GitLab jobs carry provider run times; rows
without times show nothing.
A GitLab pipeline that ran on a commit the merge request has since moved
past says so. The GitHub rollup read keys its 60s cache by the expected
head, so a push never serves the previous head's checks.
* test(checks): bound the clock work of check time labels
* perf(checks): rebuild check time text only when its data changes
Clock ticks now move only each row's age; exact times, duration and copy
are built once per data or language change. Move the run-time mapping
tests to the mapping layer to keep the client test file within budget.
* fix(checks): annotate the gh pr checks reply instead of casting it
* fix(checks): say when a running check started; key the rollup cache by a query comment
A running row reads 'started 5m ago' so its age isn't read as when it
ran. The expected head now rides in a GraphQL comment, which servers
ignore but gh's cache key includes. Add the new copy to the English
catalog and test behavior rather than formatted copy.
* fix(checks): let check times truncate before names in a narrow sidebar
At the narrowest sidebar the time text never shrank, squeezing check
names to nothing and pushing status labels out of their rows. The time
now sits beside the name, gives up width first, and the name keeps a
minimum width.
* fix(checks): rebuild check time copy when translation catalogs change
* fix(checks): reserve room for a running check's growing start age
* test(checks): keep REST check-run times covered through the schema
* fix(checks): read the checks rollup without gh's disk cache
gh's cache key ignores the PR head, so after a push it answered with the
previous head's checks, and it never evicts expired entries. Orca's own
head-keyed checks cache and read coalescing already bound the requests.
* fix(checks): hide check times in rows too narrow to show them
Below a 17rem row the time text is hidden, so the narrowest sidebar keeps
main's name, status and link layout; wider rows truncate the time before
the name, which keeps a 36px minimum.
* fix(checks): truncate a check's duration before its age
The age answers when a check ran, so in a tight row the duration now
gives up its width first.
* test(checks): type the rollup fixture
* fix(checks): show check times only in rows with room for them
Between a 17rem and 19rem row the times squeezed names to their minimum
and clipped; hold them back until 19rem, which the default 350px sidebar
clears.
* fix(checks): keep a minimum name width only while check times show
Rows too narrow for times, including the narrower folder-workspace parent
PR rows, now lay out exactly as before.
* fix(checks): show a running check's elapsed time instead of its start age
'started 10m ago' reserved so much room that running check names shrank
to a few characters at the default sidebar width; beside a running status
the elapsed time ('10m') says the same thing in a quarter of the space.
* test(checks): use a type import for the mocked module
* feat(mobile): render GitHub alerts, task boxes, inline tags, images and footnotes
GitHub text on the phone now draws what desktop and github.com do:
> [!NOTE]-style alerts (desktop's marker rule, shared), read-only task
boxes, <sub>/<sup>/<kbd>/<ins> and <b>/<i>/<del>/<code> inline tags, https
<img> and Markdown images at their authored width, raised footnote numbers,
and #123 links in the PR view into the PR's own repository.
* fix(mobile): keep linked badges and commented images, read only pixel widths
An <a href> around inline content becomes a link, so a badge keeps its
target; images inside links, comments, icons by height, and percentage
widths stay as before. Footnote numbers follow the text scale.
* fix(mobile): keep images inside headings and styles in place, read link hrefs as HTML does
Only images that a p, div, picture or center places are cut out of HTML,
in one pass; an image in a heading, link or bold stays in its element.
Inline <a> hrefs use the shared attribute reader (quotes and entities),
<code> keeps only the text of tags inside it, and alert titles follow the
text scale.
GitHub returns no field value for the built-in Parent issue field, so
grouping by it put every row in "No Parent issue". Group by
row.content.parentIssue (keyed by URL so multi-repo projects with the
same issue number stay separate) and order groups by issue number.
Fixes#38099
* refactor(native-chat): move chat link rules and the file-existence checker to shared
GitHub reference linking, the reference-repo rule, chat file-path linkification,
the per-chat existence checker and the path-existence batcher are platform-free.
Move them to src/shared so the phone's chat can use the same rules; desktop keeps
its host adapters and behaves the same.
* feat(mobile): link #123 refs, check file paths and wrap code in chat
* test(mobile): pin which chat paths and refs become links
* refactor(mobile): parse repo link fields instead of casting
* refactor(mobile): own chat link state in the chat overlay
* fix(mobile): keep unchecked chat paths as precise as before
* fix(mobile): only peek at known paths while reasoning streams
* test(mobile): leave #123 splitting rules to the shared transform's tests
* refactor(native-chat): tidy shared link helpers and skip separator-free text
* test(native-chat): import the existence type from its shared home
* style(mobile): fold the code-span link handler onto one line
Show cancelled PR checks as Cancelled with separate counts on desktop and mobile, preserving genuine failures, pending checks, existing action permissions and older-client fallback. Carry complete provider summaries through caches and presentation; preserve Azure source completeness, folder attention priority and muted cancellation details.
Tracked in #15847 and STA-5102.
Keep the GitHub Tasks source picker, rows, totals, searches and issue creation tied to the selected project, host and source. Ignore outdated replies and wait for source preference saves before creating an issue. Preserve support for older paired servers.
Tracked in #8726. Tracked in STA-1815.
* Keep opened GitHub work items bound to their exact repository
* Bind GitHub work item ownership through consumers and dispatch
* Keep empty mention lists from consuming selection keys
* Preserve GitHub action and consumer ownership across resource changes
* Exercise repository account updates through their production store action
* Exercise account publication and cache settlement through GitHub consumers
* Simplify fork PR contract verification
* Make contract verification imports and clocks deterministic
* Correct mobile task test fixtures and model types
* Correct task recording fixtures and CI types
* Correct task fixture types and static checks
* Consolidate replay test RPC imports
* Separate GitHub metadata imports from Linear hooks
* Scope mobile PR sidebar reads to the selected resource
* Separate desktop GitHub changes from phone updates
* Fix relay authority probe census across topology cases
* Repair repository owner proof fixtures and compiler allocation
* Preserve repository row observation in host lookup
* Seed metadata fixture before server-side store acquisition
* Preserve nullable fixture settings and discover mixed test types
* Preserve GitHub detail argument types and optional capabilities
* Let keyed details queries own pending read replacement
* Repair GitHub RPC and relay test fixture boundaries
* Verify expected GitHub account at repository execution capture
* Preserve captured GitHub account expectations through client dispatch
* Retain observed runtime status after switching environments
* Fix account contract fixture types and RPC setup timing
* Restore the negative-capability switch probe assertion
* Align account fixtures with runtime identity and configured origin
* Consolidate details test imports
* Drop duplicate fork pull request identity tests
* Show failed pipelines and check suites without jobs
* Use the parent pipeline as the GitLab checks verdict
The MR's own pipeline status now leads the Source Control Checks panel,
the MR dialog and the phone checks badge whenever the details reply
carries it, even when the returned jobs are empty, partial or all
passing. Job rows and counts stay a separate breakdown. The parent
follows pipeline-level policy (required manual is pending, canceled and
skipped are not failures, mergeable manual is neutral) from one shared
rule, and it is a provider link rather than an expandable job, so it
never shows a details error with Retry. A failed parent leads the
triage strip and joins the Fix prompt by name and link.
Drops the GitHub zero-run failed check-suite rows from this change;
existing approval-required suite rows are unchanged.
* Name the GitLab pipeline outcome and keep its verdict in one rule
The host now settles the parent pipeline's verdict with the same rule
and reply that produce the MR status, so a manual pipeline on older
GitLab reads pending everywhere. The phone checks badge names the
pipeline outcome (Pipeline passed/failed/pending) instead of an
unlabeled one-item count; job wording without a parent is unchanged.
The desktop parent row's status is localized, and a failed MR-details
read still shows its error beside a kept parent with no jobs.
* Keep Fix for failed GitLab jobs and treat waiting_for_callback as pending
The triage strip shows again when a returned job failed under a passing
parent pipeline, so its Fix stays available; a failed parent still
leads. A waiting_for_callback pipeline now reads pending instead of
neutral, in the MR status and the parent pipeline alike.
* Mark the checks-panel action test fixture cast as safe
* Pause the pipeline row spinner offscreen and under reduced motion
The PR tab and the Checks and Comments screens refresh by themselves while
they are open and the app is in the foreground, on desktop's checks-panel
cadence (policy moved to src/shared). A failed background read keeps the
PR on screen and backs off instead of replacing it with an error.
Review threads show the lines they are about: the host forwards the tail
of each thread root's diff hunk, and mobile numbers it back from the
thread's line. Bot findings get "Ask <agent> to fix", which launches
desktop's Resolve comments prompt (moved to src/shared) for that thread.
Fix and Ask buttons name the agent that would start.
* fix(github): start explicit Checks refreshes after the action
* fix(github): give explicit Checks refreshes fresh checks and comments
The same Refresh or Link click that now reads PR metadata after the
action also reads checks and comments after it: an explicit request no
longer joins or waits on a read begun before the click, in the renderer
or (for checks) the host coalescer. A superseded read's callers show the
owner's answer, so a late pre-click reply cannot repaint the panel, and
comments posted during either read are kept.
A lost IPC/RPC reply is reported only to the click that asked; polls stay
silent as before, and a later answer clears a failure older than itself.
The manual hook takes its verdict from its own lookup, the link flow's
card-read failure no longer skips checks, and the web shim forwards the
intent.
* fix(github): land the older Checks reply when a newer explicit read fails
When a click's checks or comments read fails while the read it replaced
succeeds, the click's read now lands that older reply through its owner
path instead of leaving the cache behind it. Post-write comments
refreshes (mutation events, bulk resolve) carry the explicit intent so
they cannot be answered by a read begun before the write.
* test(github): drop type assertions from the explicit-refresh tests
The RPC tests call the handlers with a real runtime service and spies,
and the panel test passes typed fixtures straight to the hooks.
* test(github): type the Checks panel fixtures for the renderer project
The renderer tests build their PR fixture locally instead of importing a
main-process harness, and the panel setter mocks take the hooks'
SetStateAction form.
* fix(wsl): user clicks on cwd-less gh may start the stopped default distro
#35709 stopped background gh/glab from booting a stopped default distro,
which also refused explicit clicks for users whose gh lives only in WSL.
Starring Orca, the auth diagnosis, the project picker, opening a work
item and board edits now run as a user act on the distro the fallback
uses; the board table reload, which also runs unprompted, stays gated.
The GitHub and GitLab rate-limit cards keep their last snapshot on the
not-running refusal instead of flipping to unavailable.
* fix(wsl): only an explicit click may start the stopped distro for project gh calls
Wrapping the project-view and auth-diagnosis IPC handlers as user acts
also let mount effects (useProjectViewTable listing a restored board's
views, GhAuthErrorHelp's diagnosis) start a stopped default distro. The
handlers now wake only when the renderer passes wakeWslDistro, which the
picker browse/select, opening an item and every edit set; mount effects
leave it unset, and the auth diagnosis never wakes.
* fix(mobile): report task pages and review state accurately
* test(mobile): record task page error provenance
* test(mobile): record task page errors in reply matrices
* feat(native-chat): hover cards for GitHub PR and issue links
Links to the chat's own repo (origin or upstream) open a card with the
state, title, author, update time, and +/- or comment count. Bare #123
references in agent replies now link too. Cards use a light one-call
lookup; older hosts ignore the flag and answer with the full lookup.
* test(github): expect the preview options argument in runtime owner/repo lookups
* fix(native-chat): route GitHub link cards by the chat's own host and retry failed repo lookups
The repo lookup took the first worktree with the chat's id, so a twin on
another host could answer, and the preview cache keyed by repo id alone.
A failed slug lookup also left cards off until the chat remounted.
* fix(i18n): localize GitHub project view errors and states
Main now tags Orca-authored project-view failures with an optional
reason code plus host, rate-limit numbers and diagnostic detail; the
English message is unchanged for mobile, older clients and logs. The
renderer maps type/reason to translated copy in the error state, picker,
item dialog and mutation toasts, falling back to the English message for
older hosts and GitHub's own text. Also wraps the layout labels,
unsupported-layout, not-found/too-large copy, picker partial-failure
summaries and the gh sign-in help.
Closes#34589
* test: expect input_too_large reason on oversized project refs
* fix: make project view error copy switches exhaustive
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(mobile): prepare Create PR and the commit action like desktop
Create PR now fast-forwards a behind-only branch before committing, picks its push step
from desktop's shared rule, and the commit-area button reads the branch's review state.
* fix(mobile): keep Create PR commit failures intact and skip fork push-target gating
Restaging after a failed commit is best effort and checks the branch first, and reviews
with their own push target are not gated until mobile reads targeted upstream status.
* fix(mobile): enter Create PR on desktop's intent rule and leave fork push targets ungated
* refactor(mobile): share the linked-review push decision and enter Create PR on desktop's intent rule
Desktop and mobile compose the review push target through one shared function, the
Create button admits branches Create PR can prepare, and older hosts without a lookup
outcome still fail closed on mobile.
* fix(mobile): use desktop's check order, labels and fix-checks prompt in the PR panel
Check, step, reviewer and comment rules move to src/shared; the phone's fix-checks agent
now gets failing log tails, the worktree path and the action's saved agent arguments.
* test(shared): pass only the fields comment mutability reads
* refactor(mobile): gate fix-checks on desktop's broken-check set and drop the prompt re-export
Fix and Rerun show for the same checks the prompt and the host use, desktop imports
the fix-checks prompt from src/shared directly, and job steps split through the shared summary.
* fix(mobile): gate PR merge and linking on desktop's shared rules
Merge state moves to src/shared so the phone stops offering Merge on drafts,
conflicts and blocked PRs, and stops letting branch PRs override explicit links.
* fix(mobile): keep stack merges and stale-link recovery in the PR panel
Mobile now applies desktop's stack override and drops a linked PR the branch has moved
past, and only offers Ready for review when a relaying desktop also forwards it.
* fix(mobile): persist stale PR link clears and add a merge recheck
The phone now writes desktop's link clear instead of rereading the stale link, and a
blocked Merge can be rechecked since nothing on mobile polls PR state.
* fix(mobile): guard stale PR link clears like desktop
Re-reads the worktree before clearing so a link chosen after the lookup survives, and
localizes the merge-state strings the lift exposed to the coverage gate.
* test(mobile): drop identity test for worktree link params
* refactor(mobile): share one stack-merge decision and trim PR panel wiring
* fix(mobile): default worktree bare/archived flags for the stale-link guard
* fix(mobile): label the PR merge button from its default merge method
* fix(forge): skip PR refreshes for a WSL host that is off, and say so
E9 connect policy, part 3. PR status for a workspace on a WSL host is fetched through
the host, and a poll never boots it. While the host isn't ready, the visible-row
refresh skips it (the row keeps its last badge and the existing "host disconnected"
mark), a direct PR refresh keeps the last answer and records a 'host-off' skip, and
the Checks panel says the host is off and to reconnect it. The cached-field half of the
refresh candidate moves to its own helper to keep the lookup file in bounds.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(forge): a WSL host that goes off keeps its last PR badge and records host-off
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(forge): only a stopped or closed WSL host is "off"; mark row badges as last known (E9 review)
Review of #33840:
- Connecting, reconnecting and unverifiable hosts were treated as off. Only a
confirmed-stopped (or parked) host, or one closed with WSL hosts turned off, is off
now; anything else lets the call proceed or fail as usual. A status change re-runs
the visible refresh, so rows refresh as soon as the host turns ready.
- Row badges now carry the stale mark too: the card's review status gets the hover
card's last-known treatment and "Last known status" in its label, and the hover
card's reference rows are stale and not fetched while the host is off.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(forge): build the host-off PR refresh test on the shared GitHub slice harness
Drops the copied store and seed casts.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Grouping a GitHub Projects view by a NUMBER field sorted group headers as
text (1, 10, 2, 8). Number values now carry their value as the group order
hint and the NUMBER comparator sorts by it, falling back to label. Stale
non-number values use the finite unknown-option sentinel so mismatched
single-select/iteration comparators stay consistent.
Fixes#19395
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
PR close/reopen/merge confirmation titles were built from a fragment
template ("{{value0}} PR #{{value1}}?"), so locales could not reorder the
verb, and merge method labels came from English-only shared constants.
Add whole-sentence title keys per action and merge method plus translated
merge method labels in a renderer copy module, and route every PR surface
(item dialog, PR page, Tasks MergeCell, right-sidebar HostedReviewActions)
through it. Drop the English labels from the shared merge-method
presentation and remove the dead fragment keys from all locales.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* chore(lint): remove disable directives that suppress nothing
Each was reported unused by the oxlint config that owns its rule (root,
casting, react-doctor, anti-slop, native-plugins), including 17 file-level
react-doctor blanket disables whose rule no longer fires. An unused
react-hooks disable was masking a react/purity finding in
useAgentBucketCounts (compiler rules skip functions with hook
suppressions); suppress that one explicitly where the code explains it.
* test(tab-bar): use typed tab/file fixtures instead of @ts-expect-error partials
* chore(lint): fix misc suppressed lint violations instead of disabling
- consistent-type-imports: the "vi.importActual requires inline import()"
rationale was wrong; use typed vi.mock(import(...), importOriginal) or a
type-only namespace import.
- no-control-regex: source-control commit/push failure summaries, shell PATH
hydration, and ipynb ANSI parsing reuse the shared ansi-escape-sequences
stripper and control-character pattern instead of private copies.
- no-explicit-any / no-useless-spread / no-this-alias: typed `this` in
bridge test mocks, drop blanket file-level disables, drop a this-alias.
* refactor(main): replace avoidable type assertions with checked narrowing
17 production cast suppressions in main/wsl-guest removed: untrusted IPC
and RPC payloads (Jira issue update, WSL guest plugin install, handshake
type) now narrow through isRecord/type guards and build typed results;
redundant casts dropped; hand-rolled object checks and errno casts use the
existing isRecord / hasErrorCode helpers.
* refactor(renderer,mobile): replace avoidable type assertions with checked types
13 production cast suppressions removed: RPC failures read through the
`ok` discriminant instead of casting to RpcFailure; react-native-web host
refs narrowed with instanceof HTMLElement; redundant reply/diff casts
become checked annotations; the TUI agent param uses z.custom(isTuiAgent)
like its sibling schemas; the agent-status slice cast that hid missing
actions is gone so the creator's return type checks the whole slice.
* chore(lint): drop dead tiptap wrapper; scope anti-slop mocking rule to test support
- safe-react-node-view-renderer patched handleSelectionUpdate, which
@tiptap/react 3.31.3 no longer has, so it always returned early. Use the
stock ReactNodeViewRenderer.
- The anti-slop test override only matched *.test.{ts,tsx}, forcing
file-level no-module-mocking disables in test harnesses and fixtures.
Match *-test-harness, *-test-fixture(s), .test-fixture and *.test.mjs,
then drop those disables and the now-redundant per-file exemptions.
* test: replace repeated cast suppressions with typed fixtures (main/shared/e2e)
Net -119 cast directives. Typed fixtures replace recurring casts:
unusedSshConnection/unusedOrcadHostTransport placeholders, a typed
readPersistedState harness read (exposed a test treating optional
httpProxyUrl as always set), real Response objects in fetch spies, an
updater main-window fixture, a CDP webContents adapter, one shared
releaseModuleExport for cross-version tests, and requireOverlayDir in
place of `as string` on possibly-undefined overlay paths.
* fix(runtime): validate loaded device rows and host scope instead of casting
Two cast suppressions claimed checks that did not happen:
- device-registry-file-read: "normalizeLoadedDeviceRow re-validates every
field" was false; deviceId, token, name and timestamps were never
checked. Rows without an identity are now dropped and the file is set
aside through the existing corrupt-file path (registry reads as
doubtful, so no revocation verdicts); a non-string token is stripped
so the row stays listed but cannot authenticate.
- client-ui: "only optionality differs" was false; any string reached
persisted workspaceHostScope. Narrow it with isWorkspaceHostScope and
ignore unknown scopes (wire schema unchanged for mixed versions). The
remaining cast now states what it actually covers.
* test(runtime,ipc): drop redundant cast suppressions; typed runtime store fixture
-98 cast directives across runtime/ipc tests: 61 casts that typecheck
without the assertion; a typed vi.fn for scoped invalidation; a
partialRuntimeStore fixture in place of `store as never` for
OrcaRuntimeService; typed worker terminal/authority builders in the
incarnation-fallback suite (the old stub lacked runtimeId, ptyId,
worktreeId and launchTokenHash) plus removal of stacked duplicate
directives there.
* chore(lint): typed vi.mock imports and explicit listener snapshot in shared-bucket tests
Remaining files from the misc-rule pass that overlapped other buckets:
codex-accounts mocks use the typed vi.mock(import(...)) form instead of
a consistent-type-imports disable; the daemon late-exit fixture copies
its listener set with Array.from instead of a no-useless-spread disable.
* refactor(github,mobile): narrow routing settings type; drop remaining avoidable casts
- work-item-routing cast a one-field object to AppState['settings'] under
a claim that readers only consume activeRuntimeEnvironmentId. Return the
existing RuntimeFocusSettings pick instead and narrow the cache-key
chain's parameters, so the compiler enforces that claim.
- mobile file preview reads refusals through the RpcResponse `ok`
discriminant rather than a cast.
- terminal document host-notify accepts `unknown` errors, removing the
message-bridge cast.
- native chat readability drops a redundant repo-list cast.
* test(renderer): replace repeated cast suppressions with typed fixtures
-140 cast directives (and ~150 unsuppressed casts of the same shapes):
- mockPanePtyArgs owns the connectPanePty fixture casts, so a wrong
argument order or fixture is now a type error; drop binding casts for
members PanePtyBinding already declares.
- Seed AppState tab rows with the typed makeTerminalTab; this exposed a
split direction 'row' that is not a TerminalPaneSplitDirection.
- Partial GlobalSettings use getDefaultSettings overrides; Jira-only
stores use createTestStore; runtime environment rows/statuses come from
a typed paired-runtime-environment fixture.
* chore(lint): drop no-module-mocking disable now covered by the test-fixture glob
* test(e2e): fix all 221 grandfathered e2e type errors; baseline to zero
The e2e typecheck baseline grandfathered 221 errors in 119 files. About a
third were tests drifted from the current API, several of which would
fail or mislead at runtime:
- terminal-shortcuts called a nonexistent xterm buffer method;
- the daemon-lifecycle fake lacked terminateOwnedTree, hidden by importing
its type from a module that does not export it;
- arguments in the wrong position (listProcesses(hostId, opts), a dropped
pty.write inputKind, an extra toWebTerminalSurfaceTabId argument);
- removed enum values ('drawer', 'idle', 'editor',
'session-insecure-origin') and a launch_source the telemetry schema
rejects;
- missing required fields (turnScope, childWorkOpen, providerIdentity,
reviewLookupOutcome, runtimeServiceAccount behind an `as RelayConfig`);
- dead reads (tab.customTitle, bucket.targets, changedPixels).
Also lifts variables that narrowed to `never` after poll-callback
assignment, and adds a typed xterm render-dimensions accessor. Includes
the cross-version suites' shared releaseModuleExport adoption.
* chore(typecheck): gate the now-clean e2e typecheck in local lint
The e2e baseline is empty, so the ratchet now rejects any tests/ type
error. CI already runs it via run-ratchets; add it to pnpm lint's
explicit ratchet list and replace the stale 'not yet clean' note.
* test(mobile): typecheck every mobile test; baseline 105 files -> 0
mobile/tests-typecheck-baseline.txt grandfathered 105 test files (531
errors) whose types CI never checked. Contract changes had landed without
these tests following, and type pins in them silently checked nothing.
- Root cause: salvagedOptional (src/shared/zod-salvage.ts) cast away
zod's optional marker, so every reply type built on it claimed
salvaged fields were always present. Return a real ZodOptional;
runtime is unchanged (the outer optional short-circuits undefined).
- Production now takes the port it uses: RpcOperationSender instead of
RpcClient for send-only callers, a narrow fetch signature, and only the
request fields push-receive reads.
- findAllByHostType/findByHostType replace `'Text' as never` lookups;
stubRpcClient gives tests a typed RpcClient.
- Real test bugs: settings-host-client-lifecycle "relay" hosts were
direct hosts (relayHostId no longer exists); two toEqualTypeOf pins
could never hold; a recovery hook ran with an undefined scope key;
a create-PR test cast to a never-imported type; "no URL" assertions
passed on null; plus stale required props, args and enum values.
* test(e2e): parse workerStart result instead of casting it
* test(runtime): typed partial runtime stores with production-shaped fixture data
Route every partial store passed to OrcaRuntimeService through
partialRuntimeStore with typed row builders, removing 60 cast directives
that hid fixture data production never produces:
- paired-client-navigation-test-harness keyed setWorktreeMeta writes by
`[object Object]` (it took an id where the store takes a target), so
reads never saw them;
- invalid worktree lineage origin/capture and incomplete workspace lineage;
- getWorkspaceSession returning null where the store returns the default
session; getGitHubCache returning undefined;
- orcad migration states missing migrationId/manifest/receipt, with a
toEqual pinned to that incomplete shape;
- partial repos, metadata, folders, project groups and notification rows.
* refactor(renderer): resolve suppressed React hook lint instead of disabling it
109 of 187 react-hooks/react-doctor suppressions fixed:
- ~95 exhaustive-deps disables only hid stable refs and setters passed
through controller objects; list them (identity never changes, so
nothing re-runs), plus a few real stale closures (tabId/worktreeId).
- Effects keyed on one value that read the latest props now use
useEffectEvent (WebConnect, skill freshness, Bitbucket dialog seeding,
Landing preflight, automation catalog, structured-session recovery,
file explorer).
- The conditional layout-owner hook is selected once at module load from
the build constant instead of a rules-of-hooks disable that also hid
the whole controller from compiler and react-doctor rules.
- A hook disable was masking a react/purity Date.now() in the palette's
recent-tabs memo; sample it when the snapshot is captured.
- Three identical debounced-search effects share
useTaskSearchDebouncedApply; layout snapshot merge helpers move out to
stay under max-lines.
Remaining suppressions are mount-once resources, invalidation epochs,
deliberately keyed fields, and test harnesses that mock the dispatcher.
* chore(ratchet): exempt test harnesses and fixtures from the focus-read ratchet
The ratchet skipped *.test-fixture.ts but scanned *-test-harness,
*-test-fixture(s) and *.test-support files. Those seed settings with
getDefaultSettings (which the ratchet discovers as a focus reader) and
never route host work, so 17 baseline entries were false positives, and
replacing a test's `settings: {...} as never` with typed defaults tripped
it. Match the repo's test-support names and prune (which also drops one
stale entry), and rename the frame-ordering harness to *-test-harness like
its siblings. A blanket "-harness" match would also exempt
e2e-terminal-pty-harness, which production imports, so the names stay
explicit.
* test: merge duplicate shared/constants imports
* revert(file-explorer): restore original tree load effects pending SSH e2e investigation
* test(runtime): drop RuntimeStore cast now that the fixture is typed
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(github): repo cache eviction drops every host scope's entries, keeping a twin's own
Eviction and issue-source changes matched only unscoped key prefixes, so
SSH-, runtime- and source-scoped entries survived repo removal. Keys are now
composed by one builder and read back by its inverse, so eviction classifies
each key by host and keeps only a surviving same-id twin's bucket. Hosted
review (GitLab MR) entries are evicted too.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(github): read task-source scopes with empty parts back whole
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(github): an issue-source change evicts only the changed twin's buckets
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(github): a twin project's PR cards, rows and dialogs act on the host that returned the item
* fix(github): key twin rows by host so cache sync keeps each copy; a lone row ignores the stamp
* feat(sidebar): main produces per-workspace PR facts, checked against the window in dev and test
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor(sidebar): share the PR cache key candidates instead of splitting an import
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>