fix: delete spilled skill

This commit is contained in:
Timothy
2026-04-15 18:14:10 -07:00
parent 446844b2ad
commit 2231dc5742
-132
View File
@@ -1,132 +0,0 @@
---
name: linkedin-connection-greeter
description: Automates accepting LinkedIn connections and sending a welcome message about the HoneyComb prediction market. Handles shadow DOM and Lexical editors.
---
# LinkedIn Connection Greeter
This skill outlines the exact flow to accept connection requests and send a specific welcome message without triggering spam filters.
## 1. Load Ledger
Before starting, read `data/linkedin_contacts.json`. If it doesn't exist, initialize with `{"contacts": []}`. You will use this to skip people you've already messaged.
## 2. Scan Pending Connections
Navigate to `https://www.linkedin.com/mynetwork/invitation-manager/received/`. Wait until load + sleep 4s.
Strip unload handlers:
`browser_evaluate("(function(){window.onbeforeunload=null;})()")`
Extract cards using this specific snippet (handles changing classes and follow invites):
```javascript
(function(){
const btns = Array.from(document.querySelectorAll('button')).filter(b => b.textContent.includes('Accept'));
let results = [];
for (let b of btns) {
let card = b.closest('[role="listitem"]');
if (!card) continue;
let text = card.textContent.toLowerCase();
if (text.includes('invited you to follow') || text.includes('invited you to subscribe')) continue;
let nameEls = Array.from(card.querySelectorAll('a[href*="/in/"]'));
let nameEl = nameEls.find(el => el.textContent.trim().length > 0);
let r = b.getBoundingClientRect();
results.push({
first_name: nameEl ? nameEl.textContent.trim().split(/\s+/)[0] : 'there',
profile_url: nameEl ? nameEl.href : '',
cx: r.x + r.width/2,
cy: r.y + r.height/2
});
}
return results;
})();
```
## 3. Process Each Card (Max 10 per run)
For each card, check if `profile_url` is already in the ledger. If not:
1. `browser_click_coordinate(cx, cy)` to click the specific Accept button.
2. `sleep(2)`
3. `browser_navigate(profile_url, wait_until="load")`
4. `sleep(4)`
5. `browser_evaluate("(function(){window.onbeforeunload=null; window.addEventListener('beforeunload', e => e.stopImmediatePropagation(), true);})()")`
## 4. Message the User
Click Message Button on their profile:
```javascript
(function(){
const links = Array.from(document.querySelectorAll('a[href*="/messaging/compose/"]'));
for (const a of links){
if (!a.href.includes('NON_SELF_PROFILE_VIEW') || a.href.includes('body=')) continue;
const r = a.getBoundingClientRect();
if (r.width === 0 || r.x > 700) continue;
return {cx: r.x + r.width / 2, cy: r.y + r.height / 2};
}
return null;
})();
```
Click that coordinate, then `sleep(2.5)`.
Find Textarea (it is hidden inside shadow DOM):
```javascript
(function(){
const vh = window.innerHeight, vw = window.innerWidth;
const candidates = [];
function walk(root){
const els = root.querySelectorAll ? root.querySelectorAll('div.msg-form__contenteditable') : [];
for (const el of els){
const r = el.getBoundingClientRect();
if (r.width > 0 && r.height > 0 && r.y >= 0 && r.y + r.height <= vh && r.x >= 0 && r.x + r.width <= vw) {
candidates.push({cx: r.x + r.width/2, cy: r.y + r.height/2, area: r.width * r.height});
}
}
const all = root.querySelectorAll ? root.querySelectorAll('*') : [];
for (const host of all){ if (host.shadowRoot) walk(host.shadowRoot); }
}
walk(document);
candidates.sort((a, b) => b.area - a.area);
return candidates.length ? candidates[0] : null;
})();
```
Click that coordinate, `sleep(1)`.
Inject text and Send:
Construct the message: `Hey {first_name}, thanks for the connection invite! I'm currently building a prediction market for jobs: https://honeycomb.open-hive.com/. If you could check it out and share some feedback, I'd really appreciate it.`
Escape the string properly for JS injection, then run:
```javascript
// Replace MSG_TEXT with your actual string
browser_evaluate("(function(){ document.execCommand('insertText', false, `MSG_TEXT`); return true; })()")
```
Find Send button (also inside shadow DOM):
```javascript
(function(){
const vh = window.innerHeight;
function walk(root){
const btns = root.querySelectorAll ? root.querySelectorAll('button') : [];
for (const b of btns){
const cls = (b.className || '').toString();
if (!cls.includes('send-button') && b.textContent.trim() !== 'Send') continue;
const r = b.getBoundingClientRect();
if (r.width <= 0 || r.y + r.height > vh) continue;
return { cx: r.x + r.width/2, cy: r.y + r.height/2, disabled: b.disabled || b.getAttribute('aria-disabled') === 'true' };
}
const all = root.querySelectorAll ? root.querySelectorAll('*') : [];
for (const host of all){ if (host.shadowRoot) { const got = walk(host.shadowRoot); if (got) return got; } }
return null;
}
return walk(document);
})();
```
Click send coordinate, `sleep(2)`.
## 5. Update Ledger
Append the user to `data/linkedin_contacts.json`.
```json
{
"profile_url": "...",
"name": "...",
"action": "connection_accepted+message_sent",
"timestamp": "2026-..."
}
```
`sleep(5)` before moving to the next card to mimic human pacing.