@acedatacloud/skills 2026.627.2 → 2026.628.0
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.
|
|
3
|
+
"version": "2026.628.0",
|
|
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",
|
|
@@ -135,7 +135,9 @@ Search drives the WeChat UI, so it may be slower than local DB history reads.
|
|
|
135
135
|
|
|
136
136
|
## Sending Messages — GATED
|
|
137
137
|
|
|
138
|
-
`send` dry-runs by default. It never sends unless `--confirm` is present
|
|
138
|
+
`send` dry-runs by default. It never sends unless `--confirm` is present, or
|
|
139
|
+
unless an AceDataCloud scheduled task pre-authorized this Skill and you use
|
|
140
|
+
`--unattended-confirm`.
|
|
139
141
|
|
|
140
142
|
```bash
|
|
141
143
|
python3 $WX send "Alice" "今晚 8 点开会吗?"
|
|
@@ -152,11 +154,32 @@ python3 $WX send "Alice" "今晚 8 点开会吗?" --confirm
|
|
|
152
154
|
Never add `--confirm` in the first attempt. Never infer consent from vague text.
|
|
153
155
|
The user must clearly approve sending this exact message.
|
|
154
156
|
|
|
157
|
+
### Scheduled-task unattended confirmation
|
|
158
|
+
|
|
159
|
+
When running inside an AceDataCloud scheduled task, the platform may pre-authorize
|
|
160
|
+
specific Skills for unattended execution. If all of these are true:
|
|
161
|
+
|
|
162
|
+
- `AICHAT_UNATTENDED_MODE=true`
|
|
163
|
+
- `AICHAT_ACTIVE_SKILL` is `personal-wechat` or `acedatacloud/personal-wechat`
|
|
164
|
+
- `AICHAT_ACTIVE_SKILL` appears in `AICHAT_UNATTENDED_ALLOWED_SKILLS`
|
|
165
|
+
|
|
166
|
+
then the user has pre-authorized this Skill for that scheduled task. In that
|
|
167
|
+
case, use:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
python3 $WX send "Alice" "今晚 8 点开会吗?" --unattended-confirm
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
If the helper returns `unattended_confirmation_denied`, do not retry with
|
|
174
|
+
`--confirm`; report the dry-run and explain that the task needs this Skill to be
|
|
175
|
+
selected in its unattended authorization settings.
|
|
176
|
+
|
|
155
177
|
## Safety Rules
|
|
156
178
|
|
|
157
179
|
- Never print `PERSONALWECHAT_API_TOKEN`.
|
|
158
180
|
- Treat `PERSONALWECHAT_BASE_URL + API_TOKEN` as full remote control of the user's WeChat.
|
|
159
|
-
- For
|
|
181
|
+
- For normal chat write/send operations: dry-run first, ask for explicit approval, then re-run with `--confirm`.
|
|
182
|
+
- For scheduled-task unattended writes: use `--unattended-confirm` only when the platform env says this Skill is pre-authorized.
|
|
160
183
|
- Do not call logout/restart endpoints from the skill unless the user explicitly asks to repair the Wisdom service.
|
|
161
184
|
- If Wisdom returns 503 for history, run `python3 $WX refresh-history` once, then retry the read.
|
|
162
185
|
- If the server is unreachable, ask the user to check the Windows host / security group / port 8000.
|
|
@@ -176,4 +199,4 @@ The helper wraps these Wisdom endpoints:
|
|
|
176
199
|
- `POST /api/messages/history/query`
|
|
177
200
|
- `POST /api/messages/history/refresh`
|
|
178
201
|
- `POST /api/search`
|
|
179
|
-
- `POST /api/messages/send` (only after `--confirm`)
|
|
202
|
+
- `POST /api/messages/send` (only after `--confirm` or verified `--unattended-confirm`)
|
|
@@ -7,6 +7,7 @@ import argparse
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
9
|
import sys
|
|
10
|
+
import time
|
|
10
11
|
import urllib.error
|
|
11
12
|
import urllib.parse
|
|
12
13
|
import urllib.request
|
|
@@ -15,6 +16,7 @@ import urllib.request
|
|
|
15
16
|
BASE_URL = os.environ.get("PERSONALWECHAT_BASE_URL", "").rstrip("/")
|
|
16
17
|
API_TOKEN = os.environ.get("PERSONALWECHAT_API_TOKEN", "")
|
|
17
18
|
MAX_TEXT_CHARS = 800
|
|
19
|
+
SKILL_SLUGS = {"personal-wechat", "acedatacloud/personal-wechat"}
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
def _die(message: str, code: int = 1) -> None:
|
|
@@ -26,6 +28,34 @@ def _json(data) -> None:
|
|
|
26
28
|
print(json.dumps(data, ensure_ascii=False, default=str))
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
def unattended_confirm_allowed() -> tuple[bool, str]:
|
|
32
|
+
if os.environ.get("AICHAT_UNATTENDED_MODE") != "true":
|
|
33
|
+
return False, "not running in AceDataCloud unattended scheduled-task mode"
|
|
34
|
+
|
|
35
|
+
active_skill = os.environ.get("AICHAT_ACTIVE_SKILL", "")
|
|
36
|
+
if active_skill not in SKILL_SLUGS:
|
|
37
|
+
return False, f"active skill {active_skill or '<empty>'!r} is not personal-wechat"
|
|
38
|
+
|
|
39
|
+
raw_allowed = os.environ.get("AICHAT_UNATTENDED_ALLOWED_SKILLS", "[]")
|
|
40
|
+
try:
|
|
41
|
+
allowed = json.loads(raw_allowed)
|
|
42
|
+
except json.JSONDecodeError:
|
|
43
|
+
return False, "AICHAT_UNATTENDED_ALLOWED_SKILLS is not valid JSON"
|
|
44
|
+
if not isinstance(allowed, list) or active_skill not in allowed:
|
|
45
|
+
return False, f"skill {active_skill!r} is not pre-authorized for unattended confirmation"
|
|
46
|
+
|
|
47
|
+
expires_raw = os.environ.get("AICHAT_UNATTENDED_EXPIRES_AT", "")
|
|
48
|
+
if expires_raw:
|
|
49
|
+
try:
|
|
50
|
+
expires_at = int(expires_raw)
|
|
51
|
+
except ValueError:
|
|
52
|
+
return False, "AICHAT_UNATTENDED_EXPIRES_AT is invalid"
|
|
53
|
+
if expires_at < int(time.time()):
|
|
54
|
+
return False, "unattended authorization has expired"
|
|
55
|
+
|
|
56
|
+
return True, "ok"
|
|
57
|
+
|
|
58
|
+
|
|
29
59
|
def request(method: str, path: str, *, params: dict | None = None, body: dict | None = None):
|
|
30
60
|
if not BASE_URL:
|
|
31
61
|
_die("PERSONALWECHAT_BASE_URL is not set. Reconnect the Personal WeChat connector.")
|
|
@@ -127,6 +157,7 @@ def main() -> None:
|
|
|
127
157
|
send.add_argument("target")
|
|
128
158
|
send.add_argument("text")
|
|
129
159
|
send.add_argument("--confirm", action="store_true")
|
|
160
|
+
send.add_argument("--unattended-confirm", action="store_true")
|
|
130
161
|
|
|
131
162
|
refresh = sub.add_parser("refresh-history")
|
|
132
163
|
refresh.set_defaults(cmd="refresh-history")
|
|
@@ -166,8 +197,13 @@ def main() -> None:
|
|
|
166
197
|
elif args.cmd == "search":
|
|
167
198
|
_json(request("POST", "/api/search", body={"query": args.query}))
|
|
168
199
|
elif args.cmd == "send":
|
|
169
|
-
if
|
|
170
|
-
|
|
200
|
+
if args.unattended_confirm:
|
|
201
|
+
allowed, reason = unattended_confirm_allowed()
|
|
202
|
+
if not allowed:
|
|
203
|
+
_json({"dry_run": True, "target": args.target, "text": args.text, "error": "unattended_confirmation_denied", "reason": reason})
|
|
204
|
+
return
|
|
205
|
+
elif not args.confirm:
|
|
206
|
+
_json({"dry_run": True, "target": args.target, "text": args.text, "note": "Re-run with --confirm after explicit user approval, or --unattended-confirm when this Skill is pre-authorized for an AceDataCloud scheduled task."})
|
|
171
207
|
return
|
|
172
208
|
_json(request("POST", "/api/messages/send", body={"target": args.target, "type": "text", "text": args.text}))
|
|
173
209
|
elif args.cmd == "refresh-history":
|