Add `twitter bookmarks folders` command to list bookmark folders
and `twitter bookmarks folders <id>` to fetch tweets from a specific
folder, with --since date filtering and pagination support.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace _error_code_for_message() string matching with error_code attribute on exception classes
- Add error_code to all TwitterError subclasses (AuthenticationError, RateLimitError, etc.)
- Add InvalidInputError exception class
- TwitterAPIError derives error_code from HTTP status code automatically
- auth.py: use AuthenticationError instead of RuntimeError
- cli.py: catch (TwitterError, RuntimeError) for backward compat
- Extract _fetch_and_display_users() to deduplicate followers/following commands
- Add format_iso8601() to timeutil.py
- Add createdAtISO field to tweet and user profile serialization
- New test files: test_output.py, test_cache.py, test_timeutil.py
- Expand test_filter.py (topN, score mode, custom weights, empty input)
- Tests: 152 → 194 unit tests, all passing
- Add ensure_utf8_streams() in output.py: reconfigures stdout/stderr to UTF-8
on Windows at CLI startup, fixing emoji UnicodeEncodeError on GBK locales
- Call ensure_utf8_streams() in cli() entry point — one-line fix for all
output paths (click.echo, rich Console, print)
- Add Windows ConPTY troubleshooting to README (English + Chinese):
document Git Bash workaround, ConPTY pipe capture issue, and encoding notes
Ref: #29 (issuecomment-4065690862)
- Add win32 branch in _diagnose_keychain_issues() with DPAPI/admin/shadowcopy hints
- Add _make_console() helper in formatter.py with force_terminal=False for Windows non-TTY
- Replace all 6 Console() defaults with _make_console()
- Add test for Windows-specific diagnostics
- Remove _get_client_for_output() compat shim (replaced by direct _get_client calls)
- Remove unused inspect import
- Fix redundant branch in constants.get_accept_language()
- Add TWITTER_BROWSER docs to README (en + zh)
- Update all test monkeypatch signatures
- Bump version to 0.8.4
Add TWITTER_BROWSER environment variable to allow users to control
which browser's cookies are prioritized during extraction.
Example: TWITTER_BROWSER=chrome twitter feed
Supported values: arc, chrome, edge, firefox, brave.
The specified browser is moved to the front of the extraction order.
Also adds AGENTS.md developer guide for AI coding assistants.
Co-authored-by: Agassi <413855+agassiyzh@users.noreply.github.com>
Twitter long tweets (>280 chars) store full text in
note_tweet.note_tweet_results.result.text rather than legacy.full_text.
The parser now prioritizes note_tweet text when available.
- Fix auth.py subprocess script Windows Edge cookie path inconsistency
- Add timeutil.py for UTC→local time and relative time conversion
- Integrate time localization into formatter.py and serialization.py
- Add --output/-o option to show command for saving tweet detail as JSON
- Remove constants.py legacy aliases (USER_AGENT, SEC_CH_UA)
- Remove client.py backward-compat delegation methods and re-exports
- Update test imports to use parser module directly
- Merge get_tweet_id_by_index + get_cache_size into resolve_cached_tweet
to eliminate redundant file IO on cache miss
- Move save_tweet_cache before emit_structured so --json/--yaml modes
also persist the cache for subsequent show commands
- Extract _print_show_hint helper to reduce duplication
- Add trailing newline to cache.py
Add extensive tests for the `show` command (happy path, empty/expired/malformed cache, out-of-range, zero/negative indices) and a test helper to write cache fixtures. Harden twitter_cli.cache._load_cache to validate payload types (dict/tweets list), filter non-dict entries, and treat malformed payloads as empty; also handle missing tweet id when resolving an index. Refactor CLI output logic by extracting _emit_tweet_detail and reuse it for both `tweet` and `show`; enforce 1-based indices for `show` via click.IntRange(1) and expand the "no cached results" error text to mention other list commands. These changes improve robustness against corrupted caches and increase test coverage for cache-based behavior.
Persist last displayed tweet lists and allow opening a tweet by index.
- Add twitter_cli/cache.py: stores a short-index cache (~/.twitter-cli/last_results.json) with a 1h TTL and helpers to resolve index->tweet-id and cache size.
- Update twitter_cli/cli.py: save list results to cache, display a hint, and add `twitter show <N>` command which fetches a tweet by cached index and prints detail/replies (supports --full-text, --json, structured output, and max replies).
- Update README.md and SKILL.md to document the new `show` usage.
- Add .idea/ to .gitignore and bump package version in uv.lock to 0.8.0.
This change makes it easy to open items from the last feed/search without copying IDs.
- Add image upload to Features lists (EN + CN)
- Add --image/-i usage examples to Usage sections
- Add 'Post with images' agent workflow in SKILL.md
- Update Limitations: 'text only' → 'images only (no video yet)'
- Add upload_media() method to TwitterClient (INIT/APPEND/FINALIZE flow
via upload.twitter.com, supports JPEG/PNG/GIF/WebP up to 5MB)
- Extend create_tweet() and quote_tweet() with optional media_ids param
- Add --image/-i option to post, reply, and quote CLI commands (max 4)
- Add MediaUploadError exception for upload-specific error handling
- Add 6 unit tests covering upload flow, validation, and media_ids
Co-Authored-By: Catafal <67582323+Catafal@users.noreply.github.com>
Closes#17
- New search.py query builder module
- QUERY argument now optional when using advanced filters
- 21 unit tests + 3 CLI integration tests for search
- Bumped version to 0.7.0
Auto-iterates all Chrome/Arc/Edge/Brave profiles (Default, Profile 1,
Profile 2, ...) to find Twitter cookies. Falls back to the default
browser_cookie3 behavior when no profile dirs are found.
Set TWITTER_CHROME_PROFILE env var to specify a profile explicitly:
TWITTER_CHROME_PROFILE='Profile 2' twitter feed
Closes#6