@acedatacloud/skills 2026.724.1 → 2026.724.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.724.1",
3
+ "version": "2026.724.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",
@@ -11,7 +11,7 @@ when_to_use: |
11
11
  comment, reply, like, or favorite on Xiaohongshu, including implicit requests
12
12
  such as "发一篇种草笔记" when Xiaohongshu is clear from context.
13
13
  connections: [xiaohongshu]
14
- skill_revision: 4.1.0
14
+ skill_revision: 4.2.0
15
15
  allowed_tools:
16
16
  - browser.snapshot
17
17
  - browser.get_text
@@ -35,6 +35,7 @@ allowed_tools:
35
35
  - browser.batch
36
36
  execution:
37
37
  browser:
38
+ skill_revision: 4.2.0
38
39
  provider: xiaohongshu/xiaohongshu
39
40
  origins:
40
41
  - https://www.xiaohongshu.com
@@ -51,7 +52,19 @@ execution:
51
52
  - file.upload
52
53
  operations:
53
54
  read_content:
54
- action_class: read
55
+ minimum_action_class: read
56
+ allowed_commands:
57
+ - act/hover
58
+ - act/scroll
59
+ - act/scroll_to
60
+ - navigate/url
61
+ - observe/accessibility
62
+ - observe/element
63
+ - observe/find
64
+ - observe/screenshot
65
+ - observe/visible_text
66
+ - tabs/manage
67
+ - wait/condition
55
68
  allowed_tools:
56
69
  - browser.snapshot
57
70
  - browser.get_text
@@ -67,10 +80,30 @@ execution:
67
80
  preview_schema:
68
81
  type: object
69
82
  required: []
70
- semantic_key:
71
- template: "xiaohongshu:read:{origin}:{resource}"
83
+ semantic_key_template: "{provider}:{operation_id}:{normalized_input_hash}"
72
84
  publish_note:
73
- action_class: protected.publish
85
+ minimum_action_class: protected.publish
86
+ allowed_commands:
87
+ - act/batch
88
+ - act/check
89
+ - act/click
90
+ - act/fill
91
+ - act/hover
92
+ - act/press
93
+ - act/scroll
94
+ - act/scroll_to
95
+ - act/select
96
+ - act/type
97
+ - dialog/handle
98
+ - navigate/url
99
+ - observe/accessibility
100
+ - observe/element
101
+ - observe/find
102
+ - observe/screenshot
103
+ - observe/visible_text
104
+ - tabs/manage
105
+ - transfer/upload
106
+ - wait/condition
74
107
  allowed_tools:
75
108
  - browser.snapshot
76
109
  - browser.get_text
@@ -99,10 +132,27 @@ execution:
99
132
  - content_hash
100
133
  - media_hashes
101
134
  - visibility
102
- semantic_key:
103
- template: "xiaohongshu:publish:{account}:{content_hash}"
135
+ semantic_key_template: "{provider}:{operation_id}:{preview_hash}:{normalized_input_hash}"
104
136
  comment_or_reply:
105
- action_class: protected.interaction
137
+ minimum_action_class: protected.interaction
138
+ allowed_commands:
139
+ - act/batch
140
+ - act/click
141
+ - act/fill
142
+ - act/hover
143
+ - act/press
144
+ - act/scroll
145
+ - act/scroll_to
146
+ - act/type
147
+ - dialog/handle
148
+ - navigate/url
149
+ - observe/accessibility
150
+ - observe/element
151
+ - observe/find
152
+ - observe/screenshot
153
+ - observe/visible_text
154
+ - tabs/manage
155
+ - wait/condition
106
156
  allowed_tools:
107
157
  - browser.snapshot
108
158
  - browser.get_text
@@ -126,10 +176,21 @@ execution:
126
176
  required:
127
177
  - target
128
178
  - content_hash
129
- semantic_key:
130
- template: "xiaohongshu:interaction:{target}:{content_hash}"
179
+ semantic_key_template: "{provider}:{operation_id}:{preview_hash}:{normalized_input_hash}"
131
180
  toggle_reaction:
132
- action_class: reversible.write
181
+ minimum_action_class: reversible.write
182
+ allowed_commands:
183
+ - act/click
184
+ - act/scroll
185
+ - act/scroll_to
186
+ - navigate/url
187
+ - observe/accessibility
188
+ - observe/element
189
+ - observe/find
190
+ - observe/screenshot
191
+ - observe/visible_text
192
+ - tabs/manage
193
+ - wait/condition
133
194
  allowed_tools:
134
195
  - browser.snapshot
135
196
  - browser.get_text
@@ -148,8 +209,7 @@ execution:
148
209
  - target
149
210
  - reaction
150
211
  - enabled
151
- semantic_key:
152
- template: "xiaohongshu:reaction:{target}:{reaction}:{enabled}"
212
+ semantic_key_template: "{provider}:{operation_id}:{preview_hash}:{normalized_input_hash}"
153
213
  license: Apache-2.0
154
214
  metadata:
155
215
  author: acedatacloud
@@ -100,6 +100,12 @@ def _operation_block(frontmatter: str, operation: str) -> str:
100
100
  return match.group(1)
101
101
 
102
102
 
103
+ def _operation_names(frontmatter: str) -> set[str]:
104
+ match = re.search(r"^ operations:\n(.*?)(?=^license:)", frontmatter, re.MULTILINE | re.DOTALL)
105
+ assert match, "missing execution.browser.operations"
106
+ return set(re.findall(r"^ ([a-z][a-z_]+):$", match.group(1), re.MULTILINE))
107
+
108
+
103
109
  def _operation_tools(block: str) -> set[str]:
104
110
  match = re.search(r"^ allowed_tools:\n((?: - .+\n)+)", block, re.MULTILINE)
105
111
  assert match, "missing operation allowed_tools"
@@ -109,6 +115,15 @@ def _operation_tools(block: str) -> set[str]:
109
115
  }
110
116
 
111
117
 
118
+ def _operation_commands(block: str) -> set[str]:
119
+ match = re.search(r"^ allowed_commands:\n((?: - .+\n)+)", block, re.MULTILINE)
120
+ assert match, "missing operation allowed_commands"
121
+ return {
122
+ line.removeprefix(" - ").strip()
123
+ for line in match.group(1).splitlines()
124
+ }
125
+
126
+
112
127
  def test_browser_execution_frontmatter_contract() -> None:
113
128
  frontmatter = _frontmatter(SKILL.read_text(encoding="utf-8"))
114
129
 
@@ -119,8 +134,9 @@ def test_browser_execution_frontmatter_contract() -> None:
119
134
  re.MULTILINE,
120
135
  )
121
136
  assert " Operate Xiaohongshu / RED through the user's paired browser device:" in frontmatter
122
- assert re.search(r"^skill_revision: 4\.1\.0$", frontmatter, re.MULTILINE)
137
+ assert re.search(r"^skill_revision: 4\.2\.0$", frontmatter, re.MULTILINE)
123
138
  assert re.search(r"^execution:\n browser:\n", frontmatter, re.MULTILINE)
139
+ assert re.search(r"^ skill_revision: 4\.2\.0$", frontmatter, re.MULTILINE)
124
140
  assert re.search(r"^ provider: xiaohongshu/xiaohongshu$", frontmatter, re.MULTILINE)
125
141
  assert _nested_list(frontmatter, "origins") == EXPECTED_ORIGINS
126
142
  assert _nested_list(frontmatter, "capabilities") == EXPECTED_CAPABILITIES
@@ -152,12 +168,16 @@ def test_compact_manifest_matches_final_generated_profile() -> None:
152
168
 
153
169
 
154
170
  def test_operation_descriptors_define_exact_tool_union() -> None:
155
- frontmatter = _frontmatter(SKILL.read_text(encoding="utf-8"))
171
+ skill_text = SKILL.read_text(encoding="utf-8")
172
+ frontmatter = _frontmatter(skill_text)
173
+ operation_names = _operation_names(frontmatter)
174
+ assert operation_names == {"read_content", "publish_note", "comment_or_reply", "toggle_reaction"}
156
175
  operations = {
157
176
  name: _operation_block(frontmatter, name)
158
- for name in ("read_content", "publish_note", "comment_or_reply", "toggle_reaction")
177
+ for name in operation_names
159
178
  }
160
179
  operation_tools = {name: _operation_tools(block) for name, block in operations.items()}
180
+ operation_commands = {name: _operation_commands(block) for name, block in operations.items()}
161
181
 
162
182
  assert set().union(*operation_tools.values()) == _top_level_list(frontmatter, "allowed_tools")
163
183
  assert set().union(*operation_tools.values()) == EXPECTED_FACADES
@@ -165,14 +185,31 @@ def test_operation_descriptors_define_exact_tool_union() -> None:
165
185
  for tools in operation_tools.values():
166
186
  assert tools <= DEPLOYED_BROWSER_TOOLS
167
187
 
188
+ for name, tools in operation_tools.items():
189
+ expected_commands = {
190
+ f"{MANIFEST_DATA['facades'][tool]['family']}/{MANIFEST_DATA['facades'][tool]['kind']}"
191
+ for tool in tools
192
+ }
193
+ assert operation_commands[name] == expected_commands
194
+
168
195
  publish = operations["publish_note"]
169
- assert re.search(r"^ action_class: protected\.publish$", publish, re.MULTILINE)
196
+ assert re.search(r"^ minimum_action_class: protected\.publish$", publish, re.MULTILINE)
170
197
  for field in ("title", "content_hash", "media_hashes", "visibility"):
171
198
  assert re.search(rf"^ - {field}$", publish, re.MULTILINE)
172
- assert re.search(r'^ template: "xiaohongshu:publish:\{account\}:\{content_hash\}"$', publish, re.MULTILINE)
173
- assert re.search(r"^ action_class: protected\.interaction$", operations["comment_or_reply"], re.MULTILINE)
174
- assert re.search(r"^ action_class: reversible\.write$", operations["toggle_reaction"], re.MULTILINE)
175
- assert re.search(r"^ action_class: read$", operations["read_content"], re.MULTILINE)
199
+ assert re.search(
200
+ r'^ semantic_key_template: "\{provider\}:\{operation_id\}:\{preview_hash\}:\{normalized_input_hash\}"$',
201
+ publish,
202
+ re.MULTILINE,
203
+ )
204
+ assert re.search(r"^ minimum_action_class: protected\.interaction$", operations["comment_or_reply"], re.MULTILINE)
205
+ assert re.search(r"^ minimum_action_class: reversible\.write$", operations["toggle_reaction"], re.MULTILINE)
206
+ assert re.search(r"^ minimum_action_class: read$", operations["read_content"], re.MULTILINE)
207
+ for block in operations.values():
208
+ template = re.search(r'^ semantic_key_template: "([^"]+)"$', block, re.MULTILINE)
209
+ assert template
210
+ fields = set(re.findall(r"\{([^}]+)\}", template.group(1)))
211
+ assert {"provider", "operation_id"} <= fields
212
+ assert fields <= {"provider", "operation_id", "preview_hash", "normalized_input_hash"}
176
213
 
177
214
 
178
215
  def test_generic_manifest_contains_no_site_specific_logic() -> None: