镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Expose exact captured-message reads - #3264

Draft
kazemek21 wants to merge 10 commits into
mainfrom
kylez_NEXUS-4479_exact-captured-unread
Draft

kazemek21 wants to merge 10 commits into
mainfrom
kylez_NEXUS-4479_exact-captured-unread

Conversation

@kazemek21

@kazemek21 kazemek21 commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR

This lets retained readers explicitly clear only a captured set of unread messages without including other messages or newer unread intent.
It adds one optional host method that saves reads for verified message IDs.

Why

Existing read methods can include a subtree or move a timeline boundary. A caller that already has an exact set needs a host operation that keeps that boundary exact.

What

UnreadCapability now has optional markCapturedMessagesRead(messageIds). Older hosts can omit it.

How

The method revalidates each message and saves only per-message keys in the captured set. After that save succeeds, it clears only those IDs' visit-local forced overlays and leaves the shared channel force hint untouched.

Risk

No caller or UI changes. Default read behavior remains unchanged.

Testing

No manual testing.

Generated with Codex (gpt-6-luna) on behalf of kylez

kazemek21 and others added 10 commits November 10, 2026 22:26
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
…e card (#2239)

## Summary

Lets plugins open file attachments the way
#1469 opens Markdown, without
bundling a previewer into Buzz.

File attachments in message rows now go through attachment renderers,
like images and audio already do. For files, a renderer also receives
`FileCard`: the host's own file card. Rendering it with `onPreview`
makes clicking the card open the preview, while a separate trailing
button keeps the host's native or browser download. Plugins can't reach
the native download themselves, so this keeps Download working for them
on desktop.

Renderers also receive `placement` (`"message"` or `"composer"`), so a
plugin can offer the preview only on sent messages and leave the
composer's attachment review alone. In message rows they also receive
`message`, the message that holds the attachment, so a preview can name
who shared it and where.

The first consumer is an external PDF viewer plugin: clicking a PDF card
opens it in the conversation side pane.

## Changes

- `contracts.ts` (FOUNDATION): adds optional `placement`, `message` and
`FileCard` to `AttachmentRendererProps`, plus `FileCardProps`.
- `MessageRow.tsx`: file attachments go through `AttachmentView` with
`placement="message"`, `message` and `FileCard`. Audio and image
renderers also get `placement`.
- `ComposerAttachmentViewer.tsx`, `ComposerAttachments.tsx`: pass
`placement="composer"`. The draft viewer also passes `FileCard`.
- `FileAttachment.tsx`, `Messages.module.css`: the click-to-preview card
with a separate Download action, taken from
#1469 without its summary variant.
- `docs/plugin-architecture.md`: documents `registerAttachment`,
`placement` and `FileCard`.

With no plugin claiming a file, message rows render exactly as before.

## Relationship to #1469

This takes only the host plumbing from
#1469 (the renderer routing,
`placement`, and the preview card) and leaves out the bundled File
Preview plugin. If #1469 lands later, its File Preview can render
`FileCard` the same way, and the overlapping pieces should rebase
cleanly onto this. Co-authored with htian-dev, whose code this is.

## Test plan

- `pnpm check` passes.
- `vitest run src/features/messages src/features/conversation
src/bundled`: 6941 passed.
- New tests:
- `FileAttachment.test.tsx`: preview and native download are separate
keyboard actions.
- `MessageRow.test.tsx`: a plugin renders `FileCard` in message
placement and receives the message; clicking it opens the plugin's
target; Download keeps the media address; an unclaimed file keeps the
plain download card.

### Manual test steps

1. Run `just desktop` from this branch and sign in.
2. Without any plugin, post a PDF and a `.zip`. Both show the usual file
card, and clicking either downloads it.
3. Install a plugin whose PDF renderer draws `FileCard` with `onPreview`
opening a side-pane target (Settings → Plugins → Manage plugins). I
tested with a PDF viewer plugin built this way.
4. Click the PDF card. The plugin's preview opens as a tab in the side
pane.
5. Click the download button at the right edge of the PDF card. The file
saves to Downloads, and the card shows "Saved to Downloads".
6. Tab to the card: focus lands on the card first, then on Download.
Enter on each does the same as clicking it.
7. The `.zip` card still downloads on click.
8. Attach a PDF in the composer and open it from the draft. The draft
view shows the plain card, with no side-pane preview.
9. Check both themes and a narrow window.

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

---------

Co-authored-by: Helen Tian <htian@squareup.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Joah Gerstenberg <joah@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Add an optional host capability that saves reads for exactly the captured verified message IDs and clears only their visit-local forced overlays after persistence. Preserve independent shared channel markers and newer read intent.

Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Signed-off-by: Kyle Zemek <kylez@squareup.com>
Co-authored-by: Codex <noreply@openai.com>

This branch has not been deployed

No deployments
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