@acedatacloud/skills 2026.703.9 → 2026.703.11

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acedatacloud/skills",
3
- "version": "2026.703.9",
3
+ "version": "2026.703.11",
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,103 @@
1
+ ---
2
+ name: mastodon
3
+ description: Publish, delete and read your own posts (toots) on any Mastodon instance via the Mastodon REST API. Use when the user wants to post a toot to their Mastodon / fediverse account, cross-post an article as a short dev-focused post, delete a toot, or list their own recent posts with engagement stats (boosts, favourites, replies).
4
+ when_to_use: |
5
+ Trigger when the user wants to publish a status/toot to their Mastodon
6
+ account, delete one, or review their own recent posts and engagement.
7
+ Mastodon is federated: the connector stores the instance base URL plus a
8
+ personal access token, so every call targets the user's own instance.
9
+ Confirm visibility (public/unlisted) before posting publicly.
10
+ connections: [mastodon]
11
+ allowed_tools: [Bash]
12
+ license: Apache-2.0
13
+ metadata:
14
+ author: acedatacloud
15
+ version: "1.0"
16
+ ---
17
+
18
+ Call the **Mastodon REST API** with `curl + jq`. Two connector credentials are
19
+ injected: `$MASTODON_BASE_URL` (the instance, e.g. `https://mastodon.social`)
20
+ and `$MASTODON_ACCESS_TOKEN`. Every request sends the header
21
+ `Authorization: Bearer $MASTODON_ACCESS_TOKEN`.
22
+
23
+ Errors come back as JSON `{"error":"<message>"}` — show it verbatim. `401`
24
+ (`"The access token is invalid"`) means the token is wrong/revoked → the user
25
+ must re-connect the Mastodon connector. Posting needs the token to have the
26
+ `write` (or `write:statuses`) scope.
27
+
28
+ **Always confirm the token + account first** (also gives the account `id` you
29
+ need to list your own toots):
30
+
31
+ ```bash
32
+ curl -sS "$MASTODON_BASE_URL/api/v1/accounts/verify_credentials" \
33
+ -H "Authorization: Bearer $MASTODON_ACCESS_TOKEN" \
34
+ | jq '{id, username, acct, display_name, followers: .followers_count, statuses: .statuses_count}'
35
+ ```
36
+
37
+ ## Post a toot
38
+
39
+ **Confirm with the user before posting publicly.** Default `visibility` to
40
+ `unlisted` unless they say post publicly; use `public` only on request.
41
+
42
+ ```bash
43
+ STATUS_TEXT="Hello fediverse 👋 #introductions"
44
+ curl -sS -X POST "$MASTODON_BASE_URL/api/v1/statuses" \
45
+ -H "Authorization: Bearer $MASTODON_ACCESS_TOKEN" \
46
+ -H "Idempotency-Key: $(uuidgen)" \
47
+ --data-urlencode "status=$STATUS_TEXT" \
48
+ --data-urlencode "visibility=unlisted" \
49
+ --data-urlencode "language=en" \
50
+ | jq '{id, url, visibility, created_at}'
51
+ ```
52
+
53
+ - `visibility` is one of `public`, `unlisted`, `private`, `direct`.
54
+ - Optional params: `spoiler_text` (content warning), `in_reply_to_id` (reply),
55
+ `sensitive=true`, `language` (ISO 639-1).
56
+ - `Idempotency-Key` (any unique string; `uuidgen` here) prevents duplicate
57
+ posts if the request is retried within ~1h. Use `--data-urlencode` so
58
+ hashtags, emoji and newlines in the text are encoded correctly.
59
+ - Default post length is 500 chars (instance-configurable); longer text →
60
+ `422 {"error":"Validation failed: Text ..."}`.
61
+
62
+ ## List my recent toots + engagement
63
+
64
+ Use the `id` from `verify_credentials`:
65
+
66
+ ```bash
67
+ ACCT_ID="14715" # from verify_credentials
68
+ curl -sS "$MASTODON_BASE_URL/api/v1/accounts/$ACCT_ID/statuses?limit=20&exclude_replies=true&exclude_reblogs=true" \
69
+ -H "Authorization: Bearer $MASTODON_ACCESS_TOKEN" \
70
+ | jq '.[] | {id, url, boosts: .reblogs_count, favs: .favourites_count, replies: .replies_count, created_at}'
71
+ ```
72
+
73
+ `limit` max 40. Other filters: `only_media`, `pinned`, `tagged=<hashtag>`.
74
+
75
+ ## Delete a toot
76
+
77
+ ```bash
78
+ curl -sS -X DELETE "$MASTODON_BASE_URL/api/v1/statuses/STATUS_ID" \
79
+ -H "Authorization: Bearer $MASTODON_ACCESS_TOKEN" | jq '{id, deleted: true}'
80
+ ```
81
+
82
+ Deleting returns the status with its source `text` so you can delete-and-redraft.
83
+ `404 {"error":"Record not found"}` = not yours or already gone.
84
+
85
+ ## Attaching media (optional)
86
+
87
+ Upload each image/video via `POST $MASTODON_BASE_URL/api/v2/media`
88
+ (`multipart/form-data`, field `file`) to get a media id, then pass the ids as
89
+ `media_ids[]` when posting the status. See the docs for the full media contract:
90
+ https://docs.joinmastodon.org/methods/media/
91
+
92
+ ## Gotchas
93
+
94
+ - **Federated:** the API only ever targets `$MASTODON_BASE_URL` (the user's own
95
+ instance). There is no global endpoint — a token from instance A won't work
96
+ on instance B.
97
+ - **Scopes:** reading needs `read` (or `read:accounts`/`read:statuses`);
98
+ posting/deleting needs `write` (or `write:statuses`). A `403`
99
+ (`"This action is outside the authorized scopes"`) means the token lacks a scope.
100
+ - **Rate limits:** Mastodon rate-limits per token; space out bulk posts or you'll
101
+ get `429`.
102
+ - `verify_credentials` returns HTML in fields like `note`; the plaintext source
103
+ lives under the `source` object.