|
| 1 | +--- |
| 2 | +name: x-like-notifications |
| 3 | +description: Like selected unliked notifications on X (Twitter) through ai-chrome-pilot. Use when the user wants to open X notifications, identify reply or quote repost notifications, filter them by explicit criteria such as type, actor, text, date, or limit, and click like only on the matching items while avoiding accidental likes. |
| 4 | +--- |
| 5 | + |
| 6 | +# X Like Notifications |
| 7 | + |
| 8 | +Use ai-chrome-pilot to inspect X notifications, build a candidate list, and like only the notifications that match the user's criteria. |
| 9 | + |
| 10 | +Keep the skill profile-agnostic. Ask for the profile name at runtime instead of hardcoding any specific profile. |
| 11 | + |
| 12 | +Use this skill for action-taking. If the user only wants to inspect notifications first, use `x-get-notifications` instead. |
| 13 | + |
| 14 | +## Prerequisites |
| 15 | + |
| 16 | +- ai-chrome-pilot server is available in the current repo |
| 17 | +- Google Chrome is installed |
| 18 | +- The user is already logged in to X in the chosen Chrome profile |
| 19 | +- The UI is expected to be Japanese; match labels such as `すべて`, `@ツイート`, `いいねする`, and `いいねしました` |
| 20 | + |
| 21 | +If X shows a login screen, stop and use `x-login` first. |
| 22 | + |
| 23 | +## Inputs To Confirm |
| 24 | + |
| 25 | +Confirm these before acting: |
| 26 | + |
| 27 | +- `profile_name`: default to `default` if the user did not specify |
| 28 | +- `types`: `reply`, `quote`, or both |
| 29 | +- `filters`: actor handle/name, text substring, date substring, and optional limit |
| 30 | +- `mode`: `dry-run` or `execute` |
| 31 | + |
| 32 | +If the user says only "like notifications" without enough detail, default to `dry-run` and present candidates first instead of clicking anything. |
| 33 | + |
| 34 | +Recommended decision rule: |
| 35 | + |
| 36 | +- Use `x-get-notifications` for read-only collection and review |
| 37 | +- Use `x-like-notifications` only after the user has supplied clear like conditions |
| 38 | + |
| 39 | +## Workflow |
| 40 | + |
| 41 | +### 1. Ensure the server is running |
| 42 | + |
| 43 | +Check health: |
| 44 | + |
| 45 | +```bash |
| 46 | +curl -s http://127.0.0.1:3333/health |
| 47 | +``` |
| 48 | + |
| 49 | +If not running, start it with the requested profile: |
| 50 | + |
| 51 | +```bash |
| 52 | +HEADLESS=0 PROFILE_NAME=<profile_name> npx tsx src/index.ts |
| 53 | +``` |
| 54 | + |
| 55 | +### 2. Open notifications |
| 56 | + |
| 57 | +Navigate to notifications and wait for rendering: |
| 58 | + |
| 59 | +```bash |
| 60 | +curl -s -X POST http://127.0.0.1:3333/goto \ |
| 61 | + -H 'Content-Type: application/json' \ |
| 62 | + -d '{"url":"https://x.com/notifications"}' |
| 63 | +sleep 2 |
| 64 | +``` |
| 65 | + |
| 66 | +Take a screenshot to confirm the user is logged in and the page loaded: |
| 67 | + |
| 68 | +```bash |
| 69 | +curl -s http://127.0.0.1:3333/screenshot -o /tmp/x_notifications.png |
| 70 | +``` |
| 71 | + |
| 72 | +### 3. Inspect both notification tabs |
| 73 | + |
| 74 | +Check both: |
| 75 | + |
| 76 | +- `すべて`: quote reposts often appear here |
| 77 | +- `@ツイート`: replies often appear here |
| 78 | + |
| 79 | +Before any click, take a fresh `/snapshot` and use fresh refs from that snapshot only. |
| 80 | + |
| 81 | +If the needed tab is not active, click the corresponding tab ref, then wait briefly and take another `/snapshot`. |
| 82 | + |
| 83 | +### 4. Collect candidate notifications |
| 84 | + |
| 85 | +Use `/snapshot` and limited scrolling to gather visible notifications. Repeat 2-3 times when needed: |
| 86 | + |
| 87 | +```bash |
| 88 | +curl -s http://127.0.0.1:3333/snapshot |
| 89 | +curl -s -X POST http://127.0.0.1:3333/eval \ |
| 90 | + -H 'Content-Type: application/json' \ |
| 91 | + -d '{"js":"window.scrollBy(0, window.innerHeight * 2)"}' |
| 92 | +sleep 1 |
| 93 | +``` |
| 94 | + |
| 95 | +Normalize each candidate with: |
| 96 | + |
| 97 | +- `tab`: `all` or `mentions` |
| 98 | +- `type`: `reply` if it contains `返信先:`, `quote` if it contains `引用` |
| 99 | +- `actor`: display name and handle when visible |
| 100 | +- `date`: visible date text such as `3月3日` |
| 101 | +- `notification_text`: reply or quote text |
| 102 | +- `original_post_text`: quoted or replied-to post text when visible |
| 103 | +- `like_ref`: ref of the like button in the same article |
| 104 | +- `like_state`: `liked` if the button says `いいねしました`, `unliked` if it says `いいねする` |
| 105 | + |
| 106 | +Ignore likes, follows, reposts, and any article that cannot be matched confidently to a like button. |
| 107 | + |
| 108 | +### 5. Apply filters conservatively |
| 109 | + |
| 110 | +Only keep candidates that satisfy all user-specified filters. |
| 111 | + |
| 112 | +Useful filter patterns: |
| 113 | + |
| 114 | +- `types=reply` |
| 115 | +- `types=quote` |
| 116 | +- `actor contains @shinshin86` |
| 117 | +- `text contains ひな祭り` |
| 118 | +- `date contains 3月1日` |
| 119 | +- `limit=2` |
| 120 | + |
| 121 | +If multiple candidates still match and the user asked for one specific item, stop and show the narrowed list instead of clicking. |
| 122 | + |
| 123 | +If no explicit filters were supplied, propose a candidate list grouped by reply and quote, then wait for confirmation unless the user clearly asked to like all unliked matches of a broad class such as "all replies". |
| 124 | + |
| 125 | +### 6. Execute likes |
| 126 | + |
| 127 | +In `dry-run` mode, do not click anything. Return the matched candidates with enough detail for the user to confirm. |
| 128 | + |
| 129 | +In `execute` mode: |
| 130 | + |
| 131 | +1. Click only candidates whose `like_state` is `unliked` |
| 132 | +2. Click the `like_ref`, not a surrounding article or link |
| 133 | +3. Wait `1` second after each click |
| 134 | +4. Refresh `/snapshot` before the next click |
| 135 | +5. Stop immediately if the page state becomes ambiguous |
| 136 | + |
| 137 | +Example: |
| 138 | + |
| 139 | +```bash |
| 140 | +curl -s -X POST http://127.0.0.1:3333/act \ |
| 141 | + -H 'Content-Type: application/json' \ |
| 142 | + -d '{"ref":"<like_ref>","action":"click"}' |
| 143 | +sleep 1 |
| 144 | +``` |
| 145 | + |
| 146 | +### 7. Verify and report |
| 147 | + |
| 148 | +After clicking, verify by taking a new `/snapshot` or screenshot when possible. |
| 149 | + |
| 150 | +Report: |
| 151 | + |
| 152 | +- which candidates matched |
| 153 | +- which ones were already liked and skipped |
| 154 | +- which refs were clicked |
| 155 | +- any verification gaps or transient connection errors |
| 156 | + |
| 157 | +## Safety Rules |
| 158 | + |
| 159 | +- Never hardcode a profile name |
| 160 | +- Never like anything if the matching logic is ambiguous |
| 161 | +- Prefer `dry-run` first unless the user clearly requested execution |
| 162 | +- Use fresh refs from the latest `/snapshot`; do not reuse stale refs after scrolling or clicking |
| 163 | +- Check both tabs before saying there are no matches |
| 164 | +- If `Browser connection is closed` or `CDP client is not connected` appears, restart the server and re-verify |
| 165 | +- If X appears in a non-Japanese locale, adapt the label matching before clicking |
| 166 | + |
| 167 | +## Output Format |
| 168 | + |
| 169 | +When reporting candidates in `dry-run`, include: |
| 170 | + |
| 171 | +- `type` |
| 172 | +- `actor` |
| 173 | +- `date` |
| 174 | +- `notification_text` |
| 175 | +- `original_post_text` when visible |
| 176 | +- `like_state` |
| 177 | +- why the item matched the filters |
| 178 | + |
| 179 | +When reporting `execute`, include: |
| 180 | + |
| 181 | +- clicked items |
| 182 | +- skipped items already liked |
| 183 | +- items excluded by filters |
| 184 | +- any verification gap |
0 commit comments