Commit Graph
120 Commits
Author SHA1 Message Date
Pablo Tovar afc06864c6 test: add getUserAboutAccount coverage 2026-06-24 18:40:30 +09:00
Ryan H 5509d915ba test: update feature flag expectations to match new values 2026-06-24 18:35:53 +09:00
yuta 3f370cc4b6 feat: support relay profile selection
CI / test (push) Successful in 10m2s
2026-06-24 18:30:24 +09:00
yuta 7a036e244d fix: parse verify credentials user id
CI / test (push) Successful in 9m59s
Publish npm package / publish (push) Failing after 5m12s
2026-06-24 16:33:43 +09:00
yuta 6503bb1b76 Simplify relay request headers
CI / test (pull_request) Has been cancelled
2026-06-24 03:52:16 +09:00
yuta 1f6e228272 Use twitter safe relay
CI / test (pull_request) Has been cancelled
2026-06-24 03:39:34 +09:00
Peter Steinberger afdcad4f25 fix: allow partial tweet detail errors (#48) (thanks @jsholmes) 2026-01-12 07:33:25 +00:00
Peter Steinberger afa7063a72 fix: guard pagination limits (#44) (thanks @jsholmes) 2026-01-12 07:07:47 +00:00
Peter Steinberger 9cfeda13b2 test: add search CLI pagination checks 2026-01-12 06:44:42 +00:00
Pablo Tovar e23c20a6a2 feat: add pagination support to search command
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.
2026-01-12 06:29:27 +00:00
Peter Steinberger f351414046 fix: harden home timeline live checks 2026-01-12 06:10:57 +00:00
Peter Steinberger c96ce5238f fix: tighten news output and parsing (#39) (thanks @aavetis) 2026-01-12 05:37:44 +00:00
aavetisandClaude Sonnet 4.5 fb092f5cec feat: add multi-tab fetching to news command for 5x more headlines
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]>
2026-01-12 05:33:19 +00:00
aavetisandClaude Sonnet 4.5 57d1498f1d feat: add news command to fetch AI-curated headlines
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]>
2026-01-12 05:32:06 +00:00
Peter Steinberger 28695d2ef0 fix: harden article rich content rendering (#36) (thanks @crcatala) 2026-01-12 05:14:39 +00:00
cc-vpsandChristian Catalan 316cdf77be feat: support rich content in long-form tweets (X Articles)
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]>
2026-01-12 05:12:33 +00:00
Peter Steinberger 16f21800b5 refactor: align replies/thread pagination (#35) (thanks @crcatala) 2026-01-12 02:41:08 +00:00
cc-vpsandChristian Catalan 90037ce880 feat: add pagination support for thread and replies commands
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]>
2026-01-12 02:35:36 +00:00
Peter Steinberger 9dd9efa4e3 test: split user lookup coverage 2026-01-12 02:09:52 +00:00
Peter Steinberger 11cc9fbd27 test: expand user-tweets coverage 2026-01-12 01:45:41 +00:00
Peter Steinberger 4eac0927c1 fix: paginate user-tweets by --count 2026-01-12 01:35:00 +00:00
cc-vpsandChristian Catalan df98e827f6 feat: add user-tweets command to fetch tweets from a user's profile
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]>
2026-01-12 01:28:04 +00:00
Peter Steinberger 46255e8a38 test: add followers cursor coverage 2026-01-12 00:57:24 +00:00
Peter Steinberger dec78547fe test: split following/likes tests (#33) (thanks @VACInc) 2026-01-12 00:46:32 +00:00
Peter Steinberger baede65f77 fix: following pagination returns cursor and errors (#33) (thanks @VACInc) 2026-01-12 00:41:34 +00:00
Peter Steinberger 138b643d8a test: add print output coverage (#32) (thanks @odysseus0) 2026-01-11 23:38:44 +00:00
George Zhang 0475a2e1b6 test: add tests for article metadata extraction
- extractArticleMetadata: 6 tests for title/preview extraction
- mapTweetResult: 3 tests for article field inclusion
2026-01-11 23:35:03 +00:00
Peter Steinberger 94773c66dc fix: harden home timeline pagination (#31) (thanks @odysseus0) 2026-01-11 11:36:59 +00:00
George Zhang 73b8cff1b2 test: add home timeline API tests
- getHomeTimeline: success, error, API error handling
- getHomeLatestTimeline: success, error handling
- pagination: deduplication across pages

Uses realistic fixture structure based on actual API responses.
2026-01-11 11:35:57 +00:00
Peter Steinberger 6cf177f92f fix: list timeline pagination (#30) (thanks @zheli) 2026-01-11 11:27:46 +00:00
Zhe LiandClaude Sonnet 4.5 803bd25b0c feat: add pagination support to list-timeline command
Adds --all, --max-pages, and --cursor options to list-timeline command, enabling users to fetch all tweets from a list through automatic pagination. Follows the same pattern as bookmarks pagination for consistency.

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

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
2026-01-11 11:17:27 +00:00
Peter Steinberger 0a4699711f fix: sanitize hyperlink OSC output (#29) (thanks @mafulafunk) 2026-01-11 11:11:21 +00:00
Martin FunkandClaude Opus 4.5 837b09fcad feat: add clickable hyperlinks for URLs in terminal output
Use OSC 8 escape sequences to make tweet and list URLs clickable
in supported terminals (iTerm2, Ghostty, Kitty, WezTerm, VS Code, etc.).

- Add hyperlink() helper function in output.ts
- Apply hyperlinks in printTweets() for tweet URLs
- Apply hyperlinks in printLists() for list URLs
- Add hyperlinks flag to OutputConfig (auto-disabled for non-TTY)
- Automatically falls back to plain text in --plain mode or when piped

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
2026-01-11 11:10:34 +00:00
Peter Steinberger e39b430beb test: add users command pagination cases 2026-01-11 11:09:44 +00:00
Peter Steinberger 092be1a782 fix: harden follow pagination output (#28) (thanks @malpern) 2026-01-11 11:02:09 +00:00
Micah AlpernandClaude Opus 4.5 39a477265c feat: add cursor-based pagination for following/followers commands
Add pagination support to `bird following` and `bird followers` commands,
similar to existing pagination in search/bookmarks/likes.

Changes:
- Add `cursor` parameter to `getFollowing()` and `getFollowers()` client methods
- Return `nextCursor` in `FollowingResult` for pagination continuation
- Add `--cursor <cursor>` CLI option for manual pagination
- Add `--all` CLI flag to automatically fetch all pages
- Add `--max-pages <number>` option to limit pages when using --all
- Add input validation for --max-pages (requires --all or --cursor)
- Add deduplication using Set to prevent duplicate users
- Add 1-second delay between pages to avoid overwhelming the API
- Update `-n/--count` description to clarify it's per-page
- Add unit tests for cursor parameter and nextCursor response

Usage examples:
  # Fetch first page (default 20 users)
  bird following

  # Fetch with specific page size
  bird following -n 50

  # Use cursor for next page
  bird following --cursor "CURSOR_FROM_PREVIOUS"

  # Fetch ALL following users automatically (with rate limiting)
  bird following --all --json

  # Limit to first 5 pages
  bird following --all --max-pages 5

  # Same options work for followers
  bird followers --all

Note: REST API fallback does not support cursor pagination.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
2026-01-11 10:59:35 +00:00
Peter Steinberger ad125348d6 test: expand lists feature coverage 2026-01-11 10:58:47 +00:00
Peter Steinberger ad1d5f24cd fix: add lists feature flags (#27) (thanks @zheli) 2026-01-11 10:43:33 +00:00
Peter Steinberger 2e03bd8c07 fix: paginate likes + avoid duplicate loops (#12) (thanks @titouv) 2026-01-11 10:31:47 +00:00
Peter Steinberger 6fbbaebb68 fix: improve unbookmark url handling 2026-01-05 03:51:56 +01:00
Peter Steinberger f5402f2b43 feat: add runtime feature overrides 2026-01-05 01:23:32 +01:00
Peter Steinberger f765955116 fix: stabilize bookmark pagination cursors 2026-01-04 23:42:34 +00:00
Peter Steinberger c4fa04e0b2 feat: include raw tweet data in mapping 2026-01-05 00:30:01 +01:00
Peter Steinberger 3728f7a4f5 test: add mapTweetResult media coverage 2026-01-03 18:40:05 +01:00
Peter Steinberger b83d065907 fix: restore list types and tidy tests 2026-01-03 18:34:32 +01:00
Peter Steinberger d8643ae1d1 fix: improve media extraction 2026-01-03 18:34:32 +01:00
Nikita b4542b2213 test: add comprehensive tests for extractMedia function 2026-01-03 18:34:32 +01:00
Peter Steinberger e537e102e3 fix: normalize list privacy parsing 2026-01-03 16:55:29 +01:00
Harper ReedandClaude Opus 4.5 0e8a1349c5 test(lists): add boundary and fragment tests for extractListId
- Test that 5-digit IDs (minimum length) are accepted
- Test that URLs with fragment identifiers work correctly

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
2026-01-03 16:55:29 +01:00
Harper ReedandClaude Opus 4.5 59e827e153 test(lists): improve test coverage and extract list ID parsing
- Extract extractListId to src/lib/extract-list-id.ts with proper tests
- Add json-full/includeRaw test for list timeline
- Add 404 retry tests for getOwnedLists and getListMemberships
- Add tests for skipping invalid list entries and missing owner handling
- Use shared TwitterClientPrivate type from fixtures

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
2026-01-03 16:55:29 +01:00