Commit Graph

26 Commits

Author SHA1 Message Date
jackwener
ec4589c2d1 fix: P0 Windows Edge path, add time localization, show --output, cleanup tech debt
- 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
2026-03-14 13:26:36 +08:00
Pleasurecruise
72f62cedea fix: improve show handling, cache validation and tests
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.
2026-03-12 22:26:52 +00:00
jackwener
69cb85a1c2 feat: add image upload support for post/reply/quote commands
- 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>
2026-03-13 01:59:42 +08:00
jackwener
7d1b519c85 fix: harden search validation and release v0.7.1 2026-03-13 01:04:29 +08:00
jackwener
dc832f2ee2 feat: add advanced search options (--from, --to, --lang, --since, --until, --has, --exclude, --min-likes, --min-retweets)
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
2026-03-13 00:15:53 +08:00
jakevin
79eadd2579 feat: add twitter article markdown command (#16) 2026-03-12 14:47:49 +08:00
jackwener
1313eb0be1 feat: add full-text option for tweet tables 2026-03-11 20:58:12 +08:00
jackwener
88a9f4ce97 fix: tighten pagination and platform-specific auth 2026-03-11 20:32:51 +08:00
jackwener
60e1e7c580 feat: improve cookie extraction diagnostics and add doctor command
- Add _diagnose_keychain_issues() for macOS Keychain/SSH detection
- Extraction functions now return (cookies, diagnostics) tuples
- Error messages include actionable Keychain hints (e.g. unlock-keychain)
- Add 'twitter doctor' diagnostic command for troubleshooting
- Enhance bug_report.yml with browser/access method/diagnostics fields
- Expand README troubleshooting (EN+CN) with Keychain/SSH solutions
- Add 5 new tests for Keychain diagnostics

Closes #11
2026-03-11 16:53:06 +08:00
jackwener
6d6108436f chore: bump version to 0.6.0
Changes since 0.5.1:
- feat: Chrome multi-profile cookie extraction (#6)
- fix: warn on private likes (#8)
- fix: add logger definition (CI fix)
- refactor: specific ImportError handling (#10)
- docs: upgrade instructions in README and SKILL.md
2026-03-11 12:57:34 +08:00
jackwener
53a700ec60 feat: support Chrome multi-profile cookie extraction
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
2026-03-11 12:53:25 +08:00
jackwener
4afc4fc246 refactor: add exceptions.py module with structured exception hierarchy
- Create exceptions.py with 7 exception types: TwitterError, AuthenticationError,
  RateLimitError, NotFoundError, NetworkError, QueryIdError, TwitterAPIError
- Remove inline TwitterAPIError from client.py, import from exceptions module
- Replace RuntimeError('Cannot resolve queryId') with QueryIdError
- Replace RuntimeError('User not found') with NotFoundError
- Update test assertion for new TwitterAPIError message format
2026-03-10 23:05:05 +08:00
jackwener
9cf74abd56 feat: add integration smoke tests
CLI-level smoke tests using --yaml output against real Twitter API.
Default skipped via @pytest.mark.smoke marker + pyproject.toml addopts.
Run locally with: uv run pytest -m smoke -v
2026-03-10 22:26:46 +08:00
jackwener
4c2c02efd5 feat: unify structured error output 2026-03-10 21:18:38 +08:00
jackwener
642ffe84a8 feat: unify agent status schema 2026-03-10 21:02:08 +08:00
jackwener
32d074dc9f feat: anti-detection hardening, transaction cache, article parsing, structured write output
Anti-detection:
- Add 6 sec-ch-ua-* Client Hints headers (arch, bitness, full-version, etc.)
- POST requests now send Referer: x.com/compose/post + Priority: u=1, i
- follow/unfollow REST adds include_profile_interstitial_type param

Performance:
- Transaction ID cache with 1h TTL (~/.twitter-cli/transaction_cache.json)
- resolve_user_id: auto-detect screen_name vs numeric user_id

Features:
- Twitter Article parsing: extract long-form content as Markdown
- Write operations emit structured JSON/YAML when piped or OUTPUT env set
  ActionResult: {success, action, id, url, ...}

84 tests passing
2026-03-10 20:48:42 +08:00
jackwener
49d3e237c4 feat: add whoami, reply, quote, follow/unfollow commands and --compact mode
- whoami: fetch current authenticated user profile
- reply <id> <text>: standalone reply command
- quote <id> <text>: quote-tweet command
- follow/unfollow <handle>: follow/unfollow users
- --compact/-c: global flag for LLM-friendly minimal JSON output
- client.py: add fetch_me, quote_tweet, follow_user, unfollow_user
- serialization.py: add tweet_to_compact_dict, tweets_to_compact_json
- 7 new tests (82 total, all passing)
2026-03-10 20:09:08 +08:00
jackwener
d71ad45a0a fix: harden pagination auth and runtime headers 2026-03-10 12:33:04 +08:00
jackwener
4f144d1591 test: track parser fixture files 2026-03-10 12:08:47 +08:00
jackwener
19ab11d6a4 fix: harden auth flow and sync browser support docs 2026-03-10 11:02:34 +08:00
jackwener
fda9b1c3dc fix: 431 Request Too Large — reduce FEATURES to 15 essential keys, dynamic update only updates existing keys 2026-03-09 20:59:16 +08:00
jackwener
d20c5699fd fix: 414 URI Too Long — omit False-valued features from GET URL, add regression tests 2026-03-09 20:50:45 +08:00
jackwener
12f425abea feat: write operation delays, dynamic FEATURES update, 30+ client.py tests, fix README proxy wording 2026-03-09 20:45:51 +08:00
jackwener
27d73efee5 feat: anti-detection hardening with curl_cffi TLS impersonation and request jitter 2026-03-09 17:11:59 +08:00
jackwener
55c48b077b feat: add rate limiting, retry with backoff, and max count cap
- Add configurable request delay between paginated API calls (default 1.5s)
- Add retry with exponential backoff on HTTP 429 and Twitter error code 88
- Add hard max count cap (default 200, absolute ceiling 500)
- Add rateLimit config section with requestDelay, maxRetries, retryBaseDelay, maxCount
- Add normalization tests for rateLimit config
2026-03-07 19:02:49 +08:00
jackwener
6f322ff2d6 test+ci: add regression tests and GitHub Actions workflow 2026-03-05 16:14:05 +08:00