Przejdź do treści
Biblioteka skilli
Marketing i treści · Automatyzacja

twitter

/twitter

Publikuje i usuwa tweety oraz eksportuje je do YAML na X, sterując przeglądarką Chrome w trybie Computer Use.

Repozytorium
skills ↗
Licencja
MIT
Ostatnia zmiana repozytorium
21.10.2026

Ocena i bezpieczeństwo

100/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
5
Skrypty
4
Komentarze HTML
0
Adresy URL w SKILL.md
9
Przestarzałość

Brak sygnałów. Repozytorium zmienione 21.10.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co sprawdzić przed instalacją
  • 4 skrypty w paczce. Przejrzyj je przed instalacją, bo Claude może je uruchomić.

Skrypty: scripts/copy-to-clipboard.ts, scripts/export-tweets.ts, scripts/setup.ts, scripts/x-api.ts

Co robi i kiedy

Publikuje i usuwa tweety oraz eksportuje je do YAML na X, sterując przeglądarką Chrome w trybie Computer Use.

Wyzwalacze z opisu

post to Twittertweetshare on Xpost to Xdelete tweetexport tweetssave tweets
Oryginalny opis (EN)

Posts content, deletes tweets, or exports/saves tweets to YAML on X (Twitter) using Chrome Computer Use Mode. Use when user requests "post to Twitter", "tweet", "share on X", "post to X", "delete tweet", "export tweets", or "save tweets".

Jak działa

  1. Script Directory
  2. Execution Mode
  3. Regular Posts Workflow (Text & Images)
  4. CLI Bridge (No Computer Use Tools)
  5. JavaScript / DOM Automation Guidelines (Fallback)
  6. Delete Tweet Workflow
  7. Export Tweets Workflow
Sekcje z nagłówków SKILL.md, w oryginale · 313 linii, 1 673 słów
Podgląd SKILL.md
---
name: twitter
description: Posts content, deletes tweets, or exports/saves tweets to YAML on X (Twitter) using Chrome Computer Use Mode. Use when user requests "post to Twitter", "tweet", "share on X", "post to X", "delete tweet", "export tweets", or "save tweets".
version: 1.0.0
---

# Twitter Skill

Posts text and images to X (Twitter) via Chrome Computer Use Mode.

## Script Directory

**Important**: All scripts are located in the `scripts/` subdirectory of this skill.

**Agent Execution Instructions**:
1. Determine this SKILL.md file's directory path as `{baseDir}`
2. Script paths:
   - Setup / Initializer: `{baseDir}/scripts/setup.ts`
   - Clipboard helper: `{baseDir}/scripts/copy-to-clipboard.ts`
   - Tweet exporter/scraper: `{baseDir}/scripts/export-tweets.ts`
   - Official X API helper: `{baseDir}/scripts/x-api.ts`
3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun
4. Replace all `{baseDir}` and `${BUN_X}` in this document with actual values
5. **Initial Setup**: Run the setup script to automatically initialize configuration folders and template files:
   ```bash
   ${BUN_X} {baseDir}/scripts/setup.ts
   ```

## Execution Mode

This skill follows a **Hybrid Execution Model**:

1. **API First (Recommended for text posts)**: Attempt to post the tweet using the official X API script (`x-api.ts`). This is fast, stable, and uses no browser resources.
2. **Browser Fallback**: If the API call fails (e.g., monthly 1500-tweet Free tier quota exceeded, rate limit) or API credentials are not configured in `~/.config/skills/twitter.yaml`, fall back automatically to **Chrome Computer Use Mode** / **CLI Bridge** to simulate browser actions.

### Prerequisites
- **For API Mode**: Configure your X API credentials and state in your global `~/.config/skills/twitter.yaml` file:
  ```yaml
  x_api:
    api_key: "YOUR_API_KEY"
    api_key_secret: "YOUR_API_KEY_SECRET"
    access_token: "YOUR_ACCESS_TOKEN"
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET"

  state:
    use_api: true
    last_reset_month: "2026-06"
  ```

  #### X Developer Portal Setup Guide:
  1. Go to the [X Developer Portal](https://developer.twitter.com/en/portal/dashboard).
  2. Select your App under **Projects & Apps**.
  3. Under **User authentication settings**, click **Set up** (or **Edit**):
     - **App permissions**: Select **Read and write**.
     - **Type of App**: Select **Web App, Automated App or Bot**.
     - **Callback URI / Redirect URL**: Enter `https://127.0.0.1` (required placeholder).
     - **Website URL**: Enter your project URL, e.g. `https://github.com/hankunpeng/skills` (required placeholder).
     - Save the settings.
  4. Go to the **Keys and Tokens** tab:
     - Under **Consumer Keys**, copy or regenerate the **API Key** and **API Key Secret**.
     - Under **Access Token and Secret**, click **Regenerate** to obtain the **Access Token** and **Access Token Secret** (Note: tokens must be regenerated after changing permissions to activate write access).
  5. Copy these 4 credentials and paste them into `~/.config/skills/twitter.yaml`.

- **For Browser Fallback**: Google Chrome installed, logged into X (Twitter) in Chrome, and macOS accessibility permissions granted if required.

## Regular Posts Workflow (Text & Images)

When executing a post:

1. Start the agent turn by calling `get_app_state` (or equivalent tool) for `Google Chrome`.
2. Open or navigate Google Chrome to `https://x.com/compose/post`.
3. Locate the tweet composer input box.
4. Type the post text into the composer using Computer Use keyboard inputs.
5. If there are any images to attach (max 4):
   For each image:
   a. Run the clipboard helper script to copy the image to the clipboard:
      ```bash
      ${BUN_X} {baseDir}/scripts/copy-to-clipboard.ts image /absolute/path/to/image.png
      ```
   b. Paste the image into the composer using the paste shortcut (`super+v` on macOS, `control+v` on Windows/Linux).
   c. Wait 2-3 seconds until X finishes uploading the media.
6. **Publish Safety**: Never click `Publish`, `Post`, or any equivalent button to publish the tweet without getting explicit final confirmation from the user in the current conversation.
7. Once the user confirms, click the `Post` button to publish.
8. After publishing, **close the composer modal** so the UI doesn't stay stuck on the compose dialog. Use the close button or Escape:
   - **DOM Selector**: `[data-testid="app-bar-close"]` or `[aria-label="Close"]`
   - **Fallback**: dispatch an `Escape` keydown event
9. **Auto-Reload Feed (Optional)**: If the user has other tabs open to their profile (e.g., `x.com/[username]`) or home feed (`x.com/home`), reload them so the new tweet is visible immediately.

```javascript
var closeBtn = document.querySelector('[data-testid="app-bar-close"], [aria-label="Close"]');
if (closeBtn) { closeBtn.click(); }
else { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', keyCode: 27, which: 27, bubbles: true })); }
```

## CLI Bridge (No Computer Use Tools)

When the environment lacks Computer Use keyboard/mouse tools, use platform-specific methods to open Chrome and inject JavaScript into the page.

### macOS (AppleScript)

**Open compose page:**
```bash
open -a "Google Chrome" "https://x.com/compose/post"
```

**Execute JavaScript in Chrome** — write JS to a temp file first (avoids shell escaping issues), then run via AppleScript:

```bash
cat > /tmp/tweet.js << 'EOF'
(function() { /* your code */ })();
EOF

osascript -e '
tell application "Google Chrome"
    activate
    set js to read "/tmp/tweet.js"
    set result to execute front window'"'"'s active tab javascript js
    return result
end tell'
```

**Pattern**: Always write the JS payload to a temp file first. Do NOT attempt inline `osascript -e` with embedded JS — quote/escaping conflicts will cause parse errors.

**Close composer after publishing** (otherwise the modal stays open):
```javascript
var closeBtn = document.querySelector('[data-testid="app-bar-close"], [aria-label="Close"]');
if (closeBtn) { closeBtn.click(); }
else { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', keyCode: 27, which: 27, bubbles: true })); }
```

**Reload profile/home tabs to reflect the new post immediately (Optional)**:
```bash
osascript -e '
tell application "Google Chrome"
    tell window 1
        set tabList to every tab whose URL contains "x.com/hankunpeng" or URL contains "x.com/home"
        repeat with t in tabList
            reload t
        end repeat
    end tell
end tell'
```

### Linux

```bash
google-chrome "https://x.com/compose/post"
# Use chrome-remote-interface or similar CDP client to execute JS
```

### Windows

```powershell
Start-Process "chrome" "https://x.com/compose/post"
# Use CDP via --remote-debugging-port or PowerShell automation
```

## JavaScript / DOM Automation Guidelines (Fallback)

If direct Computer Use keyboard/mouse events are not available, or you are running in browser scripting/CDP modes, follow these guidelines to interact with X's React/Draft.js editor:

1. **Multiple Editor Detection**:
   X pages often contain multiple compose textareas (e.g., inline composer on home feed and active modal dialog). Always query all editors:
   ```javascript
   var els = document.querySelectorAll('[data-testid="tweetTextarea_0"]');
   var el = els.length > 1 ? els[els.length - 1] : els[0];
   ```
   Always target the active modal composer (usually the last element in the list).

2. **Binding Selection & Focus**:
   Before inserting text, you MUST click the element to trigger Draft.js selection binding, then focus:
   ```javascript
   el.click();
   el.focus();
   ```

3. **Preserving Editor Structure**:
   - **Do NOT** use `el.innerHTML = ''` or `document.execCommand('delete')` on an empty composer. Wiping the DOM nodes destroys Draft.js's internal wrapper structure (e.g., `public-DraftStyleDefault-block` span), which crashes the React component and leaves the Post button permanently disabled.
   - Simply use `document.execCommand('insertText', false, text)` directly into the empty focused editor.

4. **Triggering React State Updates**:
   After text insertion, dispatch a bubbled `input` event to notify React:
   ```javascript
   el.dispatchEvent(new Event('input', { bubbles: true }));
   ```

5. **Locating the Correct Post Button**:
   The button testids (`tweetButtonInline` and `tweetButton`) might be swapped depending on the context. Always scan for the visible, enabled button:
   ```javascript
   var btns = document.querySelectorAll('[data-testid="tweetButtonInline"], [data-testid="tweetButton"]');
   var activeBtn = Array.from(btns).find(function(btn) {
       var isVisible = btn.offsetWidth > 0 && btn.offsetHeight > 0;
       var isDisabled = btn.disabled || btn.getAttribute('aria-disabled') === 'true';
       return isVisible && !isDisabled;
   });
    if (activeBtn) activeBtn.click();
    ```

## Delete Tweet Workflow

When executing a deletion:

1. Open or navigate Google Chrome to the user's profile page (`https://x.com/[username]`) or the direct tweet URL (`https://x.com/[username]/status/[tweetId]`).
2. Search for the target tweet `<article>` container containing the text to delete.
3. Click the options menu button on the tweet:
   - **DOM Selector**: `[data-testid="caret"]`
4. Wait 1-2 seconds, then click the "Delete" menu item:
   - **DOM Selector**: A `[role="menuitem"]` element whose text contains "Delete" or "删除".
5. Wait 1-2 seconds, then click the confirmation delete button in the dialog sheet:
   - **DOM Selector**: `[data-testid="confirmationSheetConfirm"]` (or fallback to any dialog button with text "Delete" or "删除").

### CLI Bridge Example (macOS)

Use the same temp-file + AppleScript pattern as posting. Replace `TWEET_TEXT_HERE` with the target tweet content.

**Step 1 — Find tweet and click caret:**

```bash
cat > /tmp/del-1.js << 'EOF'
(function() {
  var articles = document.querySelectorAll('article');
  var target = null;
  var needle = 'TWEET_TEXT_HERE';
  for (var i = 0; i < articles.length; i++) {
    var textEl = articles[i].querySelector('[data-testid="tweetText"]');
    if (textEl && textEl.textContent.trim().indexOf(needle) !== -1) {
      target = articles[i];
      break;
    }
  }
  if (!target) return 'ERROR: tweet not found';
  var caret = target.querySelector('[data-testid="caret"]');
  if (!caret) return 'ERROR: caret not found';
  caret.click();
  return 'OK: caret clicked';
})();
EOF

osascript -e '
tell application "Google Chrome"
    set js to read "/tmp/del-1.js"
    set result to execute front window'"'"'s active tab javascript js
    return result
end tell'
```

**Step 2 — Click Delete menuitem** (wait 1-2s after step 1):

```bash
cat > /tmp/del-2.js << 'EOF'
(function() {
  var items = document.querySelectorAll('[role="menuitem"]');
  for (var i = 0; i < items.length; i++) {
    var txt = items[i].textContent.trim();
    if (txt === 'Delete' || txt === '删除') {
      // Click the menuitem itself, or if it contains a nested clickable element
      var clickTarget = items[i].querySelector('[role="menuitem"]') || items[i];
      clickTarget.click();
      return 'OK: delete clicked (index ' + i + ')';
    }
  }
  // Fallback: click the first menuitem (always "Delete" in the dropdown)
  var first = document.querySelectorAll('[role="menuitem"]')[0];
  if (first) { first.click(); return 'OK: first menuitem clicked'; }
  return 'ERROR: no menuitems';
})();
EOF

osascript -e '
tell application "Google Chrome"
    set js to read "/tmp/del-2.js"
    set result to execute front window'"'"'s active tab javascript js
    return result
end tell'
```

**Step 3 — Confirm deletion** (wait 1-2s after step 2):

```bash
cat > /tmp/del-3.js << 'EOF'
(function() {
  var confirmBtn = document.querySelector('[data-testid="confirmationSheetConfirm"]');
  if (!confirmBtn) {
    var buttons = document.querySelectorAll('[role="button"], button');
    for (var i = 0; i < buttons.length; i++) {
      var txt = buttons[i].textContent.trim();
      if (txt === 'Delete' || txt === '删除') {
        confirmBtn = buttons[i];
        break;
      }
    }
  }
  if (!confirmBtn) return 'ERROR: confirm button not found';
  confirmBtn.click();
  return 'OK: confirm clicked';
})();
EOF

osascript -e '
tell application "Google Chrome"
    set js to read "/tmp/del-3.js"
    set result to execute front window'"'"'s active tab javascript js
    return result
end tell'
```

## Export Tweets Workflow

To export/save all or filtered tweets from your profile page:

1. Run the exporter script:
   ```bash
   ${BUN_X} {baseDir}/scripts/export-tweets.ts [startDate] [endDate]
   ```
   *   **Optional Date Filters**: You can pass `startDate` (e.g. `2026-06-01`) and `endDate` (e.g. `2026-06-30`) to filter the output by date range. If omitted, all scraped tweets are exported.
   *   **Output File**: The tweets will be saved in `/Users/alex/twitter/twitter.yaml` where the tweet URL is the key, and the tweet text content is the value.

Pliki w paczce (5)
  • SKILL.md 13 KB
  • scripts/copy-to-clipboard.ts 12 KB
  • scripts/export-tweets.ts 6 KB
  • scripts/setup.ts 1 KB
  • scripts/x-api.ts 7 KB

Wersje

RepozytoriumWynikLicencja
Ta strona · hankunpeng/skills100MIT
vanducng/skills100MIT
ReScienceLab/opc-skills100Apache-2.0
baofeng-tech/agent-skills100MIT
tdimino/claude-code-minoan100MIT

Migawka bazy z 28.10.2026 · wersja paczki debcc20f1bf6 (skrót SHA-256 całej paczki)

Pobrania w ostatnich 30 dniach: 0 · ranking

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100twitter-cli
    Pobiera zakładki, wyszukuje tweety, czyta osie czasu i publikuje wpisy na X przez CLI, na podstawie ciasteczek sesji.
  • 100scraping-twitter-profile-tweets
    Wyciąga tweety, wątki odpowiedzi i wskaźniki zaangażowania z profilu na X dla wskazanego użytkownika.
  • 100x-content-creator
    Tworzy skuteczne treści na X: tweety, wątki, cytaty i strategie odpowiedzi.
  • 100scraping-tweets-from-account
    Pobiera wszystkie tweety, odpowiedzi i media z wybranego konta na X, np. do eksportu historii wpisów.
  • 100baoyu-post-to-x
    Publikuje wpisy i artykuły na X (Twitter), w tym posty z obrazami i wideo oraz długie artykuły z Markdown, przez rozszerzenie Chrome lub skrypty CDP.
  • 100x-tweet-search
    Pobiera tweety z X po zapytaniu, nazwie użytkownika lub adresie URL wraz z pełnymi danymi: tekst, autor, metryki zaangażowania, media i hashtagi.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.