Skip to content

feat(inbox): show unread mentions and add --mentions filter - #60

Draft
roryist wants to merge 5 commits into
mainfrom
roryist/inbox-unread-mentions
Draft

roryist wants to merge 5 commits into
mainfrom
roryist/inbox-unread-mentions

Conversation

@roryist

@roryist roryist commented Sep 14, 2026

Copy link
Copy Markdown

When you run tdc inbox, you could not tell which unread threads had a fresh mention of you. The web app shows an @ badge for those. The CLI showed nothing.

The CLI was already fetching that information. The unread endpoint returns a mention flag for every unread thread, and the CLI reduced that response to a list of ids and threw the flag away. The directMentions field on a thread is not a substitute, because it only says who the first post mentioned.

Now every inbox thread carries hasUnreadMention in JSON output, there is a --mentions flag to show only those, and the human view marks them with a yellow @ and sorts them to the top of each channel. Channel thread listings get the same two fields from the same helper, so tdc channel threads --json and tdc inbox --json agree on shape.

Four tests cover the flag, the filter, the sort and the marker. Tests, type-check, lint and the skill-sync check pass. I ran the built binary against a real inbox and it returned exactly the threads the server flags.

One thing to know: this means "unread mentions", the same as the web badge. A mention you have already read past will not show. An "ever mentioned" filter needs the backend to expose a field it currently hides.

(Written by Rory's agent)

🤖 Generated with Claude Code

https://claude.ai/code/session_01XYtXq3VLuv34zPKicow2jg

`threads/get_unread` already returns a `directMention` flag per unread thread, but the CLI reduced the response to a Set of IDs and dropped it. Keep the full entry, expose it as `hasUnreadMention` on each inbox thread (JSON and human output), add a `--mentions` filter, and sort mention threads first within each channel.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtXq3VLuv34zPKicow2jg
@roryist roryist self-assigned this Sep 14, 2026
--mentions and --unread now compose instead of one overriding the
other. The three-pass filter/sort becomes one keyed sort. The last
Set-based caller moves onto the shared Map helper and the wrapper goes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtXq3VLuv34zPKicow2jg
@roryist roryist added the 🙋 Ask PR PR must be reviewed before merging label Sep 15, 2026
unreadFlags gives inbox and channel threads the same isUnread and
hasUnreadMention fields, so the JSON shape matches across both list
commands. One spelling of the row type in the inbox sort.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtXq3VLuv34zPKicow2jg
@roryist

roryist commented Sep 21, 2026

Copy link
Copy Markdown
Author

@doistbot /review

@doistbot doistbot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds unread-mention awareness to the inbox: every thread now carries hasUnreadMention in JSON output, a --mentions flag filters to threads with fresh mentions, and the human view marks them with a yellow @ and sorts them to the top of each channel. The shared unreadFlags helper keeps tdc inbox --json and tdc channel threads --json consistent, and the tests cover the flag, filter, sort, and marker.

Few things worth tightening:

  • The unread lookup keeps full UnreadThread objects for the rest of the command when consumers only need existence and the directMention boolean. Since getUnread() is workspace-wide, storing a compact Map<string, boolean> (or similar flag value) would avoid retaining fields like channelId and objIndex for large unread sets.

I also included a few optional follow-up notes in the details below.

Optional follow-up notes (3)
  • P3 src/lib/threads.ts:6: CODEBASE.md still references the removed fetchUnreadThreadIds helper (lines 162 and 179) after this rename to fetchUnreadThreads. Update those references so the repo map matches the exported function.
  • P3 src/commands/channel/threads.ts:127: tdc channel threads --json now emits hasUnreadMention, but no test covers it. The PR explicitly advertises shape parity with tdc inbox --json, yet src/commands/channel/threads.test.ts still only asserts isUnread/url. Extend the existing --json emits isUnread and url without --full test (or add one) to assert hasUnreadMention: true for an unread entry with directMention: true.
  • P3 src/commands/inbox.test.ts:275: This sort test has exactly one thread per tier (mention / plain unread / read), so it only proves the tier ordering. A comparator regression that dropped the || sortByDate(a, b) tie-break would still pass, because each tier contains a single item and the fixture's original order already matches the tier order. Add a second thread to one tier (e.g. another plain-unread thread with a different posted value) and assert newest-first within that tier.

Share FeedbackReview Logs

Comment thread src/lib/threads.ts
roryist and others added 2 commits September 21, 2026 21:44
Second plain-unread thread proves newest-first within a tier. Channel
threads JSON asserts hasUnreadMention. CODEBASE.md names the helpers
that exist now.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtXq3VLuv34zPKicow2jg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🙋 Ask PR PR must be reviewed before merging

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants