@acedatacloud/skills 2026.707.0 → 2026.712.1
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/hashnode/SKILL.md +29 -9
- package/skills/x/scripts/x.py +15 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acedatacloud/skills",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.712.1",
|
|
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",
|
package/skills/hashnode/SKILL.md
CHANGED
|
@@ -16,29 +16,41 @@ metadata:
|
|
|
16
16
|
version: "1.0"
|
|
17
17
|
---
|
|
18
18
|
|
|
19
|
-
Call the **Hashnode
|
|
20
|
-
|
|
19
|
+
Call the **Hashnode GraphQL API** with `curl + jq`. The user's Personal Access
|
|
20
|
+
Token is in `$HASHNODE_TOKEN`. Single endpoint: `https://gql-beta.hashnode.com`
|
|
21
21
|
(always `POST` a JSON body `{query, variables}`).
|
|
22
22
|
|
|
23
|
+
> The old `https://gql.hashnode.com` host is **deprecated** — it now 301-redirects
|
|
24
|
+
> to a changelog page and returns HTML, not JSON. Always use `gql-beta.hashnode.com`.
|
|
25
|
+
|
|
23
26
|
Every request needs these headers:
|
|
24
27
|
|
|
25
28
|
```
|
|
26
|
-
Authorization: $HASHNODE_TOKEN
|
|
29
|
+
Authorization: Bearer $HASHNODE_TOKEN
|
|
27
30
|
Content-Type: application/json
|
|
28
31
|
```
|
|
29
32
|
|
|
30
33
|
GraphQL always returns HTTP `200`; real failures live in the JSON `errors`
|
|
31
|
-
array — always inspect it and show it verbatim.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
array — always inspect it and show it verbatim. Two error cases matter:
|
|
35
|
+
|
|
36
|
+
- `Unauthorized` / `not authenticated` → the token is invalid → the user must
|
|
37
|
+
re-connect the Hashnode connector.
|
|
38
|
+
- `extensions.code == "FORBIDDEN"` with a message like *"Publication does not have
|
|
39
|
+
an active Pro plan"* → this is **not** a token problem. As of 2026-05-13 Hashnode
|
|
40
|
+
moved its API behind a paid plan: **every write mutation** (`publishPost`,
|
|
41
|
+
`createDraft`, `updatePost`) **and publication-scoped reads require the target
|
|
42
|
+
publication to be on [Hashnode Pro](https://hashnode.com/pro)**. Do NOT tell the
|
|
43
|
+
user to reconnect and do NOT retry in a loop — tell them the publication owner
|
|
44
|
+
must upgrade to Hashnode Pro (blog dashboard → Billing → Upgrade to Pro), after
|
|
45
|
+
which the API works immediately. Public reads (posts/feeds/users/tags) stay free.
|
|
34
46
|
|
|
35
47
|
Helper — send a query/mutation (`$1` = query string, `$2` = variables JSON):
|
|
36
48
|
|
|
37
49
|
```bash
|
|
38
50
|
gql() {
|
|
39
51
|
jq -n --arg q "$1" --argjson v "${2:-null}" '{query:$q, variables:$v}' \
|
|
40
|
-
| curl -sS -X POST https://gql.hashnode.com \
|
|
41
|
-
-H "Authorization: $HASHNODE_TOKEN" \
|
|
52
|
+
| curl -sS -X POST https://gql-beta.hashnode.com \
|
|
53
|
+
-H "Authorization: Bearer $HASHNODE_TOKEN" \
|
|
42
54
|
-H "Content-Type: application/json" \
|
|
43
55
|
-d @-
|
|
44
56
|
}
|
|
@@ -136,7 +148,15 @@ gql 'query GetPost($id: ObjectId!) { post(id: $id) { title url views reactionCou
|
|
|
136
148
|
|
|
137
149
|
## Gotchas
|
|
138
150
|
|
|
139
|
-
- **
|
|
151
|
+
- **Endpoint is `https://gql-beta.hashnode.com`** — the old `gql.hashnode.com`
|
|
152
|
+
host is deprecated (301 → HTML changelog page, never valid GraphQL JSON).
|
|
153
|
+
- **`Authorization: Bearer $HASHNODE_TOKEN`** — send the token with the `Bearer`
|
|
154
|
+
prefix (this is what Hashnode's own official skill uses).
|
|
155
|
+
- **Pro plan required for writes** — since 2026-05-13, `publishPost` / `createDraft`
|
|
156
|
+
/ `updatePost` and publication-scoped reads only work if the target publication
|
|
157
|
+
has an active **Hashnode Pro** plan; otherwise the call returns a `FORBIDDEN`
|
|
158
|
+
*"does not have an active Pro plan"* error. That is a billing state on the user's
|
|
159
|
+
blog, not something the skill or a reconnect can fix — surface it and stop.
|
|
140
160
|
- **`publicationId` is mandatory** for publishing/drafting — never guess it, read
|
|
141
161
|
it from the `me` query.
|
|
142
162
|
- **`tags` is required on `publishPost`** — supply at least one `{name, slug}`;
|
package/skills/x/scripts/x.py
CHANGED
|
@@ -98,6 +98,7 @@ def current_user_id_from_cookies() -> str | None:
|
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
def make_client():
|
|
101
|
+
import httpx
|
|
101
102
|
from twikit import Client
|
|
102
103
|
patch_twikit_transaction_resolver()
|
|
103
104
|
patch_twikit_model_defaults()
|
|
@@ -107,7 +108,12 @@ def make_client():
|
|
|
107
108
|
or os.environ.get("ALL_PROXY") or os.environ.get("all_proxy")
|
|
108
109
|
or None
|
|
109
110
|
)
|
|
110
|
-
|
|
111
|
+
# twikit builds its httpx.AsyncClient with httpx's 5s default timeout, which
|
|
112
|
+
# trips a ReadTimeout on media uploads (INIT/APPEND/FINALIZE + status poll)
|
|
113
|
+
# from datacenter egress — a text-only tweet is one fast call and squeaks
|
|
114
|
+
# under 5s, but --media does not. Give network ops generous headroom.
|
|
115
|
+
timeout = httpx.Timeout(60.0, connect=15.0)
|
|
116
|
+
client = Client("en-US", proxy=proxy, user_agent=UA, timeout=timeout)
|
|
111
117
|
client.set_cookies(load_cookie_dict())
|
|
112
118
|
return client
|
|
113
119
|
|
|
@@ -494,6 +500,14 @@ def main() -> None:
|
|
|
494
500
|
# twikit scrapes X's non-public API; a bare error here usually means an
|
|
495
501
|
# expired cookie OR that X changed its internal endpoints and twikit
|
|
496
502
|
# needs a compatibility fix.
|
|
503
|
+
import httpx
|
|
504
|
+
if isinstance(e, httpx.TimeoutException):
|
|
505
|
+
die(
|
|
506
|
+
"X request timed out talking to X (network was slow, not an "
|
|
507
|
+
"auth problem) — this is transient, retry the same command. "
|
|
508
|
+
"Timeouts are most common on --media because the image upload "
|
|
509
|
+
"is the slow leg; if it recurs, try a smaller image."
|
|
510
|
+
)
|
|
497
511
|
if "Couldn't get KEY_BYTE indices" in str(e):
|
|
498
512
|
die(
|
|
499
513
|
"X request failed because twikit cannot derive X's current "
|