Twitter API sometimes returns partial errors (e.g., is_translatable field
failures) alongside valid thread data. Previously, any error caused the
entire request to fail even when usable data was present.
Now we check if threaded_conversation_with_injections_v2.instructions
exists before failing on errors, allowing successful thread fetching
despite non-fatal API errors.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Library changes:
- Add getAllLikes(options) method for fetching all likes with cursor support
- Refactor getLikes to use private getLikesPaged helper
- Return nextCursor for resumable pagination
- Support maxPages option to limit pages fetched
CLI changes:
- Add --all flag to fetch all likes
- Add --max-pages to limit pagination
- Add --cursor to resume from previous fetch
- Output nextCursor in JSON mode for resumable pagination
This brings likes to feature parity with bookmarks.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
# Conflicts:
# src/commands/users.ts
Adds --all, --max-pages, and --cursor options to search command, enabling users to fetch all search results through automatic pagination. Follows the same pattern as bookmarks pagination for consistency.
Completely rewrites the news command to fetch from multiple Explore tabs
(For You, News, Sports, Entertainment) using GenericTimelineById GraphQL
API instead of just the ExplorePage initialTimeline. This delivers 15+
AI-curated headlines instead of 3, a 5x improvement in content discovery.
Key Changes:
- Add GenericTimelineById query ID support with auto-refresh capability
- Implement multi-tab fetching with cross-tab headline deduplication
- Add CLI flags for granular tab filtering (--for-you, --news-only,
--sports, --entertainment, --trending-only)
- Fetch from 4 tabs by default (excludes trending to reduce noise)
- Add early stopping optimization when count is reached
- Handle tab-level errors gracefully without failing entire request
Implementation:
- Added TIMELINE_IDS constant with base64 timeline identifiers
- Created fetchTimelineTab() method for GenericTimelineById requests
- Created parseTimelineTabItems() for new response structure
- Removed old parseNewsItems() and extractNewsItemsFromInstructions()
- Updated all 7 tests to mock GenericTimelineById responses
API Changes:
- NewsFetchOptions: Added `tabs?: ExploreTab[]` option
- ExploreTab type exported for library consumers
- Backward compatible - existing code continues to work
Documentation:
- Added comprehensive "News & Trending" section with examples
- Updated command reference with all new flags
- Added library usage examples with tab filtering
- Updated JSON schema documentation
Testing:
- All 268 tests passing
- Real-world verified: fetches 15+ AI headlines across tabs
- Tab filtering verified: --sports, --entertainment, etc all work
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add comprehensive news/trending feature that fetches AI-generated news
headlines from Twitter's "For You" page. This feature specifically
targets the AI-curated news items that Twitter displays under "Today's
News" section, not generic trending hashtags.
- Uses Twitter's ExplorePage GraphQL API endpoint to access the Explore
page timeline data where AI headlines are located
- AI headlines are identified by the explicit `is_ai_trend: true` flag
in the API response
- Fallback heuristic detection for full-sentence headlines (5+ words)
with "News" or time indicators in social context
- Headlines are found in "stories-*" modules within the initialTimeline
structure under a "Today's News" header
- Follows the existing mixin pattern (withNews) for composability
- Supports both AI-only filtering and mixed trending/AI results
- `bird news` - Fetch news and trending topics (mixed results)
- `bird news --ai-only` - Fetch ONLY AI-curated headlines
- `bird news -n <count>` - Limit number of results
- `bird news --json` - Output as JSON
- `bird news --json-full` - Include raw API response
- `bird news --with-tweets` - Enrich with related tweets
- `bird trending` - Alias for news command
- AI headlines are clearly marked with "AI · " category prefix
- Automatic deduplication of duplicate headlines
- Rich formatting with category, time, post count, and URLs
- src/commands/news.ts - CLI command implementation
- src/lib/twitter-client-news.ts - Core news fetching functionality
- tests/commands.news.test.ts - Command validation tests (7 tests)
- tests/twitter-client-coverage.news.test.ts - API coverage tests (7 tests)
- README.md - Added documentation for news command
- src/cli/program.ts - Registered news command
- src/lib/index.ts - Exported news-related types
- src/lib/twitter-client.ts - Integrated withNews mixin
- src/lib/query-ids.json - Added ExplorePage query ID
- src/lib/twitter-client-constants.ts - Added ExplorePage constant
- src/lib/twitter-client-features.ts - Added buildExploreFeatures()
- scripts/update-query-ids.ts - Added ExplorePage to update script
- All 268 existing tests continue to pass
- Added 14 new tests covering command validation and API functionality
- Tested with real Twitter data confirming AI headline detection
- All TypeScript compilation and linting checks pass
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add support for extracting rich content from X's long-form tweets,
including embedded code snippets, markdown blocks, quoted tweets,
and other structured content that was previously lost.
Changes:
- Add fieldToggles with withArticleRichContentState to TweetDetail API request
- Implement Draft.js content_state parser (renderContentState) that converts
blocks and entities to readable markdown format
- Add content_state type definition to GraphqlTweetResult
Supported content:
- Block types: paragraphs, headers, ordered/unordered lists, blockquotes
- Entity types: MARKDOWN (code blocks), DIVIDER, TWEET, LINK, IMAGE
No impact on regular tweets - rich content only adds payload when present.
Includes 20 unit tests for the parser and an opt-in live smoke test.
Co-authored-by: Christian Catalan <[email protected]>
Add --all, --max-pages, --delay, and --cursor options to both thread
and replies commands, enabling fetching of all conversation content
with rate-limit-friendly pagination.
Changes:
- Modified fetchTweetDetail() to accept optional cursor parameter
- Added getRepliesPaged() and getThreadPaged() methods with pagination loop
- Updated CLI commands with new options (--all, --max-pages, --delay, --cursor)
- Added TweetDetailPaginationOptions interface
- JSON output includes nextCursor for scripting/resumption
Options:
- --all: Fetch all pages (no hard limit)
- --max-pages <n>: Limit number of pages when using --all
- --delay <ms>: Delay between page fetches (default: 1000ms)
- --cursor <string>: Resume from a previous cursor
Follows patterns established by bookmarks command and PR #34 (user-tweets).
Co-authored-by: Christian Catalan <[email protected]>
Adds new CLI command to fetch tweets from any user's profile timeline.
Usage:
bird user-tweets @username [-n count] [--pages N] [--json]
Features:
- GraphQL UserByScreenName for username → userId resolution
- Cursor-based pagination with configurable delay (rate-limit safe)
- Hard cap of 10 pages to prevent abuse
- Input validation via normalizeHandle()
Includes 17 unit tests and live smoke test.
Co-authored-by: Christian Catalan <[email protected]>
The article type had title defined twice (at lines 83 and 135), causing
TypeScript compilation to fail with TS2300: Duplicate identifier 'title'.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Use startsWith check instead of fragile length heuristic for
detecting full article body vs preview mode
- Add media display for quote tweets (🖼️/🎬/🔄 indicators)
- Add preview_text to GraphqlTweetResult type definition to avoid
type assertions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>