{"_id":"@andypai/x","name":"@andypai/x","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@andypai/x","version":"0.1.0","description":"Read-only X (Twitter) API CLI.","type":"module","main":"src/index.ts","module":"src/index.ts","bin":{"x":"src/index.ts"},"repository":{"type":"git","url":"git+https://github.com/abpai/x-cli.git"},"homepage":"https://github.com/abpai/x-cli#readme","bugs":{"url":"https://github.com/abpai/x-cli/issues"},"keywords":["x","twitter","cli","bun","api"],"engines":{"bun":">=1.1.0"},"packageManager":"bun@1.3.3","license":"MIT","scripts":{"dev":"bun --watch src/index.ts","start":"bun src/index.ts","build":"bun build ./src/index.ts --target bun --outdir ./dist","lint":"bun ./node_modules/eslint/bin/eslint.js .","format":"bun ./node_modules/prettier/bin/prettier.cjs --write .","typecheck":"bun ./node_modules/typescript/bin/tsc --noEmit","check":"bun run lint && bun run typecheck","test":"bun test","test:watch":"bun test --watch","prepare":"test -d .git && bunx husky install || true"},"dependencies":{"@clack/prompts":"^1.0.1","commander":"^13.1.0"},"devDependencies":{"@eslint/js":"^9.39.1","@typescript-eslint/eslint-plugin":"^8.18.0","@typescript-eslint/parser":"^8.18.0","@types/bun":"^1.1.22","eslint":"^9.39.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","husky":"^8.0.3","lint-staged":"^15.2.0","prettier":"^3.7.4","typescript":"^5.7.2"},"lint-staged":{"*.{js,jsx,ts,tsx}":["eslint --fix","prettier --write"],"*.{css,html,json,md,scss,yaml,yml}":["prettier --write"]},"gitHead":"a3eb75bb5d78aea388b43bb82263281b19f58520","_id":"@andypai/x@0.1.0","_nodeVersion":"24.12.0","_npmVersion":"11.11.0","dist":{"integrity":"sha512-MA1ebuHOfeOksoia2xbUd8V/AMbQKuH0pRyCq7Seg/QpPhOi4KxbrRybZDtLPyGKmykLZ4NECYKHFUImkqdNxA==","shasum":"dcd3c254b0dcf57df4ea0427b06ab21c3633895e","tarball":"https://registry.npmjs.org/@andypai/x/-/x-0.1.0.tgz","fileCount":13,"unpackedSize":97925,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAmAff5iCDJrIa18QhnRwe3qp190jtkvBAqCSuwEJ5kzAiEAxViWdnPo2m8H3mHMeGSJFV6E9mjmotvPwWX2J3RINwE="}]},"_npmUser":{"name":"andypai.me","email":"andy@r2pi.co"},"directories":{},"maintainers":[{"name":"andypai.me","email":"andy@r2pi.co"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/x_0.1.0_1773281502449_0.014433552606981648"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-12T02:11:42.349Z","0.1.0":"2026-03-12T02:11:42.637Z","modified":"2026-03-12T02:11:42.871Z"},"maintainers":[{"name":"andypai.me","email":"andy@r2pi.co"}],"description":"Read-only X (Twitter) API CLI.","homepage":"https://github.com/abpai/x-cli#readme","keywords":["x","twitter","cli","bun","api"],"repository":{"type":"git","url":"git+https://github.com/abpai/x-cli.git"},"bugs":{"url":"https://github.com/abpai/x-cli/issues"},"license":"MIT","readme":"<p>\n  <img src=\"assets/icon.svg\" width=\"48\" height=\"48\" alt=\"x-cli icon\" />\n</p>\n\n# x CLI\n\nRead-only X API client for the terminal, built on Bun.\n\n## Why\n\nX launched pay-as-you-go API pricing. The $200/mo Pro tier was excessive for\npersonal use, but per-request pricing makes the API viable for lightweight\nworkflows.\n\nI wanted quick terminal access to timelines, bookmarks, and search without\nopening a browser. Puppeteer/Playwright scraping is fragile and breaks\nconstantly, and it risks your account. This uses the official API only — no\nscraping, no ToS violations. It also gives tools like\n[OpenClaw](https://github.com/openclaw/openclaw) a structured way to check\ninterests and do research.\n\n## Install\n\nGlobal install from npm registry:\n\n```bash\nbun install -g @andypai/x\n```\n\nFor local development, clone the repo and symlink the executable:\n\n```bash\nbun install\nchmod +x src/index.ts\nln -sf \"$(pwd)/src/index.ts\" ~/.bun/bin/x\n```\n\n## Getting Started\n\n### 1. Create a project in the X Developer Portal\n\nGo to the [X Developer Portal](https://developer.x.com/en/portal/dashboard) and create a project + app. You'll need:\n\n- **OAuth 1.0a** keys (API Key, API Secret, Access Token, Access Token Secret) — used by `following`\n- **OAuth 2.0** client credentials (Client ID, Client Secret) — used by `bookmarks`, `timelines`\n- **Bearer Token** — used by `search`\n\nUnder your app's \"User authentication settings\", enable OAuth 2.0 with type **Confidential client** and add `http://127.0.0.1:3000/callback` as a redirect URI.\n\n### 2. Run interactive setup\n\n```bash\nx setup\n```\n\nThis walks you through pasting each credential and runs the OAuth 2.0 authorization flow to mint a user token. If matching env vars already exist, setup uses them as hidden defaults so you can press Enter without re-pasting secrets.\n\nSkip OAuth 2.0 if you only need `following` and `search`:\n\n```bash\nx setup --no-oauth2\n```\n\nOr bootstrap non-interactively from existing env vars:\n\n```bash\nx setup --no-input\n```\n\n### Credentials\n\nThe resulting credential file (`.env` or `~/.config/x-cli/.env`) contains:\n\n| Variable                | Auth Flow              | Used By                  |\n| ----------------------- | ---------------------- | ------------------------ |\n| `X_API_KEY`             | OAuth 1.0a             | `following`              |\n| `X_API_SECRET`          | OAuth 1.0a             | `following`              |\n| `X_ACCESS_TOKEN`        | OAuth 1.0a             | `following`              |\n| `X_ACCESS_TOKEN_SECRET` | OAuth 1.0a             | `following`              |\n| `X_BEARER_TOKEN`        | App-Only (OAuth 2.0)   | `search`                 |\n| `X_USER_ACCESS_TOKEN`   | OAuth 2.0 User Context | `bookmarks`, `timelines` |\n| `X_USER_REFRESH_TOKEN`  | OAuth 2.0 refresh      | automatic token renewal  |\n| `X_CLIENT_ID`           | OAuth 2.0              | token refresh, setup     |\n| `X_CLIENT_SECRET`       | OAuth 2.0              | token refresh, setup     |\n\n> **Note:** `X_ACCESS_TOKEN` (OAuth 1.0a) and `X_USER_ACCESS_TOKEN` (OAuth 2.0 User Context) are different credentials — don't confuse them.\n\n> **Refresh tokens:** If `X_USER_REFRESH_TOKEN` and `X_CLIENT_ID` are present, the CLI will attempt one automatic refresh on 401. Read-only scopes used: `tweet.read users.read bookmark.read follows.read offline.access`.\n\n## Commands\n\n```bash\nx following [--max-results 25]\nx timelines [--max-results 25] [--all] [--pretty] [--images auto|on|off] [--image-width 40] [--max-images 4]\nx bookmarks [--max-results 25] [--pretty]\nx search \"openai bun\" [--max-results 25] [--pretty]\nx setup [--no-input] [--overwrite] [--oauth2|--no-oauth2] [--from-env]\n```\n\n`--max-results` supports `5-100`.\n\n`timelines` requests a ranking-friendly payload including:\n\n- `expansions=author_id,referenced_tweets.id,referenced_tweets.id.author_id,attachments.media_keys`\n- `tweet.fields=id,text,author_id,created_at,lang,entities,context_annotations,public_metrics,note_tweet,referenced_tweets,possibly_sensitive`\n- `user.fields=id,username,name,description,entities,verified,public_metrics`\n- `media.fields=type,url,preview_image_url,duration_ms,alt_text,public_metrics`\n\nFor human review in terminal:\n\n```bash\nx timelines -m 5 --pretty\nx bookmarks -m 5 --pretty\nx search \"long running agents\" -m 5 --pretty\n```\n\nFor Ghostty/Kitty inline previews:\n\n```bash\nx timelines -m 5 --pretty --images auto\n```\n\nNotes:\n\n- `--images auto` renders inline previews beside each timeline entry when Kitty-compatible support is detected.\n- `--images on` forces Kitty rendering attempts, while `--images off` disables inline previews.\n- Previews are fetched from `pbs.twimg.com` media and automatically retried with `format=png` when needed.\n\n## Scripts\n\n```bash\nbun run dev        # run with watch mode\nbun run start      # run once (CLI entry)\nbun run lint       # eslint\nbun run format     # prettier write\nbun run typecheck  # tsc --noEmit\nbun run test       # bun test\nbun run test:watch # bun test --watch\nbun run build      # bun build ./src/index.ts --target bun --outdir ./dist\nbun run check      # lint + typecheck\n```\n","readmeFilename":"README.md","_rev":"1-af3d0be9eb5093f15559dd8a630116fa"}