@acedatacloud/skills 2026.628.1 → 2026.628.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.628.
|
|
3
|
+
"version": "2026.628.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",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Unattended Scheduled-Task Confirmation
|
|
2
|
+
|
|
3
|
+
Write-capable Skill helpers may support unattended scheduled-task execution with
|
|
4
|
+
a common `--unattended-confirm` flag. The flag must only bypass the normal
|
|
5
|
+
dry-run/confirmation flow when all platform-provided environment checks pass:
|
|
6
|
+
|
|
7
|
+
- `AICHAT_UNATTENDED_MODE=true`
|
|
8
|
+
- `AICHAT_ACTIVE_SKILL` matches the helper's Skill slug
|
|
9
|
+
- `AICHAT_ACTIVE_SKILL` is present in `AICHAT_UNATTENDED_ALLOWED_SKILLS`
|
|
10
|
+
- `AICHAT_UNATTENDED_EXPIRES_AT`, when present, is still in the future
|
|
11
|
+
|
|
12
|
+
If any check fails, the helper must return a dry-run style response and must not
|
|
13
|
+
perform the write/send/publish/delete action. The current Skills packaging does
|
|
14
|
+
not automatically bundle `_shared` files into each Skill, so helpers that need
|
|
15
|
+
runtime code should vendor a small guard module in their own `scripts/` folder
|
|
16
|
+
until packaging grows shared-runtime support.
|
|
@@ -7,11 +7,12 @@ import argparse
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
9
|
import sys
|
|
10
|
-
import time
|
|
11
10
|
import urllib.error
|
|
12
11
|
import urllib.parse
|
|
13
12
|
import urllib.request
|
|
14
13
|
|
|
14
|
+
from unattended import unattended_confirm_allowed
|
|
15
|
+
|
|
15
16
|
|
|
16
17
|
BASE_URL = os.environ.get("PERSONALWECHAT_BASE_URL", "").rstrip("/")
|
|
17
18
|
API_TOKEN = os.environ.get("PERSONALWECHAT_API_TOKEN", "")
|
|
@@ -28,34 +29,6 @@ def _json(data) -> None:
|
|
|
28
29
|
print(json.dumps(data, ensure_ascii=False, default=str))
|
|
29
30
|
|
|
30
31
|
|
|
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
|
-
|
|
59
32
|
def request(method: str, path: str, *, params: dict | None = None, body: dict | None = None):
|
|
60
33
|
if not BASE_URL:
|
|
61
34
|
_die("PERSONALWECHAT_BASE_URL is not set. Reconnect the Personal WeChat connector.")
|
|
@@ -220,7 +193,7 @@ def main() -> None:
|
|
|
220
193
|
_json(request_task("POST", "/api/search", body={"query": args.query}, timeout=120))
|
|
221
194
|
elif args.cmd == "send":
|
|
222
195
|
if args.unattended_confirm:
|
|
223
|
-
allowed, reason = unattended_confirm_allowed()
|
|
196
|
+
allowed, reason = unattended_confirm_allowed(SKILL_SLUGS)
|
|
224
197
|
if not allowed:
|
|
225
198
|
_json({"dry_run": True, "target": args.target, "text": args.text, "error": "unattended_confirmation_denied", "reason": reason})
|
|
226
199
|
return
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Unattended scheduled-task confirmation guard bundled with this Skill."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import time
|
|
8
|
+
from collections.abc import Iterable
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def unattended_confirm_allowed(skill_slugs: Iterable[str]) -> tuple[bool, str]:
|
|
12
|
+
"""Return whether the active Skill is pre-authorized for unattended writes."""
|
|
13
|
+
|
|
14
|
+
if os.environ.get("AICHAT_UNATTENDED_MODE") != "true":
|
|
15
|
+
return False, "not running in AceDataCloud unattended scheduled-task mode"
|
|
16
|
+
|
|
17
|
+
active_skill = os.environ.get("AICHAT_ACTIVE_SKILL", "")
|
|
18
|
+
allowed_skill_slugs = set(skill_slugs)
|
|
19
|
+
if active_skill not in allowed_skill_slugs:
|
|
20
|
+
return False, f"active skill {active_skill or '<empty>'!r} is not one of {sorted(allowed_skill_slugs)!r}"
|
|
21
|
+
|
|
22
|
+
raw_allowed = os.environ.get("AICHAT_UNATTENDED_ALLOWED_SKILLS", "[]")
|
|
23
|
+
try:
|
|
24
|
+
allowed = json.loads(raw_allowed)
|
|
25
|
+
except json.JSONDecodeError:
|
|
26
|
+
return False, "AICHAT_UNATTENDED_ALLOWED_SKILLS is not valid JSON"
|
|
27
|
+
if not isinstance(allowed, list) or active_skill not in allowed:
|
|
28
|
+
return False, f"skill {active_skill!r} is not pre-authorized for unattended confirmation"
|
|
29
|
+
|
|
30
|
+
expires_raw = os.environ.get("AICHAT_UNATTENDED_EXPIRES_AT", "")
|
|
31
|
+
if expires_raw:
|
|
32
|
+
try:
|
|
33
|
+
expires_at = int(expires_raw)
|
|
34
|
+
except ValueError:
|
|
35
|
+
return False, "AICHAT_UNATTENDED_EXPIRES_AT is invalid"
|
|
36
|
+
if expires_at < int(time.time()):
|
|
37
|
+
return False, "unattended authorization has expired"
|
|
38
|
+
|
|
39
|
+
return True, "ok"
|