@acedatacloud/skills 2026.728.0 → 2026.728.2

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.728.0",
3
+ "version": "2026.728.2",
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",
@@ -54,7 +54,7 @@ Stats come straight from Bilibili: `view` (阅读), `like` (点赞), `reply` (
54
54
  ```sh
55
55
  BILI="$SKILL_DIR/scripts/bilibili.py"; [ -f "$BILI" ] || BILI=$(find /tmp -maxdepth 8 -path '*/skills/*/scripts/bilibili.py' 2>/dev/null | head -1)
56
56
  python3 "$BILI" whoami
57
- # → {"mid": 91207595, "name": "...", "level": 4}
57
+ # → {"mid": 10000000, "name": "...", "level": 4}
58
58
  ```
59
59
 
60
60
  On a not-logged-in / auth error the cookie is expired — have the user reconnect
@@ -53,7 +53,7 @@ Stats come straight from CSDN: `view_count` (阅读), `digg_count` (点赞),
53
53
  ```sh
54
54
  CSDN="$SKILL_DIR/scripts/csdn.py"; [ -f "$CSDN" ] || CSDN=$(find /tmp -maxdepth 8 -path '*/skills/*/scripts/csdn.py' 2>/dev/null | head -1)
55
55
  python3 "$CSDN" whoami
56
- # → {"username": "...", "nickname": "...", "articles_total": 1597}
56
+ # → {"username": "...", "nickname": "...", "articles_total": 0}
57
57
  ```
58
58
 
59
59
  On a WAF 403 / auth error the cookie is expired — tell the user to reconnect at
@@ -63,15 +63,15 @@ python3 scripts/discord_user.py whoami
63
63
  # list the servers (guilds) the account is in
64
64
  python3 scripts/discord_user.py guilds
65
65
  # list text channels in a server
66
- python3 scripts/discord_user.py channels --guild 1133012399448928276
66
+ python3 scripts/discord_user.py channels --guild GUILD_ID
67
67
  # read recent messages in a channel
68
- python3 scripts/discord_user.py messages --channel 1133012400174534792 --limit 20
68
+ python3 scripts/discord_user.py messages --channel CHANNEL_ID --limit 20
69
69
  # send — dry-run first, then re-run with a trailing --confirm
70
- python3 scripts/discord_user.py send --channel 1133012400174534792 --text "hello"
71
- python3 scripts/discord_user.py send --channel 1133012400174534792 --text "hello" --confirm
70
+ python3 scripts/discord_user.py send --channel CHANNEL_ID --text "hello"
71
+ python3 scripts/discord_user.py send --channel CHANNEL_ID --text "hello" --confirm
72
72
  # reply to a specific message
73
73
  python3 scripts/discord_user.py reply \
74
- --channel 1133012400174534792 --message 987654321098765432 --text "on it" --confirm
74
+ --channel CHANNEL_ID --message MESSAGE_ID --text "on it" --confirm
75
75
  ```
76
76
 
77
77
  `--confirm` is honored ONLY as the final argument (one strip), so a message body
@@ -17,10 +17,10 @@ account access — NEVER echo or print it.
17
17
  Examples:
18
18
  python3 discord_user.py whoami
19
19
  python3 discord_user.py guilds
20
- python3 discord_user.py channels --guild 1133012399448928276
21
- python3 discord_user.py messages --channel 1133012400174534792 --limit 20
22
- python3 discord_user.py send --channel 1133012400174534792 --text "hello" --confirm
23
- python3 discord_user.py reply --channel 1133012400174534792 --message 987654321 --text "on it" --confirm
20
+ python3 discord_user.py channels --guild GUILD_ID
21
+ python3 discord_user.py messages --channel CHANNEL_ID --limit 20
22
+ python3 discord_user.py send --channel CHANNEL_ID --text "hello" --confirm
23
+ python3 discord_user.py reply --channel CHANNEL_ID --message MESSAGE_ID --text "on it" --confirm
24
24
  """
25
25
 
26
26
  from __future__ import annotations
@@ -383,7 +383,7 @@ BODY='Hi Alice,
383
383
  Just a quick test note from the AceDataCloud Gmail connector.
384
384
 
385
385
  Best,
386
- Qingcai'
386
+ YOUR_NAME'
387
387
 
388
388
  # Multi-line subject lines need MIME encoded-word for non-ASCII; ASCII is fine raw.
389
389
  RAW=$(printf 'To: %s\r\nSubject: %s\r\nContent-Type: text/plain; charset=UTF-8\r\nMIME-Version: 1.0\r\n\r\n%s' \
@@ -47,7 +47,7 @@ Stats come straight from 掘金: `view_count` (阅读), `digg_count` (点赞),
47
47
  ```sh
48
48
  JJ="$SKILL_DIR/scripts/juejin.py"; [ -f "$JJ" ] || JJ=$(find /tmp -maxdepth 8 -path '*/skills/*/scripts/juejin.py' 2>/dev/null | head -1)
49
49
  python3 "$JJ" whoami
50
- # → {"user_id": "...", "name": "...", "post_article_count": 336}
50
+ # → {"user_id": "...", "name": "...", "post_article_count": 0}
51
51
  ```
52
52
 
53
53
  On an auth error (`err_no` 401 / "请登录") the cookie is expired — have the user
@@ -64,7 +64,7 @@ curl -sS -X POST "$MASTODON_BASE_URL/api/v1/statuses" \
64
64
  Use the `id` from `verify_credentials`:
65
65
 
66
66
  ```bash
67
- ACCT_ID="14715" # from verify_credentials
67
+ ACCT_ID="ACCOUNT_ID" # from verify_credentials
68
68
  curl -sS "$MASTODON_BASE_URL/api/v1/accounts/$ACCT_ID/statuses?limit=20&exclude_replies=true&exclude_reblogs=true" \
69
69
  -H "Authorization: Bearer $MASTODON_ACCESS_TOKEN" \
70
70
  | jq '.[] | {id, url, boosts: .reblogs_count, favs: .favourites_count, replies: .replies_count, created_at}'
@@ -98,7 +98,7 @@ python3 $WX conversations --history --limit 20
98
98
  First list conversations, then use the `id` as `conversation_id`:
99
99
 
100
100
  ```bash
101
- python3 $WX messages "34642176898@chatroom" --limit 50 --order asc
101
+ python3 $WX messages "CONVERSATION_ID" --limit 50 --order asc
102
102
  ```
103
103
 
104
104
  ### Historical Messages
@@ -107,7 +107,7 @@ Read from Wisdom's decrypted WeChat local databases:
107
107
 
108
108
  ```bash
109
109
  python3 $WX history --limit 50
110
- python3 $WX history --talker "34642176898@chatroom" --limit 50
110
+ python3 $WX history --talker "CONVERSATION_ID" --limit 50
111
111
  python3 $WX history --limit 20 --offset 20
112
112
  ```
113
113
 
@@ -51,7 +51,7 @@ last argument** so a message/caption that merely contains "--confirm" can never
51
51
 
52
52
  ```sh
53
53
  python3 "$TG" whoami
54
- # → {"id": 8367450178, "username": "GermeyAce", "name": "Germey", "phone": "..."}
54
+ # → {"id": 100000000, "username": "<the connected handle>", "name": "<display name>", "phone": "..."}
55
55
  ```
56
56
 
57
57
  On an auth/session error the stored session is dead — tell the user to reconnect at
@@ -54,7 +54,7 @@ Stats come straight from 头条: `impression_count` (展现), `read_count` (阅
54
54
  ```sh
55
55
  TT="$SKILL_DIR/scripts/toutiao.py"; [ -f "$TT" ] || TT=$(find /tmp -maxdepth 8 -path '*/skills/*/scripts/toutiao.py' 2>/dev/null | head -1)
56
56
  python3 "$TT" whoami
57
- # → {"user_id": ..., "name": "...", "articles_total": 273}
57
+ # → {"user_id": ..., "name": "...", "articles_total": 0}
58
58
  ```
59
59
 
60
60
  On an auth error the cookie is expired — tell the user to reconnect at
package/skills/x/SKILL.md CHANGED
@@ -50,8 +50,8 @@ python3 "$X" whoami # confirm the shipped CLI can read the authenticate
50
50
  ## Read commands (run directly)
51
51
 
52
52
  ```sh
53
- python3 $X whoami --expect GermeyAce # verify this exact account
54
53
  python3 $X whoami # discover the authenticated account
54
+ python3 $X whoami --expect SCREEN_NAME # optional: assert a specific account
55
55
  python3 $X search --query "ai agents" --product Latest --limit 20 # Top | Latest | Media
56
56
  python3 $X search-users --query "openai" --limit 10
57
57
  python3 $X timeline --limit 20 # my home timeline
@@ -65,19 +65,22 @@ python3 $X trends --category trending --limit 20 # trending|for-you|
65
65
  ## Verify the connection first
66
66
 
67
67
  ```sh
68
- python3 $X whoami --expect GermeyAce
69
- # → {"id": "...", "screen_name": "GermeyAce", "identity_verified": true, ...}
68
+ python3 $X whoami
69
+ # → {"id": "...", "screen_name": "<the connected handle>", "identity_verified": true, ...}
70
70
  ```
71
71
 
72
72
  `whoami` reads the authenticated account's screen name from X account settings,
73
- then resolves its public profile. `--expect` compares that server-authenticated
74
- screen name with the required account before any write. This avoids X's
75
- Cloudflare-blocked `UserByRestId` endpoint without trusting a local identity
76
- cookie. Always use `--expect` when the user names the required account.
73
+ then resolves its public profile. This avoids X's Cloudflare-blocked
74
+ `UserByRestId` endpoint without trusting a local identity cookie.
75
+
76
+ `--expect <screen_name>` is optional: pass it only when the user explicitly names
77
+ the account they want to act as, and it will abort if the connected cookie
78
+ belongs to someone else. Do not invent an expected handle — plain `whoami` is
79
+ the default.
77
80
 
78
81
  On an actual auth error the cookie is expired — have the user reconnect at
79
82
  <https://auth.acedata.cloud/user/connections>. A Cloudflare block is different:
80
- reconnecting cookies does not fix it. Use `--expect` for identity checks; other
83
+ reconnecting cookies does not fix it. Use `whoami` for identity checks; other
81
84
  blocked endpoints need `X_PROXY` or the official X API. Do **not** loop-retry.
82
85
 
83
86
  ## Write commands — GATED (dry-run unless trailing `--confirm`)
@@ -19,7 +19,7 @@ breakage.
19
19
 
20
20
  Examples:
21
21
  python3 x.py whoami
22
- python3 x.py whoami --expect GermeyAce
22
+ python3 x.py whoami --expect SCREEN_NAME
23
23
  python3 x.py search --query "python" --product Latest --limit 20
24
24
  python3 x.py timeline --limit 20
25
25
  python3 x.py user-tweets --user elonmusk --type Tweets --limit 20
@@ -107,7 +107,7 @@ def cloudflare_block_message(error: Exception) -> str | None:
107
107
  ray = f" Ray ID: {ray_match.group(1)}." if ray_match else ""
108
108
  return (
109
109
  "X blocked this automated web-API request at Cloudflare; the login cookies may still be valid."
110
- f"{ray} For identity checks, use `whoami --expect <screen_name>`; for other blocked endpoints, "
110
+ f"{ray} For identity checks, use `whoami`; for other blocked endpoints, "
111
111
  "configure X_PROXY or use the official X API."
112
112
  )
113
113
 
@@ -1,104 +1,125 @@
1
1
  ---
2
2
  name: yuque
3
- description: Read and write Yuque (语雀) documents with the user's own personal access token through the official open API at https://www.yuque.com/api/v2. Use when the user wants to publish Markdown to 语雀, list their knowledge bases (知识库), read or update a 语雀 document, or delete one.
3
+ description: Read and write Yuque (语雀) documents on the user's own account — list knowledge bases (知识库), read a document, publish Markdown, and update or delete one. Works with either the user's browser login (free) or a personal access token. Use when the user wants to publish Markdown to 语雀, list their 语雀 knowledge bases, or read a 语雀 document.
4
4
  when_to_use: |
5
5
  Trigger for 语雀 / Yuque document management: verify the connected account,
6
6
  list knowledge bases or the documents inside one, read a document, create a
7
- Markdown document, update an existing one, or delete one. Writes and
8
- destructive actions require explicit confirmation.
7
+ Markdown document, and (token connections only) update or delete one.
8
+ Writes and destructive actions require explicit confirmation.
9
9
  connections: [yuque]
10
10
  allowed_tools: [Bash]
11
11
  license: Apache-2.0
12
12
  metadata:
13
13
  author: acedatacloud
14
- version: "1.0"
14
+ version: "2.0"
15
15
  ---
16
16
 
17
- Use the bundled standard-library CLI. The connector injects the user's 语雀
18
- personal access token as `$YUQUE_TOKEN`. Never print it. The CLI uses the
19
- official open API at `https://www.yuque.com/api/v2` with the documented
20
- `X-Auth-Token` header.
17
+ # 语雀 — two connection modes
21
18
 
22
- ```bash
23
- python3 "$SKILL_DIR/scripts/yuque.py" whoami
24
- ```
19
+ The connector injects exactly one credential, and the CLI picks its mode from it:
25
20
 
26
- If `$SKILL_DIR` points at a different skill loaded in the same turn, resolve
27
- this skill's directory explicitly before running the commands below.
21
+ - **`$YUQUE_COOKIES`** — the user's own browser login jar, captured by the ACE
22
+ extension. **Free.** Drives 语雀's internal web API.
23
+ - **`$YUQUE_TOKEN`** — a 语雀 personal access token for the official open API.
24
+ **Requires a paid 语雀超级会员.**
28
25
 
29
- If authentication fails, ask the user to create a token at
30
- `https://www.yuque.com/settings/tokens` and reconnect at
31
- `https://auth.acedata.cloud/user/connections`. Do not ask for their account
32
- password or Cookie.
26
+ Both are **secret — never echo, print, log or return them.** Every command
27
+ reports the active mode back as `auth_mode`; read that instead of guessing.
33
28
 
34
- ## Read
29
+ | Command | cookie | token |
30
+ |---|---|---|
31
+ | `whoami`, `repos`, `docs`, `doc` | ✅ | ✅ |
32
+ | `create` | ✅ | ✅ |
33
+ | `update`, `delete` | ❌ refused with a clear error | ✅ |
34
+
35
+ If the user asks to edit or delete on a cookie connection, tell them that needs
36
+ a personal token (created at `https://www.yuque.com/settings/tokens`, 超级会员
37
+ required) and offer to create a new document instead. Do not attempt a
38
+ workaround.
35
39
 
36
- A `repo` is a 语雀 knowledge base, addressed either by its `namespace`
37
- (`user/book`, as shown in the document URL) or by its numeric id. Always run
38
- `repos` first — never guess a namespace.
40
+ ## Script resolution
39
41
 
40
- ```bash
41
- # Verify the token and see the account.
42
- python3 "$SKILL_DIR/scripts/yuque.py" whoami
42
+ Bash calls do not share shell variables. Resolve the helper inside **every**
43
+ fenced Bash invocation before using it:
43
44
 
44
- # List knowledge bases, then the documents in one.
45
- python3 "$SKILL_DIR/scripts/yuque.py" repos
46
- python3 "$SKILL_DIR/scripts/yuque.py" docs germey/blog --limit 20
47
- python3 "$SKILL_DIR/scripts/yuque.py" doc germey/blog DOC_ID
45
+ ```sh
46
+ Y="${SKILL_DIR:-}/scripts/yuque.py"; [ -f "$Y" ] || Y=$(find /tmp -maxdepth 8 -path '*/skills/*/yuque/scripts/yuque.py' -print -quit 2>/dev/null)
47
+ [ -f "$Y" ] || { echo "yuque script not found (SKILL_DIR=$SKILL_DIR)" >&2; exit 1; }
48
+ python3 "$Y" whoami
48
49
  ```
49
50
 
50
- ## Create and update
51
+ On an auth error, ask the user to reconnect at
52
+ <https://auth.acedata.cloud/user/connections>. Never ask for their password,
53
+ and never ask them to paste a Cookie into the chat.
51
54
 
52
- Prepare the complete Markdown in a file. 语雀 has no separate draft state — a
53
- document is either private or public — so the CLI creates **private** documents
54
- by default and only publishes publicly with an explicit `--public`.
55
+ ## Read
56
+
57
+ A knowledge base (`repo`) is addressed by its `user/book` namespace or its
58
+ numeric id. **Always run `repos` first — never guess a namespace or an id.**
59
+ Pass back exactly the `repo_id` that `repos` printed; on a cookie connection a
60
+ `user/book` namespace is resolved by matching the account's own knowledge
61
+ bases, so it fails for a base the account does not own, and an ambiguous slug
62
+ is refused rather than guessed.
63
+
64
+ ```sh
65
+ Y="${SKILL_DIR:-}/scripts/yuque.py"; [ -f "$Y" ] || Y=$(find /tmp -maxdepth 8 -path '*/skills/*/yuque/scripts/yuque.py' -print -quit 2>/dev/null)
66
+ python3 "$Y" repos
67
+ python3 "$Y" docs REPO_ID --limit 20
68
+ python3 "$Y" doc REPO_ID DOC_ID
69
+ ```
55
70
 
56
- ```bash
57
- # First call is always a dry run and does not load credentials or call the API.
58
- python3 "$SKILL_DIR/scripts/yuque.py" create germey/blog \
59
- --title "标题" --content-file /tmp/article.md
71
+ ## Create
72
+
73
+ Prepare the complete Markdown in a file. 语雀 has no draft state — a document is
74
+ either private or public — so the CLI creates **private** documents by default
75
+ and only publishes publicly with an explicit `--public`.
76
+
77
+ ```sh
78
+ Y="${SKILL_DIR:-}/scripts/yuque.py"; [ -f "$Y" ] || Y=$(find /tmp -maxdepth 8 -path '*/skills/*/yuque/scripts/yuque.py' -print -quit 2>/dev/null)
79
+
80
+ # The first call is always a dry run: it loads no credentials and calls no API.
81
+ python3 "$Y" create REPO_ID --title "标题" --content-file /tmp/article.md
60
82
 
61
83
  # Create it privately after the user confirms.
62
- python3 "$SKILL_DIR/scripts/yuque.py" create germey/blog \
63
- --title "标题" --content-file /tmp/article.md --confirm
84
+ python3 "$Y" create REPO_ID --title "标题" --content-file /tmp/article.md --confirm
64
85
 
65
86
  # Public publishing additionally requires --public.
66
- python3 "$SKILL_DIR/scripts/yuque.py" create germey/blog \
67
- --title "标题" --content-file /tmp/article.md --public --confirm
68
-
69
- python3 "$SKILL_DIR/scripts/yuque.py" update germey/blog DOC_ID \
70
- --title "新标题" --content-file /tmp/article.md --public --confirm
87
+ python3 "$Y" create REPO_ID --title "标题" --content-file /tmp/article.md --public --confirm
71
88
  ```
72
89
 
73
- `--confirm` is valid only as the final argument. Always show the target
74
- knowledge base, title, visibility and full content to the user before a public
75
- publish. Default to a private document unless the user explicitly asks to
76
- publish publicly.
77
-
78
- Note that `update` rewrites the whole document body. Read the current document
79
- first if the user only wants part of it changed.
90
+ `--confirm` is honored **only as the final argument**. Before a public publish,
91
+ always show the user the target knowledge base, the title, the visibility and
92
+ the full content. Default to private unless they explicitly ask to publish
93
+ publicly.
80
94
 
81
- ## Delete
95
+ ## Update and delete (token connections only)
82
96
 
83
- ```bash
84
- python3 "$SKILL_DIR/scripts/yuque.py" delete germey/blog DOC_ID --confirm
97
+ ```sh
98
+ python3 "$Y" update REPO_NAMESPACE DOC_ID --title "新标题" --content-file /tmp/a.md --confirm
99
+ python3 "$Y" delete REPO_NAMESPACE DOC_ID --confirm
85
100
  ```
86
101
 
87
- Use the real returned `doc_id` and URL. Do not retry a timed-out write
88
- automatically because its outcome may be unknown; list the documents first so
89
- you do not create a duplicate.
102
+ `update` rewrites the whole document body — read the current document first if
103
+ the user only wants part of it changed.
90
104
 
91
105
  ## Gotchas
92
106
 
107
+ - Use the real returned `doc_id` and `url`; never invent either. A cookie
108
+ connection cannot always resolve a public URL, in which case `url` is `null`
109
+ — report the `doc_id` instead of guessing a link.
110
+ - If a write times out its outcome is **unknown** — run `docs` to check before
111
+ retrying, or you will create a duplicate.
93
112
  - Images referenced by external URL are not re-hosted; 语雀 renders them from
94
- the original host. If the source blocks hotlinking, upload the images to 语雀
113
+ the original host. If that host blocks hotlinking, upload the images in 语雀
95
114
  manually first and reference the returned URLs.
96
- - 语雀's own terms state the open API is for normal reading and writing of 语雀
97
- content; abnormal automated behaviour can get the account blocked. Keep the
98
- volume human-scale.
115
+ - 语雀's terms allow the API for normal reading and writing of 语雀 content;
116
+ abnormal automated behaviour can get the account blocked. Keep the volume
117
+ human-scale and never batch-publish.
99
118
 
100
119
  ## Record the output
101
120
 
102
- After a confirmed public publish returns a real URL, call `publish_artifact`
103
- once with `kind="article"`, `channel="yuque"`, the title, returned URL, and
104
- `status="delivered"`. Do not record private documents or failed/unknown writes.
121
+ After a confirmed **public** publish, if the response carries a non-null `url`,
122
+ call `publish_artifact` once with `kind="article"`, `channel="yuque"`, the
123
+ title, that URL, and `status="delivered"`. If `url` is `null`, **do not invent
124
+ one** — report the `doc_id` to the user and skip `publish_artifact`. Do not
125
+ record private documents or failed/unknown writes.