Skip to content

fix(web): show Tux icon for WSL environments - #8511

Merged
shivamhwp merged 19 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/web-wsl-sidebar-icon
Sep 6, 2026
Merged

fix(web): show Tux icon for WSL environments#8511
shivamhwp merged 19 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/web-wsl-sidebar-icon

Conversation

@UtkarshUsername

@UtkarshUsername UtkarshUsername commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Added Linux as a first-class environment icon.
  • Reused the Linux penguin SVG from the marketing download page.
  • Added the icon to the shared components/Icons.tsx brand icon barrel.
  • Added “Linux/WSL” to the environment icon picker on the Connections page.
  • Automatically detects WSL servers from their Microsoft kernel identity.
  • Shows the Linux icon for WSL environments in:
    • Sidebar thread rows and tooltips
    • Legacy sidebar project badges
    • Composer environment selectors
    • Provider Settings environment tabs
    • Project Settings environment tabs
    • Connections environment icon controls
  • Preserved the existing Server, Cloud, Desktop, Laptop, and Mac icons.
  • Added the corresponding shared environment kind mapping for mobile clients.

Why

WSL runs locally alongside the Windows environment, but was previously represented using generic remote or desktop-local icons. WSL now identifies itself as Linux automatically, while other Linux environments can select the same “Linux/WSL” icon manually.

UI Changes

Before:
image
image
image
image
image

After:
image
image
image
image
image
image
image

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes

Verification: web typecheck, targeted lint, and exact SVG path comparison passed.

Implemented by GPT-5.6 via Codex.

Note

[!NOTE]

Show Linux icon for WSL environments across web UI

  • Adds isWslConnectionTarget predicate in desktopLocal.ts that classifies a desktop-local backend identifier as WSL when it starts with the WSL prefix
  • Adds LinuxIcon and updates getEnvironmentIcon in Icons.tsx with precedence: primary, then WSL, then remote, then cloud
  • Adds optional wsl prop to EnvironmentMachineIcon so it renders the Linux glyph when true, overriding the machine-kind mapping
  • Threads the WSL flag from connection targets through environment options in ChatView.tsx, Sidebar.tsx, LegacySidebar.tsx, the branch toolbar selectors, and the provider settings panel
  • Behavioral Change: sidebar project headers, thread rows, search results, tooltips, branch toolbar, and provider settings now render the Linux icon for WSL environments instead of the icon implied by machine kind

Macroscope summarized ec30f95.


Note

Low Risk
Presentation-only icon and labeling changes with a small connection-target helper and unit tests; no auth, data, or runtime behavior changes.

Overview
WSL backends were shown with the same icons as generic remote or desktop-local environments. This PR detects WSL via isWslConnectionTarget (wsl:* desktop backend IDs) and routes all environment icon rendering through shared getEnvironmentIcon (primary → monitor, WSL → new LinuxIcon, otherwise caller-specific remote icon).

isWsl is threaded through composer environment options (ChatView, EnvironmentOption), sidebar thread rows/tooltips/search, legacy project header badges (allRemoteMembersAreWsl on grouped projects), branch toolbar pickers, and provider settings tabs. Legacy sidebar remote-only badges swap ContainerIcon for the centralized helper (laptop vs cloud vs Tux) and vertically center the badge.

Reviewed by Cursor Bugbot for commit 8cb96c3. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6bd0a762-1c9d-418f-96da-c71dc4046a1e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 28, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI consistency review found icon-system inconsistencies introduced by this change. Details inline.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/LinuxIcon.tsx Outdated
Comment thread apps/web/src/components/Sidebar.tsx Outdated
Comment thread apps/web/src/components/BranchToolbarEnvironmentSelector.tsx Outdated
@UtkarshUsername
UtkarshUsername marked this pull request as ready for review August 28, 2026 08:29
@macroscopeapp

macroscopeapp Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This change updates automatic WSL detection and changes the default environment icon and label across web and mobile surfaces, in addition to adding a small backward-compatible contract value. Because the default presentation changes for existing WSL environments without an explicit user override, the product-default policy calls for human review.

Not approved because:

  • Monthly spending limit reached (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more.

@UtkarshUsername UtkarshUsername changed the title fix(web): show Linux icon for WSL environments fix(web): show Tux icon for WSL environments Aug 28, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One new finding on the latest commit (8f6ec6e). The two prior comments on Sidebar.tsx (row vs. SidebarThreadTooltip / SidebarSearchResultRow glyph divergence) and BranchToolbarEnvironmentSelector.tsx (icon mapping duplicated across three places) still apply and are not repeated here.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/LegacySidebar.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up on the icon-resolver refactor: the shared getEnvironmentIcon helper addresses the earlier duplication between the composer trigger and the select list. Two things from the open threads still stand, plus one small leftover noted inline.

  • apps/web/src/components/LegacySidebar.tsx (~2325-2343): the badge's accessible name (aria-label="Local sandbox project") and tooltip (Local sandbox: …) are unchanged and OS-neutral, while the glyph now asserts Linux; allRemoteMembersAreDesktopLocal derives from the local: connection-id prefix (connection/desktopLocal.ts), which carries no OS. Either the wording or the glyph should move so the label and the mark describe the same thing.
  • The same environment class is still drawn with three different marks: LinuxIcon here and in the composer/sidebar row, lucide LaptopIcon + "Local device" in settings/ProviderSettingsPanel.tsx (~157/165), and ServerIcon in Sidebar.tsx (~318) and CommandPalette.tsx (~1048). Routing the settings resolver through the new helper (or narrowing the helper's name to the surfaces it owns) would keep one mapping.

No new duplicate comments were posted for the already-open LinuxIcon.tsx and Sidebar.tsx threads.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/LegacySidebar.tsx Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d9f2b09. Configure here.

Comment thread apps/web/src/components/Sidebar.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the sidebar thread row's environment glyph now disagrees with its own details tooltip, and the non-WSL fallback silently changed from ServerIcon to CloudIcon for every remote thread. See the inline comment on apps/web/src/components/Sidebar.tsx.

Context (not blocking, no action required in this PR): getEnvironmentIcon is now the shared owner of the primary / desktop-local / cloud mapping, but apps/web/src/components/settings/ProviderSettingsPanel.tsx (~157/165) still resolves the same isDesktopLocalConnectionTarget state to LaptopIcon + "Local device", so the same environment class remains Tux in the sidebar/toolbar and a laptop in settings. Previously flagged points about the OS assertion and the LegacySidebar ternary/"Local sandbox" wording still stand and are not repeated here.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/Sidebar.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One new finding: the composer's mobile environment picker still hardcodes the old primary/cloud icon mapping, so the same WSL environment renders Tux on desktop and a cloud on mobile. Details inline.

Still open from the previous review: SidebarThreadTooltip (apps/web/src/components/Sidebar.tsx ~318) renders ServerIcon unconditionally, so a desktop-local thread row shows the Linux glyph while its own hover card — and SidebarSearchResultRow, which shares that tooltip — still shows a server glyph for that identical environment.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/BranchToolbar.logic.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two consistency findings on the shared environment-icon change, plus one earlier finding that is still open.

  • apps/web/src/components/BranchToolbar.logic.ts — the new isDesktopLocal option is not read by the mobile composer picker, so the same environment gets two glyphs depending on breakpoint.
  • apps/web/src/components/Icons.tsxgetEnvironmentIcon is a second, disagreeing resolver alongside providerEnvironmentIcon in Settings.

Still open from a previous review (not re-commented): SidebarThreadTooltip (Sidebar.tsx ~318) renders ServerIcon next to environmentLabel, so a desktop-local thread row now shows the Linux glyph while its own hover card and the search-result row describe that identical environment with a server glyph.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/Icons.tsx Outdated
Comment thread apps/web/src/components/BranchToolbar.logic.ts Outdated
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 28, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two places where this PR's narrowing from "desktop-local" to "WSL" splits one piece of state into two predicates, so the same environment can be described two different ways.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/LegacySidebar.tsx Outdated
Comment thread apps/web/src/components/settings/ProviderSettingsPanel.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI consistency review found two issues, both in scope for this check.

  • apps/web/src/components/Icons.tsx: the new shared LinuxIcon bakes a fixed p-0.5 inset, so the WSL glyph renders smaller than the lucide icons it replaces in the same slots, at a ratio that varies per call site.
  • apps/web/src/components/LegacySidebar.tsx: the reworded comment now describes header behavior that only holds for WSL projects after the badge switched to allRemoteMembersAreWsl, and the thread row still classifies on the broader desktop-local predicate.

Still open from an earlier round (not re-commented): MobileRunContextSelector in apps/web/src/components/BranchToolbar.tsx (lines ~107 and ~154) consumes the same availableEnvironments (now carrying isWsl) but keeps env.isPrimary ? MonitorIcon : CloudIcon, so the same WSL environment shows the Linux glyph on the desktop selector and a cloud glyph on the mobile one.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/Icons.tsx Outdated
Comment thread apps/web/src/components/LegacySidebar.tsx Outdated
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 28, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review August 28, 2026 10:25

Dismissing prior approval to re-evaluate 3d64750

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 28, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review September 5, 2026 18:52

Dismissing prior approval to re-evaluate 8c50438

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Sep 5, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review September 6, 2026 14:16

Dismissing prior approval to re-evaluate bf5cc13

@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Sep 6, 2026
@shivamhwp
shivamhwp merged commit 72cb638 into pingdotgg:main Sep 6, 2026
24 checks passed
@UtkarshUsername
UtkarshUsername deleted the fix/web-wsl-sidebar-icon branch September 6, 2026 16:11
patroza pushed a commit to patroza/t3code that referenced this pull request Sep 6, 2026
Fold pingdotgg#8511 onto the in-progress sync so fork/dev catches current
upstream/main, not only 223ff44.
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 6, 2026
## What's Changed
* fix(web): show Tux icon for WSL environments by @UtkarshUsername in pingdotgg/t3code#8511
* perf(web): speed up folder menu sorting by @AksharP5 in pingdotgg/t3code#10190
* style(web): fix inconsistencies in new settings layouts by @extoci in pingdotgg/t3code#10177
* feat(threads): persist manual active thread order by @juliusmarminge in pingdotgg/t3code#9729
* feat(mobile): arrange active threads from both thread lists by @juliusmarminge in pingdotgg/t3code#9730
* feat(web): drag threads across sections with consistent motion by @juliusmarminge in pingdotgg/t3code#9731
* feat(web): simplify sidebar drag destination cues by @juliusmarminge in pingdotgg/t3code#9750
* fix(mobile): keep pending tasks queued when a send fails in flight by @juliusmarminge in pingdotgg/t3code#10245
* feat(mobile): show new-task drafts alongside pending tasks in the thread list by @juliusmarminge in pingdotgg/t3code#10260
* feat(mobile): allow several new-task drafts per project by @juliusmarminge in pingdotgg/t3code#10327
* fix(mobile): slide settled threads out before collapsing by @StiensWout in pingdotgg/t3code#10345


**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260906.1303...v0.0.39-nightly.20260906.1316

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260906.1316
BarretoDiego pushed a commit to BarretoDiego/t3code that referenced this pull request Sep 7, 2026
aorwall added a commit to aorwall/t3code that referenced this pull request Sep 7, 2026
Merges 141 upstream commits (`b438447f6..8b2838e`) into the fork,
following the
`fork-upstream-merge` skill. Landed as a merge commit; conflicts
resolved by the
path-policy verdicts in `docs/fork/inventory.json`.

## Merge shape

563 files landed (`git diff --stat HEAD^1 HEAD`) against 563 in the
upstream
range, so no upstream work was dropped. Fork delta 720 files.

## Conflicts

14 files, resolved by concern. The merge commit message names each. Two
are worth
carrying forward:

- Upstream extracted the project action rows into
`ProjectActionsList.tsx`. The
fork's Edit gate now rides an `editable` prop that defaults to
upstream's
  always-editable behavior, so the gate survives the next extraction.
- Upstream moved the `agent-browser-access` setting onto its new
`/settings/projects` page. `settingsSearch.ts` points that item there
and drops
  a fork delta.

## Two things a clean merge did not show

**Upstream can delete an export the fork still imports.** pingdotgg#10225 removed
`ClientTracingLive` as unused. `apps/web/src/lib/runtime.ts` still
installs it,
and neither file conflicted, so the typecheck failed four ways on a
merge git
called clean. Restored with a `// Fork:` comment naming the consumer.

**A green test step can hide a suite that never finished.** `vp run -r
test`
kills the packages still running when one of them fails. A
`@t3tools/desktop`
failure truncated `apps/web` and `@t3tools/mobile` after each had
reported
hundreds of passing files, and `verify.mjs` counted any package with
labeled
output as tested. Four failing web tests went unreported. The check now
keys on
the closing `Test Files` line and runs every unfinished package alone.

## Unsupported methods

`unsupported-methods.mjs` reports 0 ADD, 0 DROP, 2 KEEP, against 61
dispatched
backend methods and 131 contract methods.

Getting there took a fix. The backend moved its dispatch from
`crates/t3code/src/lib.rs` to `crates/t3code/src/rpc/dispatch.rs`, where
every
arm is a one-line call into a handler below the match. The script read
the old
path and reported zero dispatched methods, then read the new one and
called
`vcs.switchRef` a DROP, because the `unsupported_exit` that refuses it
had moved
out of the arm. It now tries both paths and follows an arm two calls
deep.

Contract changes: `provider.consumeResetCredit` and
`server.getHostResources`
gained `UnsupportedMethodError`; `server.getUsageSummary` lost it, which
closes
the item the previous merge left open.

## Feature classification

**Usable as-is** — client-only, nothing new on the wire. Sidebar drag
across
sections with destination cues and a named drop action (pingdotgg#9731, pingdotgg#9750,
pingdotgg#10378,
pingdotgg#10453, pingdotgg#10464). Composer behavior: a multiline draft survives timeline
scrolling (pingdotgg#10444), the composer stops collapsing on blur (pingdotgg#10437) and
regains
focus when you tab back (pingdotgg#10463). Panel and preview chrome: resize the
floating
preview from any edge (pingdotgg#10467), toolbar controls stay anchored (pingdotgg#10478),
the
stuck resize cursor clears (pingdotgg#10461), the browser hides as the right
panel closes
(pingdotgg#10385), manual panel choices hold during a turn (pingdotgg#10113). Settings and
accessibility polish (pingdotgg#10177, pingdotgg#10262, pingdotgg#10415, pingdotgg#10258, pingdotgg#10124, pingdotgg#10125,
pingdotgg#10127,
pingdotgg#10128, pingdotgg#10175). Performance (pingdotgg#10413, pingdotgg#10190, pingdotgg#10118). Plus the GitHub
mark on
`github.com` links (pingdotgg#10324), the Tux icon for WSL (pingdotgg#8511), a remembered
usage
page selection (pingdotgg#10189), project settings in the legacy sidebar menu
(pingdotgg#10021),
and text-only preview snapshots (pingdotgg#10232).

**Unsupported in Moatless** — resolves to a refusal, or falls through to
its own
empty state. Each is recorded in `docs/fork/gaps.md`:

- Reset credits through the hub and CLIProxyAPI (pingdotgg#10462, pingdotgg#10395,
pingdotgg#10308).
`provider.consumeResetCredit`, new union entry. `UsageLimits.tsx`
catches the
  refusal and shows "Could not use the reset credit."
- Balancing new threads across connected machines (pingdotgg#9895, pingdotgg#10433,
pingdotgg#10407).
`server.getHostResources`, new union entry. Nothing polls until a user
picks
automatic routing, and the composer then reads "Auto balance
unavailable."
- Onboarding: import grouped by repository (pingdotgg#10493), the shared
multi-computer
  wizard (pingdotgg#10465), agent install without Node or npm (pingdotgg#10402). All ride
  `agentSessions.scan` and `.import`, an existing gap.
- Shared project defaults and scoped overrides (pingdotgg#9754). The page reads,
and every
  write goes through `server.updateSettings`, which the backend does not
  dispatch.
- Two new `orchestration.dispatchCommand` types: `thread.active.reorder`
(pingdotgg#9729)
and `thread.user-input.dismiss` (pingdotgg#10431). Both are ordinary controls, a
sidebar
drag and a Dismiss button, and a dispatched command cannot be refused
per type.
That is the standing _A command cannot be refused_ gap, now 26 members
wide.

**Backend behavior to consider reproducing in Moatless** — upstream
server fixes
whose behavior the fork's client assumes:

- Invalid script IDs no longer crash threads (pingdotgg#10019). The fork ships
project
  scripts, so this one is worth reading first.
- Settlement: settle inactive threads without a PR lookup (pingdotgg#10103), skip
disabled
settlement lookups (pingdotgg#10424), settle threads with unanswered async
questions
  (pingdotgg#10400).
- Interrupted threads stay resumable after a restart (pingdotgg#10421).
- Completed requests stay closed across clients (pingdotgg#10123).
- Placeholder branches are followed after a checkout updates (pingdotgg#10441).
- A thread's PR links without an open client (pingdotgg#10101), and checkpoints
are
  captured before a PR status refresh (pingdotgg#10347).
- Adapters declare their own context compaction (pingdotgg#10112).
- Transcripts with oversized tool records import (pingdotgg#10430), and git
status scans
  are skipped while the index is locked (pingdotgg#9845).
- Usage limits pool per provider across accounts and environments
(pingdotgg#10300). The
client renders what `server.getUsageSummary` returns, so this shows
something
  only if the Moatless payload carries per-account limits.

Mobile, marketing, desktop, provider adapters and release tooling are
not this
fork's surface and are not classified.

## Also fixed here, and not upstream's doing

- Three `browser-*` search items still routed to
`/settings/integrations`, which
the fork owns for its Moatless administration page. A non-administrator
who
  searched for them was redirected away from the result.
- `moatless/listSearch.ts` carried no fork-only declaration.
- `pnpm fmt:check` failed on 294 files, 293 of them orval output. The
generator
  now formats what it writes through an `afterAllFilesWrite` hook.
- `@t3tools/moatless-api` exported `./generated`, a barrel that is never
checked
  in.

## Verification

`inventory-check.mjs` clean. `verify.mjs` green on seven checks:
duplicate-adds,
tripwires, resolution-check, unsupported-methods, `fmt:check` (3876
files),
`lint` and `typecheck`.

`test` is red on one package, and it is the machine.
`@t3tools/desktop`'s
`bundled libsecret helper` shells out to `pkg-config` for `libsecret-1`,
which
this sandbox does not have; it fails the same way when retried alone.
Everything
else passes: `apps/web` 369 files, `t3` 291, `@t3tools/mobile` 149,
`t3code-relay` 27, `@t3tools/client-runtime` 71, plus the smaller
packages.

`spec:check` cannot run in a sandbox: it needs a sibling `moatless`
checkout or a
deployment URL and has neither.

Written by Claude Opus 5 in Claude Code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
Moatless task:
https://moatless.soaplabstest.com/tasks/8d348ecf-f9cb-4e65-b96b-6c1054a8ed33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants