Skip to content

Unify file preview and download behavior - #3

Open
jonolee-kr wants to merge 19 commits into
mainfrom
bm-41-file-preview-download
Open

Unify file preview and download behavior#3
jonolee-kr wants to merge 19 commits into
mainfrom
bm-41-file-preview-download

Conversation

@jonolee-kr

Copy link
Copy Markdown
Owner

Summary

  • unify preview and download handling across chat, sidebar files, Tasks, desktop, and mobile shells
  • route project attachments through in-app previews and explicit downloads
  • resolve Markdown links, images, encoded paths, line targets, and inline-code file references consistently
  • apply safe inline MIME, disposition, sandbox, containment, and filename policies

Validation

  • GitHub CI passed on the reviewed head
  • 170 focused tests passed across 21 files
  • nine typechecks passed
  • six production builds passed
  • targeted mutation checks detected both intended regressions
  • isolated browser QA covered project files, Tasks attachments, file references, encoded paths, missing files, and unsupported files

Scope limits

Physical Electron, installed native mobile, and physical mobile WebView testing were not performed.

brsbl and others added 19 commits August 29, 2026 01:18
## 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.

![Before — native Skill call with Puzzle
icon](https://raw.githubusercontent.com/brsbl/bb/a8df5aae7c5fb670a9ba5b3e13c600650d1c7e74/2609-skill-before.png)

### After — PR head `d8a06e53`

The same row uses the established Zap skill glyph.

![After — native Skill call with Zap
icon](https://raw.githubusercontent.com/brsbl/bb/a8df5aae7c5fb670a9ba5b3e13c600650d1c7e74/2609-skill-after.png)

## 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.

![Before hover — settled composer
metadata](https://raw.githubusercontent.com/brsbl/bb/a8df5aae7c5fb670a9ba5b3e13c600650d1c7e74/2611-hover-before.png)

### After hover

Hovering the model control preserves the row geometry while exposing its
normal interactive treatment.

![After hover — stable composer metadata
geometry](https://raw.githubusercontent.com/brsbl/bb/a8df5aae7c5fb670a9ba5b3e13c600650d1c7e74/2611-hover-after.png)

## 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`

![Before — verbose worktree action
tooltip](https://raw.githubusercontent.com/brsbl/bb/a8df5aae7c5fb670a9ba5b3e13c600650d1c7e74/2612-tooltip-before.png)

### After — PR head `738b5606`

![After — concise worktree action
tooltip](https://raw.githubusercontent.com/brsbl/bb/a8df5aae7c5fb670a9ba5b3e13c600650d1c7e74/2612-tooltip-after.png)

## 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.**

![Before — generic Worktree environment
label](https://github.com/user-attachments/assets/224b176f-5e3d-4cad-9b11-b626b58f9f6c)

**After — the host identifies the environment while the branch remains
visible as checkout metadata.**

![After — host environment identity with separate branch
metadata](https://github.com/user-attachments/assets/90386fa6-c341-4bf8-acd9-342500fe1b4f)

### Rename flow

**Before — generic environment terminology and no worktree context.**

![Before — generic rename environment
dialog](https://github.com/user-attachments/assets/a927c09c-880d-4c6e-b8dd-3526f27df668)

**After — worktree-specific terminology for an unnamed worktree.**

![After — rename worktree
dialog](https://github.com/user-attachments/assets/bdd814b3-862b-40e8-a2e4-06fec2fce476)

**Custom-name state — the branch remains visible and clearing the custom
name restores host identity.**

![After — custom worktree name with branch context and Clear custom name
action](https://github.com/user-attachments/assets/36dd5510-9e3b-45d6-a911-06b47f3ddfee)

## 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.

![Before — both fixture rows say Stopped — host daemon
restarted](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/stop-before-93d-final.png)

### After — child head `38bec6236a6b58ca75542bb3e5cff98182cd3b71`

The confirmed restart remains unchanged; the unconfirmed disconnect is
labeled as a lost host connection.

![After — confirmed restart and lost host connection are
distinct](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/stop-after-38bec-final.png)

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.

![Before — composer controls at inconsistent foreground
tiers](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/controls-before-38bec-final.png)

### After — child head `699352c7e7576ee937d68d3e9f43f02f570aecfd`

All three affordances use the same lower-emphasis chrome tier while
model text and primary actions retain their hierarchy.

![After — composer controls share the lower-emphasis chrome
tier](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/controls-after-699352-final.png)

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.

![Before — environment matrix without unmanaged, named, or detached
worktrees](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/environment-before-699352-final.png)

### After — child head `f4707e0ad2ea6622fa4c314e943c6735a1d21f34`

The same fixture now exposes unmanaged, named, and detached worktree
label/icon shapes.

![After — expanded environment matrix with unmanaged, named, and
detached
worktrees](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/environment-after-f4707e-final.png)

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.

![Before — composer caret is left of the two carets above
it](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/carets-before-f4707e-final.png)

### After — child head `400f7c6674cbeb5a1df9c2f331f97b020865c3ba`

All three carets share the same horizontal center.

![After — composer, queue, and branch carets are
aligned](https://raw.githubusercontent.com/brsbl/bb/a236be40b18b147c043415ff93f70ece328baa78/carets-after-400f7c-final.png)

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.

![Before — mismatched prompt-box affordance
colors](https://raw.githubusercontent.com/brsbl/bb/26f9bfcf704b980867b455fd962d2e92ee2c3600/promptbox-control-colors-before-main-controls-retina.png)

### 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.

![After — balanced prompt-box control
hierarchy](https://raw.githubusercontent.com/get-bb/bb/6247139cf44b266f4f8c34b18e26596df6ef55ef/promptbox-control-colors-after-final-retina.png)

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

![Before: queued-message stack headed Queued at medium
weight](https://gist.githubusercontent.com/brsbl/8265fcd0d8d5f7d506788d9f9ecad876/raw/29b1727a6a39c95e09d5f0757bbb501d0cdbbb72/before.svg)

### After — PR head

![After: queued-message stack headed Follow-ups at normal weight with a
subtle
foreground](https://gist.githubusercontent.com/brsbl/8265fcd0d8d5f7d506788d9f9ecad876/raw/4cf9b8f04042aa3a681cc165b439d07fa48dd8e7/after.svg)

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:

![Before: Update all download icon follows the
label](https://img3.pixhost.cc/images/5324/763945924_before-update-all.webp)

After — PR head, 1440×900:

![After: Update all download icon precedes the
label](https://img3.pixhost.cc/images/5324/763945951_after-update-all.webp)

After — PR head, 767×900:

![After at narrow width: Update all keeps the icon-first
order](https://img3.pixhost.cc/images/5324/763945954_after-update-all-narrow.webp)

### Sidebar active install state

Before — merge base during the controlled install, 1440×900:

![Before: sidebar footer keeps the download icon during an active
install](https://img3.pixhost.cc/images/5324/763945959_before-sidebar-active.webp)

After — PR head during the same controlled install, 1440×900:

![After: sidebar footer replaces download with loading and preserves
provider
marks](https://img3.pixhost.cc/images/5324/763945963_after-sidebar-active.webp)

After — PR head after the controlled failure settles, 1440×900:

![After settled: sidebar footer restores the download
icon](https://img3.pixhost.cc/images/5324/763945967_after-sidebar-cleared.webp)

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` |
| --- | --- |
| ![Before: thread actions menu without Copy thread
link](https://gist.githubusercontent.com/brsbl/ec5a76b1a7c321d9ccf3429cbed8d9b2/raw/cf4fe9cd0ede18728c8a46bbe1f21bf38e2d9585/before-copy-thread-link.svg)
| ![After: header thread actions menu with Copy thread
link](https://gist.githubusercontent.com/brsbl/7a294c74da211bd2815126df53bbd89d/raw/9cb7466721ecb7f2380c7ec9618b337fc2f24067/after-header-copy-thread-link.svg)
|

Sidebar parity on the same production-code revision:

![After: sidebar thread actions menu with Copy thread
link](https://gist.githubusercontent.com/brsbl/7a294c74da211bd2815126df53bbd89d/raw/33d1d9400cc9a1fb28d190c085fce1b7b70a6092/after-sidebar-copy-thread-link.svg)

## 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants