Unify file preview and download behavior - #3
Open
jonolee-kr wants to merge 19 commits into
Open
Conversation
## Human comments ## What was wrong Native Claude `Skill` calls used the generic plugin Puzzle glyph instead of bb’s established skill glyph. ## What changed Maps native Claude `Skill` calls to the Zap glyph and adds focused provider and story coverage. ### Before — parent `main` at `93643a53` Native Claude Skill calls use the generic Puzzle glyph.  ### After — PR head `d8a06e53` The same row uses the established Zap skill glyph.  ## How you verified - Exact parent/head Ladle states rendered in Chrome for Testing 149.0.7827.55. - The focused provider presentation test and app story coverage pass in remote CI. - All required CI checks are green. ## Fixes No linked GitHub issue; addresses the reported icon regression. BB-Thread-ID: thr_fdabesxhdr > AGENT GENERATED
## Human comments ## What was wrong Muted project, environment, and model controls changed foreground treatment on hover, creating a subtle visual jump in the composer metadata row. ## What changed Keeps the muted foreground token stable across hover while preserving the existing interactive background treatment. ### Before hover The composer metadata row is settled in its resting geometry.  ### After hover Hovering the model control preserves the row geometry while exposing its normal interactive treatment.  ## How you verified - Chrome for Testing 149.0.7827.55 exercised project, environment, and model controls in the real composer. - Element bounds remained unchanged across rest and hover; only the intended interactive background changed. - All required CI checks are green. ## Fixes No linked GitHub issue; addresses the reported hover regression. BB-Thread-ID: thr_fdabesxhdr > AGENT GENERATED
## Human comments ## What was wrong The worktree action tooltip said “Create new thread in this worktree,” which was longer than needed and inconsistent across the composer and metadata panel. ## What changed Uses “Create thread in worktree” for the tooltip and accessible label in both surfaces. ### Before — parent head `a1b2d5c8`  ### After — PR head `738b5606`  ## How you verified - The same isolated worktree thread and 1440×900 viewport were rendered against the exact parent and PR head in Chrome for Testing 149.0.7827.55. - The composer action exposed the expected visible tooltip and matching accessible label on each revision. - All required CI checks are green. ## Fixes No linked GitHub issue; addresses the reported tooltip copy regression. BB-Thread-ID: thr_fdabesxhdr > AGENT GENERATED
## Human comments ## What was wrong The composer reduced an unnamed worktree to the generic “Worktree” label, so users could see the checkout but not which host owned the environment. Environment type was also implicit, worktree rename copy used the broader “environment” concept, and provisioning could be presented as a workspace type instead of a lifecycle state. ## What changed The environment summary now preserves environment identity and checkout metadata as separate dimensions: - Direct environments and unnamed worktrees show their host name; named worktrees show their custom name. - The branch remains separately visible with the branch icon and copies on click, even if it matches a custom worktree name. - The environment icon tooltip distinguishes Local worktree, Remote worktree, Local, and Remote. - Provisioning takes precedence, uses the active loading spinner, and keeps the lifecycle label “Provisioning.” - Worktree actions and the rename dialog use worktree-specific language. A custom-named worktree shows its branch beneath the field, and “Clear custom name” restores the host as the environment identity. ### Composer identity **Before — the unnamed worktree is reduced to the generic “Worktree” label.**  **After — the host identifies the environment while the branch remains visible as checkout metadata.**  ### Rename flow **Before — generic environment terminology and no worktree context.**  **After — worktree-specific terminology for an unnamed worktree.**  **Custom-name state — the branch remains visible and clearing the custom name restores host identity.**  ## How you verified - Exact parent head `409ef81e9c36ef927e4af0a2bbff89c5001ed5c7` and exact PR head `78b589967f86c575066b2e8ef1d339c97f8c0b3e` were rendered in the branch web app with the same project, thread, environment, route, light theme, and 1440×900 viewport. - Chrome for Testing 150 exercised hard reload, host and branch rendering, worktree rename and clear, the Local worktree tooltip, and the Create thread in worktree tooltip. All passed with no runtime errors. - Remote CI covers the environment-state matrix, icon selection, branch presentation, rename copy, and component integration. ## Fixes No linked GitHub issue; addresses the reported environment-summary and worktree-naming regressions. BB-Thread-ID: thr_fdabesxhdr > AGENT GENERATED
## What was wrong The server's daemon-disconnect grace callback classified every unrecovered host/session socket loss as `host-daemon-restarted`, even when no replacement daemon instance had connected. That persisted reason flowed unchanged through the thread events API and timeline projection, so a transient tunnel/session failure rendered as “Stopped — host daemon restarted.” Confirmed restarts already have a separate stable signal: `handleHostSessionOpened` observes a changed daemon `instanceId`. ## What changed - Added the additive persisted interruption reason `host-connection-lost` and use it only when the daemon/session disconnect grace expires without a confirmed replacement instance. - Preserved `host-daemon-restarted` for the existing changed-`instanceId` restart path. - Added lifecycle failure copy and the timeline title “Stopped — connection to host was lost.” - Added regressions at the server lifecycle and thread-view parser boundaries proving lost connections and confirmed restarts remain distinguishable. - Refreshed the Plugin Guide's generated SDK public-API inventory for the additive declaration change. The inherited SDK version remains `0.4.25` and its release guard passes. - No host-daemon wire message changed, so `HOST_DAEMON_PROTOCOL_VERSION` is unchanged. There are no CLI changes. ## How you verified - Red proof on the parent behavior: the new server lifecycle assertion failed 1/11 because the disconnect-grace event was `host-daemon-restarted` instead of `host-connection-lost`. - Green proof on the child behavior: the focused server file passed 11/11 and the thread-view parser file passed 9/9, including distinct assertions for confirmed restart and lost connection. - Regenerated the exhaustive declaration inventory with `pnpm exec turbo run update:sdk-inventory --filter=@bb/plugin-api-map`; only the two declaration hashes affected by the additive reason changed. - Exact rebased head `38bec6236a6b58ca75542bb3e5cff98182cd3b71` passes every required GitHub check, including app, server, packages, integration, Linux package smoke, and macOS package smoke. - Chrome for Testing 152.0.7977.64 rendered the real branch web app at 1440×900 with the same deterministic thread fixture. The untouched parent rendered two restart rows; the exact child rendered one confirmed restart and one lost connection, with no runtime exceptions. Safari is not required for this non-marketing bb UI change. ### Before — untouched PR get-bb#2472 head `93d1dca06ab44ae8365a60cd33d996e97d834a8d` Both the confirmed restart and unconfirmed disconnect render as a daemon restart.  ### After — child head `38bec6236a6b58ca75542bb3e5cff98182cd3b71` The confirmed restart remains unchanged; the unconfirmed disconnect is labeled as a lost host connection.  BB-Thread-ID: thr_sjdd7gudiq > AGENT GENERATED
## What was wrong Secondary follow-up composer affordances used three different foreground tiers: the plus action inherited the primary foreground, the model caret used the muted foreground, and the collapse caret used the subtle foreground. That inconsistency gave low-priority chrome more visual weight than its function warranted. ## What changed - Moves the composer collapse caret and plus action to the established shared subtle chrome-button treatment. - Moves the model-picker caret to the same `text-subtle-foreground/75` tier only in its muted composer presentation; non-composer styling is unchanged. - Preserves hover, focus, menu, collapse, and responsive behavior. - Adds focused regression assertions for all three foreground treatments and a focused Ladle state. - No daemon wire, SDK, API, CLI, or persisted contract changes. ## How you verified - Red proof on the parent behavior: computed light-theme colors resolved to three different tiers—`foreground` for plus, `muted-foreground` for the model caret, and `subtle-foreground` for collapse. - Green proof on the child behavior: the focused class assertions pass with all three resolving to `subtle-foreground/75`; the relevant app test files passed 144/144. - Exact rebased head `699352c7e7576ee937d68d3e9f43f02f570aecfd` passes every required GitHub check, including all app shards, packages, server, integration, and Linux/macOS package smoke. - Chrome for Testing 152.0.7977.64 rendered the same `Stacked cards with pills` fixture at 1440×900 on exact parent and child heads. The deliberate interaction pass covered plus-menu, model-menu, collapse, focus re-expansion, light/dark rendering, responsive widths, and runtime exceptions. The later rebase changed only ancestor SDK inventory metadata, not this layer's app tree. Safari is not required for this non-marketing bb UI change. ### Before — parent head `38bec6236a6b58ca75542bb3e5cff98182cd3b71` The plus action, model caret, and collapse caret use stronger, inconsistent foreground tiers.  ### After — child head `699352c7e7576ee937d68d3e9f43f02f570aecfd` All three affordances use the same lower-emphasis chrome tier while model text and primary actions retain their hierarchy.  BB-Thread-ID: thr_sjdd7gudiq > AGENT GENERATED
## What was wrong The follow-up composer story catalog defaulted every row without an explicit environment fixture to the same local-direct summary, so most functional states repeated one environment treatment. The environment matrix also omitted unmanaged, named, and detached worktree shapes, and its detached fixture lacked the machine label needed to render the worktree icon. ## What changed - Rotates the functional overview through a balanced mix of local/remote and direct/worktree summaries. - Expands `Environment matrix` with unmanaged, named, and detached worktree rows. - Supplies the detached fixture's machine label so the production `FolderGit` environment icon renders. - Keeps provisioning on bb’s active-work `Loading03` indicator because discovery has not confirmed the eventual workspace type. - Changes only Ladle fixtures; there are no product, daemon-wire, SDK, API, CLI, or persistence changes. ## How you verified - Exact rebased head `f4707e0ad2ea6622fa4c314e943c6735a1d21f34` passes every required GitHub check, including all app shards, packages, server, integration, and Linux/macOS package smoke. - Ladle metadata registers both the native-skill-call and environment-matrix stories; neither renders a missing-story state. - Chrome for Testing 152.0.7977.64 rendered the exact parent and child matrix at the same 1440×900 viewport and scroll position. The child visibly adds unmanaged, named, and detached worktree rows with the production worktree icon; provisioning uses bb’s active-work `Loading03` indicator. The deliberate QA pass also verified all environment accessible labels, a balanced overview mix, no horizontal overflow, and no runtime exceptions. - Safari is not required for this non-marketing Ladle change. ### Before — parent head `699352c7e7576ee937d68d3e9f43f02f570aecfd` The matrix ends after managed local/remote worktrees.  ### After — child head `f4707e0ad2ea6622fa4c314e943c6735a1d21f34` The same fixture now exposes unmanaged, named, and detached worktree label/icon shapes.  BB-Thread-ID: thr_sjdd7gudiq > AGENT GENERATED
## What was wrong The three right-edge disclosure controls in the follow-up composer stack did not share a horizontal geometry contract. The branch and queued-message controls centered their 16px chevrons in a 24px edge column, while the composer collapse control used a 32px icon button against the same right edge. That put the composer caret four pixels left of the carets above it. ## What changed - Adds one shared 24px horizontal edge-caret class for the follow-up prompt stack. - Applies it to the branch banner, queued-message header, and wide composer collapse control while preserving their existing vertical hit targets. - Adds a regression assertion at the stable composer behavior boundary so the collapse control cannot drift back to a wider horizontal box. - No wire, persistence, SDK, CLI, or daemon protocol behavior changed. ## How you verified - Red proof: with the production composer class absent, the new assertion fails because the collapse control does not contain `w-6`. - Green proof: the focused composer assertion passes, and neighboring queued-message coverage passes 36/36. - Exact rebased head `400f7c6674cbeb5a1df9c2f331f97b020865c3ba` passes every required GitHub check, including all app shards, packages, server, integration, and Linux/macOS package smoke. - Chrome for Testing 152.0.7977.64 rendered the same `Stacked cards with pills` fixture at 1440×900 on exact parent and child heads. On the child, branch, queue, and composer caret centers all measured x=1019; the deliberate real-app pass also covered expanded/collapsed behavior, plus/model menus, focus re-expansion, responsive overflow, and runtime exceptions. The later rebase changed only ancestor SDK inventory metadata, not this layer's app tree. Safari is not required for this non-marketing bb UI change. ### Before — parent head `f4707e0ad2ea6622fa4c314e943c6735a1d21f34` The composer caret sits four pixels left of the banner and queue carets.  ### After — child head `400f7c6674cbeb5a1df9c2f331f97b020865c3ba` All three carets share the same horizontal center.  BB-Thread-ID: thr_sjdd7gudiq > AGENT GENERATED
## Human comments ## What was wrong The prompt-box footer applied semantic warning and hover colors to secondary affordances. Full Access correctly made the permission label amber, but it also made the dropdown caret amber; hovering Create thread in worktree promoted its icon to foreground. Both controls therefore stood out from the prompt box's other neutral affordances. ## What changed - Moves the permission caret to the prompt box’s `text-subtle-foreground/75` chrome tier while the selected permission label retains its warning tone. - Moves the Create thread in worktree icon to the same low-emphasis chrome tier, with the established muted hover treatment. - Uses normal weight for the model selector so its long label and provider mark do not dominate the composer. - Aligns the top-right collapse caret exactly with the permission caret while preserving its hit target. - Expands the existing Control emphasis story to show Full Access and the worktree-create action together. - Adds focused regression assertions for the color, weight, and caret-alignment contracts. - No wire, persistence, SDK, CLI, or daemon protocol behavior changed. ## How you verified - Chrome for Testing 149.0.7827.55 rendered matched DPR 2 crops of the same Control emphasis fixture at 1440×900. Per product review, the Before image combines the target controls’ parent behavior (`68a9aa715db41ede83ae66ccf72cf385aabab28c`) with main’s plus/model/composer-caret styling (`ec8f4ef04105c2cb5a59f7a9a9328bf2b16b39ce`); After is the exact child head `cb254b273da66575afcc307fefd466602650f02d`. - Before: the permission label and caret both resolved to the amber warning color; the worktree-create icon sat at the stronger muted tier. - After: the permission label remains amber, while the permission caret, worktree-create icon, model caret, composer caret, and plus icon all resolve to the exact same `text-subtle-foreground/75` color in light and dark themes. - The same neutral equality was checked in dark theme. On the final light-theme capture, the model selector resolves to weight 400; the collapse and permission carets both render at 16px with center x=894 and the same color. Local CI-equivalent checks were not run per repository policy; GitHub CI owns test and typecheck execution. ### Before — main styling for the other prompt-box controls The plus, model caret, and composer caret use their main styling; the permission caret remains amber and the worktree-create icon remains darker.  ### After — child head `cb254b273da66575afcc307fefd466602650f02d` The warning remains on the Full Access label; the model returns to normal weight, and the two right-edge carets align exactly.  BB-Thread-ID: thr_fdabesxhdr > AGENT GENERATED
## Human comments ## What was wrong The queued-message stack used the internal state label “Queued” as its visible heading and throughout its accessible names. That made the surface sound implementation-led, gave secondary chrome too much visual weight, and left sighted and assistive-technology terminology inconsistent once the heading changed. ## What changed - Rename the visible stack heading to “Follow-ups,” use normal weight, and apply the subtle foreground token so it reads as tertiary chrome. - Use follow-up terminology consistently across the section label, expand/collapse and drag controls, row actions, action menu, and inline editor. - Update focused component and thread-detail assertions for the new accessible names. - Keep internal queued-message APIs, types, and persisted contracts unchanged. ## How you verified - `git diff --check` - Chrome for Testing 151: final Ladle Overview at 1440×1000 in light and dark themes, with desktop and 320px mobile fixtures rendered together; label/count hierarchy, truncation, and layout remained stable. - Chrome for Testing 151: matching queued-item fixture captured from 1440×1000 branch web apps, cropped to the identical 728×86 component region on merge base `8d926c312` and PR head `d3757a814`. - Local CI-equivalent tests were not run per repository policy; focused assertions were updated for remote CI. - Remote CI passed across checks, app, integration, server, package, and macOS/Linux package-smoke jobs. ### Before — merge base  ### After — PR head  BB-Thread-ID: thr_yyjgejjc8w > AGENT GENERATED
## Human comments ## What was wrong The secondary panel had no command or state for restoring a closed tab, and the desktop-only `Cmd+Shift+T` binding was assigned to opening a terminal instead of the platform-standard reopen gesture. The first implementation also treated incomplete storage inventories as authoritative, rebuilt restored tabs from canonical rather than visible placement, and left browser `WebContentsView`s visible while the host renderer reloaded. ## What changed - Added the `panel.reopenClosedTab` app command, a desktop default of `Cmd+Shift+T`, and a matching native File menu item. - Added a 25-entry LIFO history for closed file, browser, and plugin-panel tabs. Reopened tabs become active; launchers, fixed tabs, and destroyed terminal sessions are excluded. - Keyed history by one canonical panel-context identity—panel state, environment, project, project host, and file-owner thread—so each context has an independent stack. Ownership is enforced when recording; restoration only pops the current stack and validates resource liveness. - Preserved storage-inventory readiness and truncation. Restoration waits for an authoritative inventory, performs targeted existence checks when the inventory is truncated, skips deleted or foreign-owner entries, and continues to the next valid entry. - Preserved each tab's visible split-panel placement when it is temporarily removed and restored, independent of canonical fixed-panel ordering. - Hid browser `WebContentsView`s before native or keyboard renderer reloads so stale child views cannot cover or intercept the replacement renderer; the fresh renderer reattaches and shows them after startup. - Kept terminal opening on its existing cross-platform `Cmd+Shift+Enter` binding and documented the shared panel command for plugin surfaces. - Added focused regressions for history ordering and exclusions, environment/project/project-host/file-owner isolation, storage readiness and truncation, deleted and beyond-page storage files, visible tab placement, default bindings, native accelerators, the menu action, and desktop reload preparation. - Refreshed the tracked public SDK inventory for the additive command-ID value. No host-daemon wire contract changed, so `HOST_DAEMON_PROTOCOL_VERSION` is unchanged. ### Before The merge base has no reopen-closed-tab command. <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/before-shortcut.svg" alt="Before: keyboard settings return no result for Reopen closed" width="720"> Native View → Reload with an open browser view could leave the host renderer blank. <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/e761bc2677083cd9d721e2a22d1a94422755e644/final-07-reload-blank-renderer.svg" alt="Before: blank renderer after native reload" width="720"> ### After The exact PR branch exposes the desktop shortcut as `Cmd+Shift+T`. <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/after-shortcut.svg" alt="After: keyboard settings show Reopen closed panel tab with Shift Command T" width="720"> Native View → Reload restores both the host renderer and embedded browser view. <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/e72383943d487e6c5bed2602e01b9e3f9f18553b/final-08-reload-restored.svg" alt="After: host renderer and browser view restored after native reload" width="720"> ## Exact-head desktop smoke evidence Two browser tabs open: <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/9f8f80cdab49f13a92b4508908ebe13dd0c1a0ad/final-01-open-tabs.svg" alt="Two browser tabs open" width="720"> Both browser tabs closed: <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/7763cbb60bb8ba498fb8441954ed01ae35d03601/final-02-closed.svg" alt="Both browser tabs closed" width="720"> First `Cmd+Shift+T` restores the most recently closed tab and its URL: <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/af895d88d32caf9ed16e1d16506f1648c770dabb/final-04-first-restore.svg" alt="First tab restoration" width="720"> Second `Cmd+Shift+T` restores the remaining tab: <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/cd423f696d8cb99c59ffbff18a06d187416dcc36/final-05-second-restore.svg" alt="Second tab restoration" width="720"> A third `Cmd+Shift+T` is a no-op, and the original visible order remains `Browser · Example Domain`: <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/76f9b4343c3b3c6c7e616dbd2cd99322c25f561c/final-09-restored-order.svg" alt="Restored tabs retain their original visible order" width="720"> A normally provisioned, environment-backed thread also restores a real file from the current worktree. After closing `README.md`, the literal `Cmd+Shift+T` gesture restores the active tab with its rendered repository content—not a skeleton: <img src="https://gist.githubusercontent.com/brsbl/b680331f494f59963e1c1f0918f12cb8/raw/7301c7f3ff63eb33f8ec3a80ccbdc3cef4d4d4a2/real-environment-readme-restored.jpg" alt="README restored with rendered current-worktree content in an environment-backed desktop thread" width="720"> ## How you verified - Exact candidate: `e82f32cb5d961299d69be7f2f1bfde80b49a1270` in the branch desktop app, Electron 41.7.0. - **Pass:** opened two browser tabs, closed both, and pressed the real `Cmd+Shift+T` gesture twice. The tabs returned in reverse close order, the URL was retained, the original visible placement was restored, and a third press was a no-op. - **Pass:** opened the exact Electron app's native File menu and confirmed its accessibility tree exposes **Reopen Closed Tab**. The OS-level menu capture was discarded because an unrelated system prompt contaminated the frame; accessibility evidence is used instead of presenting misleading visual evidence. - **Pass:** invoked native View → Reload with a live browser view. The replacement host renderer loaded, the child browser view reattached, and both remained interactive after settling. - **Pass:** regression coverage switches across environments and also distinguishes project, project host, panel state, and file-owner thread before restoring only the nearest entry owned by the active context. - **Pass:** storage regressions cover unresolved inventories, truncated inventories, valid paths beyond the first page, deleted files, foreign owners, and open storage tabs that must not be pruned from an incomplete inventory. - **Pass:** provisioned a fresh thread through the official CLI against the branch dev server, confirmed its environment resolves to the exact current worktree, opened `README.md` through real file search, closed the tab, and pressed the literal `Cmd+Shift+T` gesture. The tab returned active with fully rendered file content and no persistent skeleton or 409 response. - Reviewed every retained screenshot for clipping, layout shift, stale frames, and incorrect tab state. No visual defect remains in the captured flows. - Per repository policy, tests, typechecks, and lint were not run locally. Pull-request CI is fully green: checks, app/server/package/integration tests, Linux/macOS package smoke, and version checks all passed. ## Final review and triage One deliberate architecture and implementation review was run for this PR. Its findings were validated, then all confirmed product defects from the review and smoke pass were fixed: - **P1 — fixed:** native desktop reload could leave a live browser child view covering and intercepting the replacement host renderer. - **P1 — fixed:** closed-tab history could cross environment/checkout boundaries without using the complete panel, environment, project, project-host, and file-owner identity. - **P2 — fixed:** unresolved or truncated storage inventories could transiently restore a deleted file or permanently discard a valid entry beyond the inventory page. - **P2 — fixed:** the second restored tab could be appended instead of returning to its original visible split-panel placement. - **P2 — fixed:** deleted or foreign-owner thread-storage entries are skipped while restoration continues to the next valid history entry. No known product defect remains from the review, smoke test, or screenshot inspection. The earlier convenience fixture that populated nine tabs bypassed normal provisioning and produced an environment-less thread. It was discarded and is not used as merge evidence; the final file-tab pass used the normally provisioned environment-backed thread shown above. One QA-infrastructure observation remains outside this feature: on a cold desktop-dev launch, the launcher's fixed readiness window can expire while branch packaging is still completing, producing a temporary blank window. Logs and the later automatic load established that this was service readiness timing rather than a renderer crash. BB-Thread-ID: thr_ufp89hj9ea > AGENT GENERATED
## Human comments ## What was wrong PR get-bb#2686 added `panel.reopenClosedTab` to the public Plugin SDK declaration while the package remained at `0.4.28`. That version is already published with different bundled types, so the post-merge npm version guard correctly failed on `main`. ## What changed Bumped `@get-bb/plugin-sdk` and the shared domain version constant together from `0.4.28` to `0.4.29`. No host-daemon wire contract changed. ## How you verified - Used the repository-provided `node scripts/bump-plugin-sdk.mjs --patch` command. - Per repository policy, CI-equivalent checks were not run locally; pull-request CI is the verification gate. Follow-up to get-bb#2686 BB-Thread-ID: thr_ufp89hj9ea > AGENT GENERATED
## Human comments ## What was wrong The Updates header explicitly positioned the Update all download glyph after its label, while the sidebar update badge only reflected provider-version status and never observed an active CLI install. The Updates story fixture also copied provider metadata without seeding the real logo assets, so installed-provider marks could render without their provider icon in Ladle. ## What changed - Keep the existing Update all control intact while using its standard icon-first order. - Subscribe the sidebar update badge to the existing install runner and replace its download glyph with the existing loading glyph only while an installed provider is actively downloading; restore the download glyph after success or failure. - Seed provider-logo assets in the existing Updates story fixture and add focused available/downloading sidebar stories. - Preserve the existing actions, styles, spacing, tooltips, and accessible names. ## How you verified - Chrome for Testing, exact branch web app: compared merge base `9c170fdbb` with head `56bafa392` using the same provider-status fixture, route, and 1440×900 viewport. - Confirmed the Update all glyph is first at 1440×900 and 767×900 and retains `aria-label="Update all 2 CLI tools"`. - Exercised Update all and the individual Codex update action. - During a controlled install failure, confirmed the sidebar shows the animated loading glyph with both Codex and Claude provider marks, then restores the download glyph after the install settles. - Remote CI: 13 required checks passed; 2 not-applicable checks skipped. ## Screenshots ### Update all icon order Before — merge base, 1440×900:  After — PR head, 1440×900:  After — PR head, 767×900:  ### Sidebar active install state Before — merge base during the controlled install, 1440×900:  After — PR head during the same controlled install, 1440×900:  After — PR head after the controlled failure settles, 1440×900:  BB-Thread-ID: thr_m57exaav4m > AGENT GENERATED
## Human comments None. ## What was wrong Thread action menus did not provide a reliable way to copy the current thread URL. The first implementation wired the URL only from the thread header, which allowed the header and sidebar `…` menus to drift. ## What changed - Adds **Copy thread link** to the shared thread-action item set used by the header, sidebar dropdown, desktop context menu, and compact long-press menu. - Derives the link from the active app origin and canonical project/thread route inside the shared menu, so every instance follows the current environment while excluding transient panel, split, and query state. - Adds focused coverage that the shared menu copies its canonical thread URL with success and failure feedback. ## Screenshots The comparison uses the same seeded thread, route, open-menu state, and 1440×1000 viewport, cropped identically to the header action area. The after evidence is from branch commit `8f0eef326`, which contains the final production code; final head `1b911180c` changes only the test interaction event. | Before — merge base `720b3163d` | After — final production code `8f0eef326` | | --- | --- | |  |  | Sidebar parity on the same production-code revision:  ## How you verified - Chrome for Testing 151.0.7922.71 against the branch web app at 1440×1000. - Hard reloaded the seeded thread, opened both header and sidebar `…` menus, copied from each, verified the exact clipboard URL, and observed success feedback. - Confirmed no console errors during the changed flow. - CI: all required build, typecheck, lint, app, server, integration, package, and packaging smoke checks pass on final head `1b911180c`. - `git diff --check origin/main...HEAD` - Local CI-equivalent checks were not run per repository policy; PR CI is the validation path. BB-Thread-ID: thr_dwsizgdy3q > AGENT GENERATED
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Validation
Scope limits
Physical Electron, installed native mobile, and physical mobile WebView testing were not performed.