Skip to content

Make plugin file openers reachable and give them a real height - #2026

Merged
ymichael merged 2 commits into
get-bb:mainfrom
andrewkchan:fix/plugin-file-opener-slot
Aug 20, 2026
Merged

Make plugin file openers reachable and give them a real height#2026
ymichael merged 2 commits into
get-bb:mainfrom
andrewkchan:fix/plugin-file-opener-slot

Conversation

@andrewkchan

@andrewkchan andrewkchan commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Human comments

Before this, (1) custom file openers did not work on files opened via CMD+P, and (2) a custom file opener would render with nearly 0px height:
Screenshot 2026-08-20 at 1 14 41 AM


What was wrong

The fileOpener plugin slot could not work end to end — three independent defects, each of which alone made the slot unusable. Reachability: the secondary panel's file search built its tab through createTabForFileSearchSelection and never called createFileOpenerTabForRequest, so a file picked from the "+"/quick-open screen always got the built-in preview regardless of the user's Settings → File openers choice; diversion applied only to file links and bb thread open, contradicting the comment on openTab that claims every file-open flow funnels through it. Sizing: fileTabContentFillsRegion resolved the active tab's actionId against threadPanelActions, but a file-opener tab's actionId is file-opener:<id> (FILE_OPENER_ACTION_ID_PREFIX) and never matched, so opener tabs always landed in the preview's scroll container rather than the definite-height region; and the file-opener wrapper was min-h-0 flex-1 where the action-tab wrapper 90 lines above it is h-full min-h-0 flex-1. Since that region is a block box, flex-1 was inert and the wrapper collapsed to content height, so an opener that sizes itself with flex-1 rendered at zero height.

Found while building a Monaco-based editor plugin against the slot: the opener registered, appeared in Settings, was explicitly selected for .ts and .json, and still never rendered — and once forced to render, occupied ~10px.

What changed

  • apps/app/src/components/secondary-panel/useThreadFileTabs.tsselectFileSearchResult now runs the same opener diversion as openTab, falling back to the built-in tab when no opener matches. The replace-the-new-tab-screen behavior is unchanged.
  • apps/app/src/views/thread-detail/ThreadDetailView.tsx, apps/app/src/views/RootComposeView.tsxfileTabContentFillsRegion now also returns true for file-opener tabs, keyed off fileOpenerOwner (already set on exactly these tabs). A plugin opener owns its own layout and scrolling, so it gets the definite-height region, matching a layout: "flush" action tab.
  • apps/app/src/components/plugin/PluginPanelActions.tsx — the file-opener wrapper gains h-full, matching the action-tab wrapper.

No wire changes, so HOST_DAEMON_PROTOCOL_VERSION is untouched. No CLI, guide, or doc surfaces are affected: this restores documented behavior rather than adding any.

Both sizing changes are required. Without the region fix the opener fills a scroll container and overflows by its pb-3; without h-full the wrapper stays content-sized however tall the region is.

How you verified

Three tests added to useThreadFileTabs.test.ts, alongside the existing openTab diversion coverage:

  • diverts a workspace file picked from the file searchfails before, passes after. Verified by restoring the pre-fix useThreadFileTabs.ts with the new tests in place: 17 pass, this one fails; with the fix, 18 pass.
  • keeps the built-in preview for an unmatched file search extension and honors a pinned built-in preference from the file search — pass both before and after. They are guards, not regression proofs: they pin the fallbacks so a future change cannot start diverting files the user asked BB to keep.
pnpm exec turbo run test --filter=@bb/app -- useThreadFileTabs   # 18 passed
pnpm exec turbo run typecheck --filter=@bb/app                   # clean

The two sizing defects are not covered by automated tests. They are CSS-in-DOM-context failures — the wrapper collapses only because its ancestor is a block box — and the only cheap unit test available would assert a Tailwind class string, which is the kind of test AGENTS.md discourages. Testing them for real would mean extracting the fileTabContentFillsRegion computation out of both views into a helper; happy to do that if reviewers want it covered.

Verified manually against a dev server on this checkout with a Monaco fileOpener plugin installed. Before: quick-open a .ts file → built-in preview, with the plugin's registration confirmed live in the console and "Automatic (Monaco)" selected in Settings; pinning .json to Monaco explicitly changed nothing. Walking the DOM from [data-testid="plugin-file-opener-tab-content"] showed the wrapper at clientHeight: 38 inside a display: block scroll container at 775px. After: quick-open renders the plugin editor, filling the panel, with editing, saving, and find working.

Fixes #

AGENT GENERATED: by Claude Opus 5

andrewkchan and others added 2 commits August 20, 2026 01:55
A plugin `fileOpener` could not work end to end. Three independent
defects, each of which alone made the slot unusable:

The file search built its tab through `createTabForFileSearchSelection`
and never called `createFileOpenerTabForRequest`, so every file picked
from the "+"/quick-open screen got the built-in preview no matter what
Settings → File openers said. Diversion applied only to file links and
`bb thread open`, contradicting the comment on `openTab` that claims
every file-open flow funnels through it.

`fileTabContentFillsRegion` resolved the active tab's `actionId` against
`threadPanelActions`, but a file-opener tab's actionId is
`file-opener:<id>` and never matched, so opener tabs always landed in
the preview's scroll container instead of the definite-height region.

The file-opener wrapper was `min-h-0 flex-1` where the action-tab
wrapper is `h-full min-h-0 flex-1`. That region is a block box, so
`flex-1` was inert and the wrapper collapsed to content height — an
opener sizing itself with `flex-1` got zero height.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The search path had no coverage, which is why it could silently skip
opener diversion while the link and `bb thread open` paths were tested.

The first test fails before the fix and passes after; the other two pin
the fallbacks (unmatched extension, pinned built-in) so a future change
cannot start diverting files the user asked BB to keep.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@andrewkchan
andrewkchan force-pushed the fix/plugin-file-opener-slot branch from 69f5329 to 0faccf7 Compare August 20, 2026 09:00
@ymichael
ymichael merged commit 7af6934 into get-bb:main Aug 20, 2026
12 checks passed
andrewkchan added a commit to andrewkchan/bb-plugin-monaco that referenced this pull request Aug 20, 2026
The [monaco-plugin] tracing existed to find why BB never routed files to
the opener; that turned out to be a host bug (get-bb/bb#2026) and the
logs have served their purpose. Failures already surface in the UI —
open errors become the editor's error notice, and loader failures reject
the boot promise into that same path — so nothing observable is lost.

Keeps one console.warn for the case where Monaco's typescript defaults
cannot be found at either the current or deprecated path. That one is
silent on success and otherwise invisible: the symptom would be an
editor full of false "Cannot find module" errors with no stated cause.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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