@acedatacloud/skills 2026.703.10 → 2026.703.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/bluesky/SKILL.md +147 -0
- package/skills/vk/SKILL.md +118 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acedatacloud/skills",
|
|
3
|
-
"version": "2026.703.
|
|
3
|
+
"version": "2026.703.12",
|
|
4
4
|
"description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bluesky
|
|
3
|
+
description: Publish, delete and read your own posts on Bluesky via the AT Protocol (XRPC). Use when the user wants to post to their Bluesky account, cross-post an article as a short dev-focused post, delete a post, or list their own recent posts with engagement stats (reposts, likes, replies). Auth uses the user's handle plus an App Password.
|
|
4
|
+
when_to_use: |
|
|
5
|
+
Trigger when the user wants to publish a post to their Bluesky account,
|
|
6
|
+
delete one, or review their own recent posts and engagement. Bluesky runs on
|
|
7
|
+
the AT Protocol: the connector stores the user's handle plus an App Password
|
|
8
|
+
(NOT the main account password) and a PDS service URL (default
|
|
9
|
+
https://bsky.social). Confirm the post text with the user before publishing.
|
|
10
|
+
connections: [bluesky]
|
|
11
|
+
allowed_tools: [Bash]
|
|
12
|
+
license: Apache-2.0
|
|
13
|
+
metadata:
|
|
14
|
+
author: acedatacloud
|
|
15
|
+
version: "1.0"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Call the **Bluesky AT Protocol** XRPC endpoints with `curl + jq`. Three
|
|
19
|
+
connector credentials are injected: `$BLUESKY_HANDLE` (e.g. `name.bsky.social`),
|
|
20
|
+
`$BLUESKY_APP_PASSWORD` (an App Password created in Bluesky **Settings →
|
|
21
|
+
Privacy and Security → App Passwords**, NOT the account login password) and
|
|
22
|
+
`$BLUESKY_SERVICE` (the PDS base URL, default `https://bsky.social`).
|
|
23
|
+
|
|
24
|
+
Errors come back as JSON `{"error":"<name>","message":"<detail>"}` — show it
|
|
25
|
+
verbatim. A `401 {"error":"AuthenticationRequired"}` on session creation means
|
|
26
|
+
the handle or App Password is wrong/revoked → the user must re-connect the
|
|
27
|
+
Bluesky connector (or generate a fresh App Password).
|
|
28
|
+
|
|
29
|
+
## Step 1 — always create a session first
|
|
30
|
+
|
|
31
|
+
Everything needs a short-lived `accessJwt` and your account `did`. Do this once
|
|
32
|
+
per task and reuse the values:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
SVC="${BLUESKY_SERVICE:-https://bsky.social}"
|
|
36
|
+
SESSION=$(curl -sS -X POST "$SVC/xrpc/com.atproto.server.createSession" \
|
|
37
|
+
-H "Content-Type: application/json" \
|
|
38
|
+
-d "$(jq -n --arg id "$BLUESKY_HANDLE" --arg pw "$BLUESKY_APP_PASSWORD" \
|
|
39
|
+
'{identifier:$id, password:$pw}')")
|
|
40
|
+
echo "$SESSION" | jq '{did, handle, active}'
|
|
41
|
+
JWT=$(echo "$SESSION" | jq -r .accessJwt)
|
|
42
|
+
DID=$(echo "$SESSION" | jq -r .did)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If `JWT` / `DID` are empty or `null`, print the raw `$SESSION` (it contains the
|
|
46
|
+
error) and stop — do not continue to post.
|
|
47
|
+
|
|
48
|
+
## Post to Bluesky
|
|
49
|
+
|
|
50
|
+
**Confirm the text with the user before posting.** Text is limited to **300
|
|
51
|
+
graphemes**; longer text → `400 {"error":"InvalidRequest"}`. `createdAt` must be
|
|
52
|
+
an ISO-8601 UTC timestamp.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
TEXT="Hello Bluesky 👋 shipping with the AT Protocol"
|
|
56
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
|
|
57
|
+
curl -sS -X POST "$SVC/xrpc/com.atproto.repo.createRecord" \
|
|
58
|
+
-H "Authorization: Bearer $JWT" \
|
|
59
|
+
-H "Content-Type: application/json" \
|
|
60
|
+
-d "$(jq -n --arg did "$DID" --arg text "$TEXT" --arg now "$NOW" \
|
|
61
|
+
'{repo:$did, collection:"app.bsky.feed.post",
|
|
62
|
+
record:{ "$type":"app.bsky.feed.post", text:$text, createdAt:$now, langs:["en"] }}')" \
|
|
63
|
+
| jq '{uri, cid}'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The returned `uri` looks like `at://did:plc:xxxx/app.bsky.feed.post/<rkey>`. The
|
|
67
|
+
public web URL is `https://bsky.app/profile/$BLUESKY_HANDLE/post/<rkey>` where
|
|
68
|
+
`<rkey>` is the last path segment of the `uri`.
|
|
69
|
+
|
|
70
|
+
### Clickable links, mentions and hashtags (facets)
|
|
71
|
+
|
|
72
|
+
Plain URLs/hashtags in `text` are shown but **not clickable** — Bluesky needs
|
|
73
|
+
`facets` with UTF-8 **byte** offsets. Add a hashtag link like this (byteStart/
|
|
74
|
+
byteEnd are byte indices into the UTF-8 text, not character indices):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# text = "New post about #ai" — "#ai" starts at byte 15, ends at byte 18
|
|
78
|
+
curl -sS -X POST "$SVC/xrpc/com.atproto.repo.createRecord" \
|
|
79
|
+
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
|
|
80
|
+
-d "$(jq -n --arg did "$DID" --arg now "$NOW" '
|
|
81
|
+
{repo:$did, collection:"app.bsky.feed.post",
|
|
82
|
+
record:{ "$type":"app.bsky.feed.post", text:"New post about #ai", createdAt:$now,
|
|
83
|
+
facets:[ { index:{byteStart:15, byteEnd:18},
|
|
84
|
+
features:[{ "$type":"app.bsky.richtext.facet#tag", tag:"ai" }] } ] }}')" \
|
|
85
|
+
| jq '{uri, cid}'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For a link, use feature `app.bsky.richtext.facet#link` with a `uri` field; for a
|
|
89
|
+
mention, `app.bsky.richtext.facet#mention` with a `did`. Compute byte offsets
|
|
90
|
+
with e.g. `printf '%s' "$prefix" | wc -c`.
|
|
91
|
+
|
|
92
|
+
## List my recent posts + engagement
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
curl -sS "$SVC/xrpc/app.bsky.feed.getAuthorFeed?actor=$DID&limit=20&filter=posts_no_replies" \
|
|
96
|
+
-H "Authorization: Bearer $JWT" \
|
|
97
|
+
| jq '.feed[] | {uri: .post.uri,
|
|
98
|
+
text: .post.record.text,
|
|
99
|
+
reposts: .post.repostCount,
|
|
100
|
+
likes: .post.likeCount,
|
|
101
|
+
replies: .post.replyCount,
|
|
102
|
+
at: .post.indexedAt}'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`limit` max 100. `filter` options: `posts_with_replies`, `posts_no_replies`,
|
|
106
|
+
`posts_with_media`, `posts_and_author_threads`.
|
|
107
|
+
|
|
108
|
+
## Delete a post
|
|
109
|
+
|
|
110
|
+
`deleteRecord` needs the `rkey` (the last path segment of the post `uri`):
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
POST_URI="at://$DID/app.bsky.feed.post/3kabc123xyz"
|
|
114
|
+
RKEY="${POST_URI##*/}"
|
|
115
|
+
curl -sS -X POST "$SVC/xrpc/com.atproto.repo.deleteRecord" \
|
|
116
|
+
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
|
|
117
|
+
-d "$(jq -n --arg did "$DID" --arg rkey "$RKEY" \
|
|
118
|
+
'{repo:$did, collection:"app.bsky.feed.post", rkey:$rkey}')" \
|
|
119
|
+
| jq '{deleted: true, rkey: "'"$RKEY"'"}'
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
An empty `{}` response is success. `400 {"error":"InvalidRequest"}` usually
|
|
123
|
+
means the record is already gone or the `rkey` is wrong.
|
|
124
|
+
|
|
125
|
+
## Attaching images (optional)
|
|
126
|
+
|
|
127
|
+
Upload each image via `POST $SVC/xrpc/com.atproto.repo.uploadBlob`
|
|
128
|
+
(`Content-Type: image/jpeg`, raw bytes body, Bearer `$JWT`) → returns a `blob`
|
|
129
|
+
object. Then set `record.embed` to
|
|
130
|
+
`{ "$type":"app.bsky.embed.images", images:[{ alt:"<desc>", image:<blob> }] }`.
|
|
131
|
+
Max 4 images per post; each blob ≲ 1 MB (resize/compress first).
|
|
132
|
+
|
|
133
|
+
## Gotchas
|
|
134
|
+
|
|
135
|
+
- **App Password, not account password:** creating a session with the real
|
|
136
|
+
login password may be rejected or trip 2FA. Always the App Password from
|
|
137
|
+
Settings → App Passwords.
|
|
138
|
+
- **Byte offsets, not char offsets:** facet `byteStart`/`byteEnd` are UTF-8
|
|
139
|
+
byte indices — emoji and CJK take multiple bytes. Get them wrong and the
|
|
140
|
+
link highlights the wrong span.
|
|
141
|
+
- **300 graphemes**, counted as user-perceived characters (emoji = 1).
|
|
142
|
+
- **Rate limits:** the PDS rate-limits writes per account; space out bulk posts
|
|
143
|
+
or you'll get `429 {"error":"RateLimitExceeded"}`.
|
|
144
|
+
- **Self-hosted PDS:** if the user runs their own PDS, `$BLUESKY_SERVICE` points
|
|
145
|
+
there; all XRPC calls target that host, not `bsky.social`.
|
|
146
|
+
- The `accessJwt` is short-lived (~2h). For a single task it's fine; if it
|
|
147
|
+
expires mid-task, just re-run Step 1.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vk
|
|
3
|
+
description: Publish posts to your VK (ВКонтакте) profile or community wall and read your own recent posts, via the official VK API (wall.post / wall.get). Use when the user wants to post to VK, cross-post an article for a Russian-speaking audience, or list their own recent VK wall posts with engagement. Auth uses a VK access token (community access key recommended).
|
|
4
|
+
when_to_use: |
|
|
5
|
+
Trigger when the user wants to publish content to their VK wall or community,
|
|
6
|
+
or review their own recent VK posts. VK's user-token OAuth flows were disabled
|
|
7
|
+
in June 2024, so the connector stores a long-lived **community access key**
|
|
8
|
+
(VK community → Manage → Settings → API usage, with the `wall` right). Posting
|
|
9
|
+
to a community wall uses a negative owner_id + from_group=1. Confirm the post
|
|
10
|
+
text with the user before publishing.
|
|
11
|
+
connections: [vk]
|
|
12
|
+
allowed_tools: [Bash]
|
|
13
|
+
license: Apache-2.0
|
|
14
|
+
metadata:
|
|
15
|
+
author: acedatacloud
|
|
16
|
+
version: "1.0"
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
Call the **VK API** with `curl + jq`. The token is injected as `$VK_ACCESS_TOKEN`
|
|
20
|
+
and is passed in the `Authorization: Bearer` header. **Every** VK API call also
|
|
21
|
+
requires the `v` (API version) query parameter — use `v=5.199`. Base URL:
|
|
22
|
+
`https://api.vk.com/method/<method>`.
|
|
23
|
+
|
|
24
|
+
VK always returns HTTP 200; success is `{"response": ...}` and failure is
|
|
25
|
+
`{"error":{"error_code":<n>,"error_msg":"<detail>"}}` — always check for `.error`
|
|
26
|
+
and show `error_msg` verbatim. Common codes: `5` = auth failed (token wrong or
|
|
27
|
+
revoked → user must re-connect the VK connector), `214` = access to adding post
|
|
28
|
+
denied (the token lacks the `wall` right — a community access key with `wall` is
|
|
29
|
+
required), `15`/`203` = access denied to that owner.
|
|
30
|
+
|
|
31
|
+
## Step 1 — identify who you can post as
|
|
32
|
+
|
|
33
|
+
A **community access key** posts on the community wall: `owner_id` must be the
|
|
34
|
+
**negative** community id and you pass `from_group=1`. Resolve the community id
|
|
35
|
+
from the token:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
curl -sS "https://api.vk.com/method/groups.getById?v=5.199" \
|
|
39
|
+
-H "Authorization: Bearer $VK_ACCESS_TOKEN" \
|
|
40
|
+
| jq '.response, .error'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Take the group `id` (e.g. `123456`) → `owner_id` is `-123456`. (For a personal
|
|
44
|
+
user token, `owner_id` is your positive user id from `users.get`, and you omit
|
|
45
|
+
`from_group`.)
|
|
46
|
+
|
|
47
|
+
## Post to the wall
|
|
48
|
+
|
|
49
|
+
**Confirm the message text with the user before posting.** The post must have
|
|
50
|
+
text and/or attachments.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
OWNER_ID="-123456" # negative = community; from_group=1 posts as the community
|
|
54
|
+
MSG="Пример поста через VK API. #ai"
|
|
55
|
+
curl -sS -G "https://api.vk.com/method/wall.post" \
|
|
56
|
+
-H "Authorization: Bearer $VK_ACCESS_TOKEN" \
|
|
57
|
+
--data-urlencode "v=5.199" \
|
|
58
|
+
--data-urlencode "owner_id=$OWNER_ID" \
|
|
59
|
+
--data-urlencode "from_group=1" \
|
|
60
|
+
--data-urlencode "message=$MSG" \
|
|
61
|
+
| jq '.response, .error'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Success returns `{"response":{"post_id":<id>}}`. The public URL is
|
|
65
|
+
`https://vk.com/wall<OWNER_ID>_<post_id>` (e.g. `https://vk.com/wall-123456_17`).
|
|
66
|
+
|
|
67
|
+
- Hashtags (`#tag`) and plain URLs in `message` are rendered/clickable natively —
|
|
68
|
+
no facet/offset handling needed (unlike Bluesky).
|
|
69
|
+
- Attach media/links with `attachments` (comma-separated), format
|
|
70
|
+
`{type}{owner_id}_{media_id}` (e.g. `photo-123456_789`) or a single external
|
|
71
|
+
URL. Only **one** link may be attached; more than one link → error 222.
|
|
72
|
+
- `publish_date` (Unix timestamp) schedules a deferred post.
|
|
73
|
+
- Always send Cyrillic `message` via `--data-urlencode` so it isn't mangled.
|
|
74
|
+
|
|
75
|
+
## List my recent wall posts + engagement
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
OWNER_ID="-123456"
|
|
79
|
+
curl -sS -G "https://api.vk.com/method/wall.get" \
|
|
80
|
+
-H "Authorization: Bearer $VK_ACCESS_TOKEN" \
|
|
81
|
+
--data-urlencode "v=5.199" \
|
|
82
|
+
--data-urlencode "owner_id=$OWNER_ID" \
|
|
83
|
+
--data-urlencode "count=20" \
|
|
84
|
+
| jq '.error, (.response.items[]? | {id,
|
|
85
|
+
text,
|
|
86
|
+
likes: .likes.count,
|
|
87
|
+
reposts: .reposts.count,
|
|
88
|
+
comments: .comments.count,
|
|
89
|
+
views: .views.count,
|
|
90
|
+
date})'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`count` max 100. Combine `owner_id` + a post `id` to build the URL
|
|
94
|
+
`https://vk.com/wall<owner_id>_<id>`.
|
|
95
|
+
|
|
96
|
+
## Delete a post
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
OWNER_ID="-123456"; POST_ID="17"
|
|
100
|
+
curl -sS -G "https://api.vk.com/method/wall.delete" \
|
|
101
|
+
-H "Authorization: Bearer $VK_ACCESS_TOKEN" \
|
|
102
|
+
--data-urlencode "v=5.199" \
|
|
103
|
+
--data-urlencode "owner_id=$OWNER_ID" \
|
|
104
|
+
--data-urlencode "post_id=$POST_ID" \
|
|
105
|
+
| jq '.response, .error'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Gotchas
|
|
109
|
+
|
|
110
|
+
- **`v` is mandatory** on every call — omitting it returns an error.
|
|
111
|
+
- **User tokens can't be freshly minted via OAuth** (Implicit / Authorization
|
|
112
|
+
Code flows for user tokens were disabled 2024-06); use a **community access
|
|
113
|
+
key** (unlimited lifetime, created in the community's API settings) with the
|
|
114
|
+
`wall` right.
|
|
115
|
+
- Posting as the community requires both `owner_id` negative **and**
|
|
116
|
+
`from_group=1`.
|
|
117
|
+
- Rate/anti-spam: repeated identical posts or too-frequent posting can hit codes
|
|
118
|
+
like `214`/`219` — space posts out.
|