Loading...
Loading...
Compare original and translation side by side
Skill by ara.so — AI Agent Skills collection.
由ara.so提供的Skill — AI Agent技能合集。
undefinedundefinedundefinedundefinedgit clone https://github.com/LocoreMind/locoagent.git
cd locoagent
bun installgit clone https://github.com/LocoreMind/locoagent.git
cd locoagent
bun install.envundefined.envundefined
Alternative provider configurations:
```env
其他提供商配置示例:
```envundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefined/x-com open home timeline, like first 3 posts about AI
/x-com open home timeline, like first 3 posts about AI
/operation-log recent --limit 20
undefined/operation-log recent --limit 20
undefinedundefinedundefinedundefinedundefinedundefinedundefined/x-com open home timeline, like first 3 posts about AI, reply to the best one
/x-com open home timeline, like first 3 posts about AI, reply to the best one
Available X.com operations (32+):
- Navigation: home, notifications, messages, profile, search
- Engagement: like, retweet, reply, quote tweet
- Social graph: follow, unfollow, mute, block
- Content: post tweet, post thread, upload media
- Profile: edit bio, change avatar, update banner
- Lists: create, add members, view
可用的X.com操作(32+种):
- 导航:首页、通知、消息、个人主页、搜索
- 互动:点赞、转发、回复、引用转发
- 社交关系:关注、取消关注、静音、屏蔽
- 内容:发布推文、发布推文线程、上传媒体
- 个人资料:编辑简介、更换头像、更新横幅
- 列表:创建、添加成员、查看skills/linkedin/SKILL.md---
description: "LinkedIn platform operations playbook"
allowed-tools:
- Bash
user-invocable: true
---skills/linkedin/SKILL.md---
description: "LinkedIn platform operations playbook"
allowed-tools:
- Bash
user-invocable: true
---agent-browser open https://www.linkedin.com/feedagent-browser open https://www.linkedin.com/feedagent-browser open "https://www.linkedin.com/search/results/content/?keywords=AI%20agents"
agent-browser snapshot -i -c -s 'div[data-post-id]'agent-browser open "https://www.linkedin.com/search/results/content/?keywords=AI%20agents"
agent-browser snapshot -i -c -s 'div[data-post-id]'agent-browser snapshot -ibutton[aria-label*="Like"]agent-browser click @e<ref>agent-browser snapshot -ibutton[aria-label*="Like"]agent-browser click @e<ref>div[role="textbox"]agent-browser click @e<ref>agent-browser fill @e<ref> "Insightful post!"
Load the skill:
```bash
bun start
> /linkedin search for posts about 'AI safety', like top 3div[role="textbox"]agent-browser click @e<ref>agent-browser fill @e<ref> "Insightful post!"
加载技能:
```bash
bun start
> /linkedin search for posts about 'AI safety', like top 3undefinedundefinedundefinedundefinedworkflows/linkedin-engagement.json{
"id": "linkedin-engagement",
"name": "LinkedIn Daily Engagement",
"description": "Search for AI posts on LinkedIn and engage",
"schedule": "daily",
"executor": "executors/linkedin-engagement.ts",
"config": {
"searchQuery": "artificial intelligence",
"maxPosts": 5,
"cdpPort": 9222
}
}workflows/executors/linkedin-engagement.ts#!/usr/bin/env bun
import { execSync } from 'node:child_process'
// Parse config from workflow engine
const configArg = process.argv.find((_, i, a) => a[i - 1] === '--config')
const config = JSON.parse(configArg!)
// agent-browser helper
function ab(cmd: string): string {
return execSync(`agent-browser --cdp ${config.cdpPort} ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
// Helper to check operation log
function hasEngaged(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform linkedin --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
// Helper to log operation
function logOperation(postUrl: string, action: string, status: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform linkedin --action ${action} --url "${postUrl}" --status ${status} --note "${note}"`, {
encoding: 'utf-8',
stdio: 'inherit'
})
}
console.error('[linkedin-engagement] Starting workflow...')
// Step 1: Navigate to search
console.error(`[linkedin-engagement] Searching for: ${config.searchQuery}`)
const searchUrl = `https://www.linkedin.com/search/results/content/?keywords=${encodeURIComponent(config.searchQuery)}`
ab(`open "${searchUrl}"`)
ab('wait 3000')
// Step 2: Get posts
console.error('[linkedin-engagement] Getting posts...')
const snapshot = ab('snapshot -i -c -s \'div[data-post-id]\'')
const posts = JSON.parse(snapshot)
let engaged = 0
const stepsTotal = Math.min(posts.length, config.maxPosts)
// Step 3: Engage with posts
for (let i = 0; i < stepsTotal; i++) {
const post = posts[i]
const postUrl = post.attributes?.['data-urn'] || `post-${i}`
// Check if already engaged
if (hasEngaged(postUrl)) {
console.error(`[linkedin-engagement] Already engaged with ${postUrl}, skipping`)
continue
}
// Find like button
const likeButton = post.children?.find((el: any) =>
el.attributes?.['aria-label']?.includes('Like')
)
if (likeButton?.ref) {
ab(`click ${likeButton.ref}`)
logOperation(postUrl, 'like', 'success', `Workflow: ${config.searchQuery}`)
engaged++
console.error(`[linkedin-engagement] Liked post ${i + 1}/${stepsTotal}`)
ab('wait 2000') // Rate limiting
}
}
// Output final summary (required)
console.log(JSON.stringify({
stepsCompleted: engaged,
stepsTotal,
searchQuery: config.searchQuery
}))bun run workflow run --id linkedin-engagementworkflows/linkedin-engagement.json{
"id": "linkedin-engagement",
"name": "LinkedIn Daily Engagement",
"description": "Search for AI posts on LinkedIn and engage",
"schedule": "daily",
"executor": "executors/linkedin-engagement.ts",
"config": {
"searchQuery": "artificial intelligence",
"maxPosts": 5,
"cdpPort": 9222
}
}workflows/executors/linkedin-engagement.ts#!/usr/bin/env bun
import { execSync } from 'node:child_process'
// Parse config from workflow engine
const configArg = process.argv.find((_, i, a) => a[i - 1] === '--config')
const config = JSON.parse(configArg!)
// agent-browser helper
function ab(cmd: string): string {
return execSync(`agent-browser --cdp ${config.cdpPort} ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
// Helper to check operation log
function hasEngaged(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform linkedin --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
// Helper to log operation
function logOperation(postUrl: string, action: string, status: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform linkedin --action ${action} --url "${postUrl}" --status ${status} --note "${note}"`, {
encoding: 'utf-8',
stdio: 'inherit'
})
}
console.error('[linkedin-engagement] Starting workflow...')
// Step 1: Navigate to search
console.error(`[linkedin-engagement] Searching for: ${config.searchQuery}`)
const searchUrl = `https://www.linkedin.com/search/results/content/?keywords=${encodeURIComponent(config.searchQuery)}`
ab(`open "${searchUrl}"`)
ab('wait 3000')
// Step 2: Get posts
console.error('[linkedin-engagement] Getting posts...')
const snapshot = ab('snapshot -i -c -s \'div[data-post-id]\'')
const posts = JSON.parse(snapshot)
let engaged = 0
const stepsTotal = Math.min(posts.length, config.maxPosts)
// Step 3: Engage with posts
for (let i = 0; i < stepsTotal; i++) {
const post = posts[i]
const postUrl = post.attributes?.['data-urn'] || `post-${i}`
// Check if already engaged
if (hasEngaged(postUrl)) {
console.error(`[linkedin-engagement] Already engaged with ${postUrl}, skipping`)
continue
}
// Find like button
const likeButton = post.children?.find((el: any) =>
el.attributes?.['aria-label']?.includes('Like')
)
if (likeButton?.ref) {
ab(`click ${likeButton.ref}`)
logOperation(postUrl, 'like', 'success', `Workflow: ${config.searchQuery}`)
engaged++
console.error(`[linkedin-engagement] Liked post ${i + 1}/${stepsTotal}`)
ab('wait 2000') // Rate limiting
}
}
// Output final summary (required)
console.log(JSON.stringify({
stepsCompleted: engaged,
stepsTotal,
searchQuery: config.searchQuery
}))bun run workflow run --id linkedin-engagementimport { execSync } from 'node:child_process'
function hasLiked(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform x --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
const url = "https://x.com/user/status/123"
if (hasLiked(url)) {
console.log("Already liked this post")
} else {
// Perform like action
execSync(`agent-browser click @e5`)
// Log operation
execSync(`bun run scripts/log-operation.ts add --platform x --action like --url "${url}" --status success --note "AI research post"`)
}import { execSync } from 'node:child_process'
function hasLiked(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform x --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
const url = "https://x.com/user/status/123"
if (hasLiked(url)) {
console.log("Already liked this post")
} else {
// Perform like action
execSync(`agent-browser click @e5`)
// Log operation
execSync(`bun run scripts/log-operation.ts add --platform x --action like --url "${url}" --status success --note "AI research post"`)
}undefinedundefined
State stored in `persona/operation-log.json`.
状态存储在`persona/operation-log.json`中。persona/tasks.mdundefinedpersona/tasks.mdundefined| Action | Max per session |
|---|---|
| Likes | 10 |
| Comments | 2 |
| Follows | 5 |
| Posts | 1 |
undefined| Action | Max per session |
|---|---|
| Likes | 10 |
| Comments | 2 |
| Follows | 5 |
| Posts | 1 |
undefinedundefinedundefinedundefinedundefined--printundefined--printundefined
Output shows live execution:
Additional commands:
```bash
输出会显示实时执行过程:
其他命令:
```bashundefinedundefined#!/usr/bin/env bun
import { execSync } from 'node:child_process'
function ab(cmd: string): string {
return execSync(`agent-browser --cdp 9222 ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
function hasEngaged(platform: string, action: string, url: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform ${platform} --action ${action} --url "${url}"`, {
stdio: 'ignore'
})
return true
} catch {
return false
}
}
function logEngagement(platform: string, action: string, url: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform ${platform} --action ${action} --url "${url}" --status success --note "${note}"`, {
stdio: 'inherit'
})
}
// Navigate to page
ab('open https://x.com/search?q=AI%20agents&f=live')
ab('wait 3000')
// Get posts
const snapshot = JSON.parse(ab('snapshot -i -c -s \'article\''))
const posts = snapshot.slice(0, 5)
for (const post of posts) {
const postUrl = post.attributes?.['data-testid'] || `post-${Math.random()}`
// Skip if already engaged
if (hasEngaged('x', 'like', postUrl)) {
console.error(`Already liked ${postUrl}`)
continue
}
// Find like button
const likeBtn = post.children?.find((el: any) =>
el.attributes?.['data-testid'] === 'like'
)
if (likeBtn?.ref) {
ab(`click ${likeBtn.ref}`)
logEngagement('x', 'like', postUrl, 'AI agents search result')
ab('wait 2000') // Rate limiting
}
}#!/usr/bin/env bun
import { execSync } from 'node:child_process'
function ab(cmd: string): string {
return execSync(`agent-browser --cdp 9222 ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
function hasEngaged(platform: string, action: string, url: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform ${platform} --action ${action} --url "${url}"`, {
stdio: 'ignore'
})
return true
} catch {
return false
}
}
function logEngagement(platform: string, action: string, url: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform ${platform} --action ${action} --url "${url}" --status success --note "${note}"`, {
stdio: 'inherit'
})
}
// Navigate to page
ab('open https://x.com/search?q=AI%20agents&f=live')
ab('wait 3000')
// Get posts
const snapshot = JSON.parse(ab('snapshot -i -c -s \'article\''))
const posts = snapshot.slice(0, 5)
for (const post of posts) {
const postUrl = post.attributes?.['data-testid'] || `post-${Math.random()}`
// Skip if already engaged
if (hasEngaged('x', 'like', postUrl)) {
console.error(`Already liked ${postUrl}`)
continue
}
// Find like button
const likeBtn = post.children?.find((el: any) =>
el.attributes?.['data-testid'] === 'like'
)
if (likeBtn?.ref) {
ab(`click ${likeBtn.ref}`)
logEngagement('x', 'like', postUrl, 'AI agents search result')
ab('wait 2000') // Rate limiting
}
}#!/usr/bin/env bun
import { execSync } from 'node:child_process'
import { writeFileSync, readFileSync, existsSync } from 'fs'
const CHECKPOINT_FILE = '/tmp/workflow-checkpoint.json'
function loadCheckpoint(): any {
if (existsSync(CHECKPOINT_FILE)) {
return JSON.parse(readFileSync(CHECKPOINT_FILE, 'utf-8'))
}
return { step: 0, data: {} }
}
function saveCheckpoint(step: number, data: any) {
writeFileSync(CHECKPOINT_FILE, JSON.stringify({ step, data }))
}
const checkpoint = loadCheckpoint()
let currentStep = checkpoint.step
// Step 1: Fetch data
if (currentStep === 0) {
console.error('[workflow] Step 1: Fetching data...')
const data = { papers: ['paper1', 'paper2', 'paper3'] }
saveCheckpoint(1, data)
currentStep = 1
}
// Step 2: Process data
if (currentStep === 1) {
console.error('[workflow] Step 2: Processing data...')
const { data } = loadCheckpoint()
// Process papers
saveCheckpoint(2, { ...data, processed: true })
currentStep = 2
}
// Step 3: Post to social
if (currentStep === 2) {
console.error('[workflow] Step 3: Posting to social...')
const { data } = loadCheckpoint()
// Post each paper
saveCheckpoint(3, data)
currentStep = 3
}
// Cleanup checkpoint on success
if (existsSync(CHECKPOINT_FILE)) {
execSync(`rm ${CHECKPOINT_FILE}`)
}
console.log(JSON.stringify({ stepsCompleted: 3, stepsTotal: 3 }))#!/usr/bin/env bun
import { execSync } from 'node:child_process'
import { writeFileSync, readFileSync, existsSync } from 'fs'
const CHECKPOINT_FILE = '/tmp/workflow-checkpoint.json'
function loadCheckpoint(): any {
if (existsSync(CHECKPOINT_FILE)) {
return JSON.parse(readFileSync(CHECKPOINT_FILE, 'utf-8'))
}
return { step: 0, data: {} }
}
function saveCheckpoint(step: number, data: any) {
writeFileSync(CHECKPOINT_FILE, JSON.stringify({ step, data }))
}
const checkpoint = loadCheckpoint()
let currentStep = checkpoint.step
// Step 1: Fetch data
if (currentStep === 0) {
console.error('[workflow] Step 1: Fetching data...')
const data = { papers: ['paper1', 'paper2', 'paper3'] }
saveCheckpoint(1, data)
currentStep = 1
}
// Step 2: Process data
if (currentStep === 1) {
console.error('[workflow] Step 2: Processing data...')
const { data } = loadCheckpoint()
// Process papers
saveCheckpoint(2, { ...data, processed: true })
currentStep = 2
}
// Step 3: Post to social
if (currentStep === 2) {
console.error('[workflow] Step 3: Posting to social...')
const { data } = loadCheckpoint()
// Post each paper
saveCheckpoint(3, data)
currentStep = 3
}
// Cleanup checkpoint on success
if (existsSync(CHECKPOINT_FILE)) {
execSync(`rm ${CHECKPOINT_FILE}`)
}
console.log(JSON.stringify({ stepsCompleted: 3, stepsTotal: 3 }))undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefined