Repository navigation
Conversation
registerLinkPreview contributes a card below a message for one of its HTTPS links. The lowest order among matches draws it, so a plugin can claim its own URLs ahead of a catch-all web card. Bare and labeled links in prose get cards; <url>, code, images and attachment URLs do not. Past three cards the rest fold behind one button. Linear: AGNTOPS-773 Co-authored-by: Hertz <c6741012416ef5c49a865db79682113385c5fb998e8c890234fb442b59e22748@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Joah Gerstenberg <joah@squareup.com>
This branch has not been deployed
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.
Linear: AGNTOPS-773
Why
Core Buzz should unfurl links, and plugins should be able to override the default per site (Joah, plugin bounty thread). Plugins have no slot below a message today. The marketplace link-previews plugin renders its cards inside the link anchor, then moves the DOM nodes under the bubble and watches them with MutationObservers.
What
ctx.conversation.registerLinkPreview({ id, title, matches(url), order?, component }). Components receive{ url, messageId, open }.open()routes through the host's link handler, as clicking the link does, and returns false once the contribution or message retires.orderamong matches draws its card, the same resolutionregisterLinkand panels use. A default web card sits at the catch-all band (100), so a plugin claims its own site at 0. A component that renders nothing leaves that link without a card.previewLinks): credential-free HTTPS links in the message's Markdown prose, once each in the order written. Bare and labeled links count.<url>doesn't, since it asks for no preview, matching Let authors dismiss link previews with a one-link edit #2677's convention. Neither do links in code, images, or links naming one of the message's attachments. Diffs, agent envelopes and messages drawn by a message renderer get none.MessageRowmounts the stack between the bubble and its attachments. After three cards, the rest fold behind "Show N more previews". Each card has its ownContributionBoundary, so a failing renderer drops only its card.plugin-architecture.mdandplugin-authoring-guide.md.No core card ships in this PR; the bundled
buzz.link-previewsplugin follows it in the stack.Review notes
contracts.tsandservice.tsxare FOUNDATION. This adds one contribution kind besideregisterLink, with the same validation and lifetime. Joah asked for this extension point explicitly.editedInBodyinMessageRowis now derived frommarkdownBody, which the previews also use. Behavior is unchanged.Testing
vitest:preview-links.test.ts(new),LinkPreviews.test.tsx(new: order override, fold and unfold, host open, a throwing card isolated),service.test.tsx(new: registration validation and withdrawal), and the existingMessageRowtests: 223 passed.tsc --noEmitis clean.Part of a stack:
buzz.link-previews, on by default.🤖 Generated with Claude Code