@acedatacloud/skills 2026.704.3 → 2026.704.4

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.704.3",
3
+ "version": "2026.704.4",
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,120 @@
1
+ ---
2
+ name: instagram
3
+ description: Publish images, videos, Reels or carousels to your Instagram professional account via the Instagram Content Publishing API, and read your own recent media. Use when the user wants to post to Instagram (photo / video / reel / carousel), cross-post a visual, or review their own Instagram posts. Instagram is image/video-only (no text-only posts). Auth uses an access token (BYOC). 支持 Instagram 图片 / 视频 / Reels / 轮播发布。
4
+ when_to_use: |
5
+ Trigger when the user wants to publish a photo, video, reel or carousel to
6
+ their Instagram professional (Business/Creator) account, or review their own
7
+ recent posts. Instagram only publishes image/video — there are no text-only
8
+ posts. Publishing posts as their real account — confirm caption + media first.
9
+ connections: [instagram]
10
+ allowed_tools: [Bash]
11
+ license: Apache-2.0
12
+ metadata:
13
+ author: acedatacloud
14
+ version: "1.0"
15
+ ---
16
+
17
+ Call the **Instagram Graph API** (`graph.facebook.com`) with `curl + jq`. The
18
+ connector injects `$INSTAGRAM_ACCESS_TOKEN` (a token with
19
+ `instagram_content_publish` + `pages_read_engagement`; a Facebook Page token or
20
+ an Instagram-Login user token) and optionally `$INSTAGRAM_IG_USER_ID`. Never echo them.
21
+
22
+ Instagram publishes only **images / videos / reels** to a **professional**
23
+ (Business or Creator) account linked to a Facebook Page. There are no text-only posts.
24
+
25
+ ### Resolve the Instagram account id
26
+
27
+ If `$INSTAGRAM_IG_USER_ID` is set, use it. Otherwise derive it from the linked Page:
28
+
29
+ ```bash
30
+ if [ -n "$INSTAGRAM_IG_USER_ID" ]; then
31
+ IGID="$INSTAGRAM_IG_USER_ID"
32
+ else
33
+ PAGE=$(curl -sS "https://graph.facebook.com/v21.0/me/accounts?access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.data[0].id')
34
+ IGID=$(curl -sS "https://graph.facebook.com/v21.0/$PAGE?fields=instagram_business_account&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r '.instagram_business_account.id')
35
+ fi
36
+ echo "ig_user_id=$IGID"
37
+ ```
38
+
39
+ Errors are JSON with `error.message` / `error.code` — show them verbatim.
40
+ `401` / `OAuthException` → token expired or missing scope; a null `IGID` → the
41
+ token isn't linked to a professional IG account / Page (see Gotchas). Reconnect if needed.
42
+
43
+ ## Publish a single image (two-step: create container → publish)
44
+
45
+ **Confirm the caption + image with the user first.** The `image_url` must be a
46
+ **public JPEG** URL (Instagram server-side cURLs it):
47
+
48
+ ```bash
49
+ CID=$(curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media" \
50
+ -d "image_url=https://cdn.acedata.cloud/xxxx.jpg" \
51
+ --data-urlencode "caption=One endpoint → posters, cards, mockups. #AI #API" \
52
+ -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .id)
53
+ echo "container=$CID"
54
+
55
+ curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media_publish" \
56
+ -d "creation_id=$CID" -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq .
57
+ # → {"id":"<IG_MEDIA_ID>"}
58
+ ```
59
+
60
+ Get the permalink to hand back to the user:
61
+
62
+ ```bash
63
+ curl -sS "https://graph.facebook.com/v21.0/<IG_MEDIA_ID>?fields=permalink&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .permalink
64
+ ```
65
+
66
+ ## Reels / video
67
+
68
+ Create with `media_type=REELS` + a public `video_url`, then **poll the container
69
+ status until FINISHED** before publishing (video processing takes time):
70
+
71
+ ```bash
72
+ CID=$(curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media" \
73
+ -d "media_type=REELS" -d "video_url=https://cdn.acedata.cloud/xxxx.mp4" \
74
+ --data-urlencode "caption=..." -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .id)
75
+
76
+ # poll until the video finishes processing (up to ~5 min) BEFORE publishing —
77
+ # publishing an IN_PROGRESS container is rejected:
78
+ for i in $(seq 1 60); do
79
+ ST=$(curl -sS "https://graph.facebook.com/v21.0/$CID?fields=status_code&access_token=$INSTAGRAM_ACCESS_TOKEN" | jq -r .status_code)
80
+ echo "status=$ST"; [ "$ST" = "FINISHED" ] && break
81
+ [ "$ST" = "ERROR" ] || [ "$ST" = "EXPIRED" ] && { echo "container failed: $ST"; break; }
82
+ sleep 5
83
+ done
84
+
85
+ curl -sS -X POST "https://graph.facebook.com/v21.0/$IGID/media_publish" \
86
+ -d "creation_id=$CID" -d "access_token=$INSTAGRAM_ACCESS_TOKEN" | jq .
87
+ ```
88
+
89
+ ## Carousel (2–10 items)
90
+
91
+ Create each child with `is_carousel_item=true`, then a `media_type=CAROUSEL`
92
+ container with `children=<ID1>,<ID2>,...` + `caption`, then publish the carousel id.
93
+
94
+ ## Gotchas
95
+
96
+ - **No text-only posts** — Instagram requires an image or video. Use a public
97
+ **JPEG** for images (PNG/other formats are rejected; extended JPEG like MPO/JPS too).
98
+ - **Professional account required** — a Business/Creator IG account linked to a
99
+ Facebook Page. If `instagram_business_account` is null, the account isn't a
100
+ professional account or isn't linked; the user must fix that in IG / Page settings.
101
+ - **Media must be a public URL** on a server Instagram can reach; local files
102
+ won't work. Host on cdn.acedata.cloud first.
103
+ - **Rate limit:** 100 API-published posts per 24h (a carousel counts as 1). Check
104
+ via `GET /$IGID/content_publishing_limit`.
105
+ - **Page Publishing Authorization (PPA):** some Pages must complete PPA before API
106
+ publishing works — surface the API error verbatim if it mentions PPA.
107
+ - API version: keep the `vXX.0` path current if you hit a version/deprecation error.
108
+
109
+ ## Record the output
110
+
111
+ After you successfully publish and obtain the live permalink, call the built-in
112
+ `publish_artifact` tool ONCE so the user can track it in **My Outputs**:
113
+
114
+ ```
115
+ publish_artifact(kind="image", channel="instagram", title="<title>", url="<the REAL permalink>", status="delivered")
116
+ ```
117
+
118
+ Use the real returned URL — never fabricate one. Call it once per published item,
119
+ only after delivery is confirmed; skip it (or use `status="failed"`) if publishing failed.
120
+ See `_shared/artifacts.md`.
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: threads
3
+ description: Publish text, image, video or carousel posts to your Threads (@threads) account via the official Threads API, and read your own recent posts. Use when the user wants to post to Threads, cross-post a short update / thread, attach an image or link, or review their own Threads posts. Auth uses a Threads access token (BYOC). 支持 Threads 文本 / 图片 / 视频 / 轮播发布与自有贴文读取。
4
+ when_to_use: |
5
+ Trigger when the user wants to publish a post to their Threads account or
6
+ review their own recent Threads posts. Threads is Meta's text-first social
7
+ app; the connector stores a Threads access token with threads_content_publish.
8
+ Posting publishes as their real account — confirm the text with the user first.
9
+ connections: [threads]
10
+ allowed_tools: [Bash]
11
+ license: Apache-2.0
12
+ metadata:
13
+ author: acedatacloud
14
+ version: "1.0"
15
+ ---
16
+
17
+ Call the **Threads API** (`graph.threads.net`) with `curl + jq`. The connector
18
+ injects one credential: `$THREADS_ACCESS_TOKEN` (a long-lived Threads access
19
+ token with the `threads_basic` + `threads_content_publish` scopes). Never echo it.
20
+
21
+ Resolve the caller's Threads user id once (every publish needs it):
22
+
23
+ ```bash
24
+ ME=$(curl -sS "https://graph.threads.net/v1.0/me?fields=id,username&access_token=$THREADS_ACCESS_TOKEN")
25
+ TID=$(echo "$ME" | jq -r .id)
26
+ echo "$ME" # {"id":"<THREADS_USER_ID>","username":"..."}
27
+ ```
28
+
29
+ Errors are JSON with `error.message` / `error.code` — show them verbatim.
30
+ `401` / `OAuthException` → the token expired or lacks scope; reconnect the
31
+ Threads connector.
32
+
33
+ ## Publish a post (two-step: create container → publish)
34
+
35
+ **Confirm the text with the user first** (it publishes as their real account).
36
+ Text ≤ **500 characters** (emoji counted as UTF-8 bytes).
37
+
38
+ Step 1 — create a media container. Text-only (guard the 500-byte limit first):
39
+
40
+ ```bash
41
+ TEXT="Shipping one API for AI images → posters, cards, mockups. https://platform.acedata.cloud #AI #API"
42
+ [ "$(printf %s "$TEXT" | wc -c)" -le 500 ] || { echo "text exceeds Threads 500-byte limit — shorten it"; }
43
+ CID=$(curl -sS -X POST "https://graph.threads.net/v1.0/$TID/threads" \
44
+ --data-urlencode "media_type=TEXT" \
45
+ --data-urlencode "text=$TEXT" \
46
+ -d "access_token=$THREADS_ACCESS_TOKEN" | jq -r .id)
47
+ echo "container=$CID"
48
+ ```
49
+
50
+ Image post — add `media_type=IMAGE` + a **public** `image_url` (Threads cURLs it
51
+ server-side, so it must be on a public server); video uses `media_type=VIDEO` + `video_url`:
52
+
53
+ ```bash
54
+ CID=$(curl -sS -X POST "https://graph.threads.net/v1.0/$TID/threads" \
55
+ --data-urlencode "media_type=IMAGE" \
56
+ -d "image_url=https://cdn.acedata.cloud/xxxx.jpg" \
57
+ --data-urlencode "text=caption here" \
58
+ -d "access_token=$THREADS_ACCESS_TOKEN" | jq -r .id)
59
+ ```
60
+
61
+ Step 2 — publish the container. **Text posts publish immediately; for IMAGE /
62
+ VIDEO / carousel containers you MUST wait ≥30s first** so Threads can
63
+ fetch/process the upload — publishing too early fails or returns no id:
64
+
65
+ ```bash
66
+ sleep 30 # REQUIRED for IMAGE / VIDEO / carousel; skip for TEXT-only posts
67
+ curl -sS -X POST "https://graph.threads.net/v1.0/$TID/threads_publish" \
68
+ -d "creation_id=$CID" -d "access_token=$THREADS_ACCESS_TOKEN" | jq .
69
+ # → {"id":"<THREADS_MEDIA_ID>"}
70
+ ```
71
+
72
+ If `threads_publish` returns no id, the container isn't ready yet — poll
73
+ `GET /v1.0/<CID>?fields=status&access_token=$THREADS_ACCESS_TOKEN` until
74
+ `status=FINISHED`, then retry publish.
75
+
76
+ Get the public URL of the published post and hand it to the user:
77
+
78
+ ```bash
79
+ curl -sS "https://graph.threads.net/v1.0/<THREADS_MEDIA_ID>?fields=id,permalink&access_token=$THREADS_ACCESS_TOKEN" | jq -r .permalink
80
+ ```
81
+
82
+ ## Carousel (2–20 items)
83
+
84
+ Create each child with `is_carousel_item=true`, then a `media_type=CAROUSEL`
85
+ container with `children=<ID1>,<ID2>,...`, then publish the carousel id. Links:
86
+ add `link_attachment=<URL>` (text-only posts, ≤5 links). Topic tag: `topic_tag=<TAG>`.
87
+
88
+ ## List my recent posts
89
+
90
+ ```bash
91
+ curl -sS "https://graph.threads.net/v1.0/$TID/threads?fields=id,text,permalink,timestamp&limit=20&access_token=$THREADS_ACCESS_TOKEN" | jq '.data'
92
+ ```
93
+
94
+ ## Gotchas
95
+
96
+ - **500-char limit**; emoji count as their UTF-8 byte length.
97
+ - **Media must be a public URL** — Threads server-side cURLs `image_url`/`video_url`;
98
+ local files won't work. Upload to a public host / cdn.acedata.cloud first.
99
+ - **Wait ~30s before publishing media** containers (text publishes instantly); if
100
+ `threads_publish` doesn't return an id, poll `GET /<container-id>?fields=status`.
101
+ - **Rate limit:** 250 published posts per 24h per profile (a carousel counts as 1).
102
+ - Threads tokens differ from Facebook/Instagram tokens — they come from the
103
+ Threads OAuth flow on `graph.threads.net`, not `graph.facebook.com`.
104
+
105
+ ## Record the output
106
+
107
+ After you successfully publish and obtain the live permalink, call the built-in
108
+ `publish_artifact` tool ONCE so the user can track it in **My Outputs**:
109
+
110
+ ```
111
+ publish_artifact(kind="message", channel="threads", title="<title>", url="<the REAL permalink>", status="delivered")
112
+ ```
113
+
114
+ Use the real returned URL — never fabricate one. Call it once per published item,
115
+ only after delivery is confirmed; skip it (or use `status="failed"`) if publishing failed.
116
+ See `_shared/artifacts.md`.