@remixmate/cli 0.1.1 → 0.9.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.
Files changed (62) hide show
  1. package/README.md +46 -0
  2. package/README.zh-CN.md +22 -0
  3. package/dist/auth/auth-lock.d.ts +26 -0
  4. package/dist/auth/auth-lock.js +100 -0
  5. package/dist/auth/auto-login.d.ts +20 -0
  6. package/dist/auth/auto-login.js +66 -0
  7. package/dist/auth/commands.d.ts +8 -0
  8. package/dist/auth/commands.js +130 -0
  9. package/dist/auth/credential-store.d.ts +44 -0
  10. package/dist/auth/credential-store.js +126 -0
  11. package/dist/auth/device-flow-runner.d.ts +43 -0
  12. package/dist/auth/device-flow-runner.js +62 -0
  13. package/dist/auth/device-flow.d.ts +52 -0
  14. package/dist/auth/device-flow.js +115 -0
  15. package/dist/auth/environment.d.ts +25 -0
  16. package/dist/auth/environment.js +48 -0
  17. package/dist/auth/resolve.d.ts +30 -0
  18. package/dist/auth/resolve.js +44 -0
  19. package/dist/cli.js +11 -0
  20. package/dist/handlers/gen-digital-human.js +1 -1
  21. package/dist/handlers/gen-image.js +1 -1
  22. package/dist/handlers/gen-video.js +1 -1
  23. package/dist/handlers/gen-voice.js +2 -2
  24. package/dist/http.d.ts +9 -5
  25. package/dist/http.js +24 -10
  26. package/dist/manifest.json +14 -3
  27. package/dist/runner.d.ts +1 -1
  28. package/dist/skill-schema.d.ts +18 -0
  29. package/dist/skill-schema.js +4 -0
  30. package/package.json +1 -1
  31. package/skills/export-jianying/skill.json +1 -0
  32. package/skills/gen-digital-human/SKILL.md +11 -11
  33. package/skills/gen-digital-human/skill.json +1 -0
  34. package/skills/gen-digital-human/version.json +1 -1
  35. package/skills/gen-image/SKILL.md +6 -6
  36. package/skills/gen-image/skill.json +1 -0
  37. package/skills/gen-image/version.json +1 -1
  38. package/skills/gen-script/scripts/gen_script.py +105 -31
  39. package/skills/gen-script/skill.json +3 -1
  40. package/skills/gen-script/version.json +1 -1
  41. package/skills/gen-video/SKILL.md +6 -6
  42. package/skills/gen-video/skill.json +1 -0
  43. package/skills/gen-video/version.json +1 -1
  44. package/skills/gen-voice/SKILL.md +6 -6
  45. package/skills/gen-voice/skill.json +1 -0
  46. package/skills/gen-voice/version.json +1 -1
  47. package/skills/prepare-video-assets/skill.json +1 -0
  48. package/skills/render-video/scripts/remote_renderer_client.py +9 -7
  49. package/skills/render-video/scripts/render_video.py +72 -15
  50. package/skills/render-video/skill.json +1 -0
  51. package/skills/render-video/version.json +1 -1
  52. package/skills/template-registry/README.md +12 -13
  53. package/skills/template-registry/SKILL.md +11 -12
  54. package/skills/template-registry/scripts/list_templates.py +87 -2
  55. package/skills/template-registry/scripts/registry_loader.py +117 -96
  56. package/skills/template-registry/scripts/render_job_client.py +12 -0
  57. package/skills/template-registry/skill.json +4 -2
  58. package/skills/template-registry/version.json +1 -1
  59. package/skills/template-registry/video_dsl/runtime/dsl_validator.py +2 -2
  60. package/skills/video-parser/skill.json +1 -0
  61. package/skills/web-capture/skill.json +1 -1
  62. package/skills/web-capture/version.json +1 -1
@@ -1,17 +1,29 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
- 模板 registry 加载器 - 统一抽象本地文件 / HTTP API 两种数据源。
3
+ 模板 registry 加载器 - 单一数据源(ab-api HTTP)。
4
4
 
5
5
  为什么独立成一个模块:
6
6
  template-registry、render-video 等多个 skill 都要读 registry,集中在一处便于:
7
7
  - 缓存策略一致(HTTP 拉取 5 分钟 TTL + ETag 复用)
8
- - 解析顺序一致(环境变量 → 本地文件 → monorepo 回退)
9
- - 错误降级一致(HTTP 故障时复用上一次缓存)
8
+ - 错误降级一致(HTTP 故障时复用上一次磁盘缓存)
10
9
 
11
- 环境变量解析优先级(高 → 低):
12
- 1. VIDEO_TEMPLATE_REGISTRY 显式本地文件路径(CI / 调试)
13
- 2. VIDEO_TEMPLATE_REGISTRY_URL HTTP API(生产,多租户由 ab-api 鉴权过滤)
14
- 3. monorepo 默认回退 <repo>/template-library/packages/metadata/registry.json
10
+ 单一数据源(设计取舍):
11
+ registry 只从 ab-api HTTP 接口加载,避免「本地文件 / monorepo 源码 / 数据库」
12
+ 多源并存导致的不一致 —— 私有 / 多租户模板只存在于 ab-api,本地源永远不全。
13
+
14
+ URL 解析:
15
+ 1. 显式 VIDEO_TEMPLATE_REGISTRY_URL(若设置则直接用)
16
+ 2. 否则按 CLI 后端约定推导:
17
+ <MM_API_BASE_URL>/remotionTemplate/registry
18
+ MM_API_BASE_URL 默认 http://localhost:2999/api(与 src/http.ts 一致),
19
+ 兼容 ab-agent 注入的 MM_BACKEND_API_URL。默认值内置在 CLI 自身,独立安装
20
+ (codex / npm i -g)开箱即用,无需宿主在 spawn 时注入。
21
+
22
+ 鉴权:PRIV_TOKEN(env)或 ~/.config/remixmate/credentials.json(同源条目)。
23
+
24
+ monorepo / 显式本地文件等其它来源已**移除**。需要离线 / pinned 数据的维护脚本
25
+ (check_contracts.py / sync_registry.py)直接走 template_paths 读 monorepo,
26
+ 那是 monorepo-only 工具,不是运行时数据源。
15
27
 
16
28
  P1.2 — list/detail split (待后端就绪):
17
29
  100+ 模板时 ``GET /api/template/list`` 应该只返摘要(id / name / aspects /
@@ -21,14 +33,6 @@ P1.2 — list/detail split (待后端就绪):
21
33
  改成「先拉摘要,触发 ``get_template`` 时再补全」,公共 API 不变。
22
34
  调用方今天用 ``get_template(id)`` / ``list_templates()`` 已经是按需消费的形态,
23
35
  迁移时不需要改任何 caller。
24
-
25
- 本地 dev 调试开关:
26
- VIDEO_TEMPLATE_REGISTRY_PREFER_LOCAL=1
27
- 将 monorepo registry.json 提到 #2 之前 —— 即"软优先"语义:
28
- - monorepo 文件存在 → 用本地源码(与 template-library 改动严格一致)
29
- - monorepo 文件不存在 → 自动落到 HTTP API,行为与未开启此开关时一致
30
- 设计意图:让本地开发避开"数据库 template_json 与 template-library 源码不一致"
31
- 导致的渲染问题,同时不破坏在容器/CI 中错误启用此开关时的鲁棒性。
32
36
  """
33
37
 
34
38
  from __future__ import annotations
@@ -43,8 +47,7 @@ import urllib.error
43
47
  import urllib.request
44
48
  from functools import lru_cache
45
49
  from typing import Optional
46
-
47
- from template_paths import monorepo_registry_path
50
+ from urllib.parse import urlparse
48
51
 
49
52
  __all__ = [
50
53
  "load_registry_data",
@@ -67,14 +70,28 @@ _CACHE_DIR = os.environ.get(
67
70
  )
68
71
 
69
72
 
70
- def _monorepo_fallback_path() -> str:
71
- """monorepo registry.json 的路径(仅 dev / 本地单仓部署用)。
73
+ # CLI 默认后端 base,与 remixmate-cli/src/http.ts 的 DEFAULT_API_BASE_URL 保持一致。
74
+ _DEFAULT_API_BASE_URL = "http://localhost:2999/api"
75
+
72
76
 
73
- 路径解析现已统一到 ``template_paths.monorepo_registry_path``;
74
- 本函数保留只是为了让模块内其它函数(``_load_from_url`` 的兜底分支)
75
- 继续按既有名字调用。
77
+ def _default_registry_url() -> str:
78
+ """未显式配置 VIDEO_TEMPLATE_REGISTRY_URL 时,推导默认 ab-api registry endpoint。
79
+
80
+ 默认值内置在 CLI 自身(而非依赖 ab-agent 等宿主在 spawn 时注入),这样
81
+ ``remixmate-cli`` 独立安装(codex / ``npm i -g``)也能开箱即用。
82
+
83
+ base 解析顺序与 CLI / ab-agent 对齐:
84
+ MM_API_BASE_URL(CLI ``src/http.ts`` 约定)
85
+ → MM_BACKEND_API_URL(ab-agent 约定,向后兼容)
86
+ → http://localhost:2999/api(本地 dev 兜底)
87
+ 路径段固定为 ``/remotionTemplate/registry``(POST,返回 ``{code,msg,data}``)。
76
88
  """
77
- return monorepo_registry_path()
89
+ base = (
90
+ os.environ.get("MM_API_BASE_URL", "").strip()
91
+ or os.environ.get("MM_BACKEND_API_URL", "").strip()
92
+ or _DEFAULT_API_BASE_URL
93
+ ).rstrip("/")
94
+ return f"{base}/remotionTemplate/registry"
78
95
 
79
96
 
80
97
  def _cache_path_for(url: str) -> str:
@@ -110,6 +127,60 @@ def _write_cached(cache_file: str, payload: dict) -> None:
110
127
  raise
111
128
 
112
129
 
130
+ # ── PrivToken 解析(env → 凭证库回退)──────────────────────────────────────
131
+ #
132
+ # 与 CLI 的 resolve.ts 共享同一优先级与同一凭证文件路径(Req 7.5)。Python 侧只读
133
+ # 文件存储(不读 keychain —— keychain 由 CLI 写/读,Python 用纯 stdlib 不引依赖)。
134
+
135
+ def _credentials_file_path() -> str:
136
+ """凭证文件路径,与 CLI credential-store.ts 的 CRED_FILE 保持一致。"""
137
+ return os.path.join(os.path.expanduser("~"), ".config", "remixmate", "credentials.json")
138
+
139
+
140
+ def _origin(url: str) -> tuple:
141
+ p = urlparse(url)
142
+ return (p.scheme, p.hostname, p.port)
143
+
144
+
145
+ def _priv_token_from_credential_store(url: str) -> str:
146
+ """从 ~/.config/remixmate/credentials.json 取与 url 同源的 PrivToken。
147
+
148
+ 匹配顺序:① 与 registry URL 同源(scheme/host/port)的条目;② 仅有单条目时直接用。
149
+ secret=='keychain' 的条目跳过(Python 无法读取 keychain)。任何异常静默返回空串。
150
+ """
151
+ try:
152
+ with open(_credentials_file_path(), encoding="utf-8") as f:
153
+ doc = json.load(f)
154
+ except (OSError, json.JSONDecodeError):
155
+ return ""
156
+ creds = doc.get("credentials") if isinstance(doc, dict) else None
157
+ if not isinstance(creds, dict) or not creds:
158
+ return ""
159
+
160
+ target = _origin(url)
161
+ for base_url, entry in creds.items():
162
+ if not isinstance(entry, dict) or entry.get("secret") == "keychain":
163
+ continue
164
+ if _origin(base_url) == target:
165
+ tok = str(entry.get("privToken") or "").strip()
166
+ if tok:
167
+ return tok
168
+ # 单条目兜底:CLI 通常只登录一个后端。
169
+ if len(creds) == 1:
170
+ entry = next(iter(creds.values()))
171
+ if isinstance(entry, dict) and entry.get("secret") != "keychain":
172
+ return str(entry.get("privToken") or "").strip()
173
+ return ""
174
+
175
+
176
+ def _resolve_priv_token(url: str) -> str:
177
+ """PrivToken 解析:环境变量优先,空则回退凭证库(与 CLI 一致的优先级)。"""
178
+ env = os.environ.get("PRIV_TOKEN", "").strip()
179
+ if env:
180
+ return env
181
+ return _priv_token_from_credential_store(url)
182
+
183
+
113
184
  def _fetch_http(url: str, timeout: int) -> dict:
114
185
  """执行 HTTP 请求,自动加 X-Priv-Token / If-None-Match 头。
115
186
 
@@ -127,7 +198,7 @@ def _fetch_http(url: str, timeout: int) -> dict:
127
198
  headers = {"Accept": "application/json"}
128
199
  if method == "POST":
129
200
  headers["Content-Type"] = "application/json"
130
- if token := os.environ.get("PRIV_TOKEN", "").strip():
201
+ if token := _resolve_priv_token(url):
131
202
  headers["X-Priv-Token"] = token
132
203
  if cached and (etag := cached.get("etag")):
133
204
  headers["If-None-Match"] = etag
@@ -166,10 +237,8 @@ def _fetch_http(url: str, timeout: int) -> dict:
166
237
 
167
238
 
168
239
  def _load_from_url(url: str, ttl: int, timeout: int) -> dict:
169
- """先看缓存是否在 TTL 内;超期则远程拉取,失败时按以下顺序降级:
170
- 1. HTTP 缓存(fetchedAt 之后的最后一份成功响应)
171
- 2. monorepo 本地 registry.json(仅本地 dev 时存在)
172
- 3. 都没有则抛错
240
+ """先看缓存是否在 TTL 内;超期则远程拉取。失败时降级到磁盘缓存(同一 URL
241
+ 上一份成功响应),无缓存则抛错 —— 不再回退本地文件 / monorepo,保证单一数据源。
173
242
  """
174
243
  cache_file = _cache_path_for(url)
175
244
  cached = _read_cached(cache_file)
@@ -181,38 +250,20 @@ def _load_from_url(url: str, ttl: int, timeout: int) -> dict:
181
250
  try:
182
251
  return _fetch_http(url, timeout)
183
252
  except Exception as exc:
184
- # 1. HTTP 故障时降级:有缓存就继续用,写日志告警
253
+ # HTTP 故障时降级:有磁盘缓存就继续用(同一数据源的容错,不是第二个源)
185
254
  if cached:
186
255
  print(
187
256
  f"⚠️ registry HTTP 拉取失败,降级使用本地缓存: {exc}",
188
257
  file=sys.stderr,
189
258
  )
190
259
  return cached["data"]
191
- # 2. 没缓存再尝试 monorepo fallback(本地 dev / 单仓库部署时这条路一定通)
192
- fallback = _monorepo_fallback_path()
193
- if os.path.exists(fallback):
194
- print(
195
- f"⚠️ registry HTTP 拉取失败且无 HTTP 缓存,降级使用 monorepo registry: {exc}",
196
- file=sys.stderr,
197
- )
198
- return _load_from_file(fallback)
199
- # 3. 都没有,向上抛
200
260
  raise RuntimeError(
201
- f"registry HTTP 拉取失败且无可用缓存 / 本地 fallback: {url} ({exc})"
261
+ f"registry HTTP 拉取失败且无可用缓存: {url} ({exc})"
262
+ f" 请确认 ab-api 可达、VIDEO_TEMPLATE_REGISTRY_URL / MM_API_BASE_URL"
263
+ f" 配置正确,并已设置有效 PRIV_TOKEN。"
202
264
  ) from exc
203
265
 
204
266
 
205
- def _load_from_file(path: str) -> dict:
206
- """从本地文件加载并解析 registry.json。"""
207
- with open(path, "r", encoding="utf-8") as f:
208
- return json.load(f)
209
-
210
-
211
- def _truthy(value: str) -> bool:
212
- """统一解析布尔型环境变量:1 / true / yes / on(大小写不敏感)。"""
213
- return value.strip().lower() in ("1", "true", "yes", "on")
214
-
215
-
216
267
  def load_registry_data(
217
268
  *,
218
269
  ttl_seconds: int = _DEFAULT_TTL_SECONDS,
@@ -220,56 +271,21 @@ def load_registry_data(
220
271
  ) -> dict:
221
272
  """加载 registry 完整文档(含 version / generatedAt / templates)。
222
273
 
223
- 解析顺序:
224
- 1. 环境变量 VIDEO_TEMPLATE_REGISTRY 指定的本地文件
225
- 2. VIDEO_TEMPLATE_REGISTRY_PREFER_LOCAL 开启且 monorepo registry 存在,先走本地
226
- 3. 环境变量 VIDEO_TEMPLATE_REGISTRY_URL 指定的 HTTP API(带缓存)
227
- 4. monorepo 默认回退(仅本地 dev 有效)
228
-
229
- 任何来源都返回相同形状的 dict,调用方按 `data.get("templates", [])` 取列表。
274
+ 单一数据源:ab-api HTTP。URL 取显式 ``VIDEO_TEMPLATE_REGISTRY_URL``,
275
+ 未设置则按 ``MM_API_BASE_URL`` 推导(见 ``_default_registry_url``)。
276
+ 带磁盘缓存(TTL + ETag/304),返回 ``data.get("templates", [])`` 形状的 dict。
230
277
  """
231
- if explicit_path := os.environ.get("VIDEO_TEMPLATE_REGISTRY", "").strip():
232
- print(f"[registry_loader] using explicit file: {explicit_path}", file=sys.stderr)
233
- return _load_from_file(explicit_path)
234
-
235
- prefer_local = _truthy(os.environ.get("VIDEO_TEMPLATE_REGISTRY_PREFER_LOCAL", ""))
236
- fallback = _monorepo_fallback_path()
237
-
238
- if prefer_local and os.path.exists(fallback):
278
+ url = os.environ.get("VIDEO_TEMPLATE_REGISTRY_URL", "").strip()
279
+ if url:
280
+ print(f"[registry_loader] using HTTP registry: {url}", file=sys.stderr)
281
+ else:
282
+ url = _default_registry_url()
239
283
  print(
240
- f"[registry_loader] PREFER_LOCAL=1, using monorepo registry: {fallback}",
284
+ f"[registry_loader] VIDEO_TEMPLATE_REGISTRY_URL unset; using derived"
285
+ f" default URL: {url}",
241
286
  file=sys.stderr,
242
287
  )
243
- return _load_from_file(fallback)
244
-
245
- if url := os.environ.get("VIDEO_TEMPLATE_REGISTRY_URL", "").strip():
246
- if prefer_local:
247
- # 走到这里说明开启了 PREFER_LOCAL 但 monorepo 文件不存在 —— 例如容器里
248
- # 误启用此开关。给出明确告警,避免使用者以为还在用本地源码。
249
- print(
250
- f"[registry_loader] PREFER_LOCAL=1 but monorepo registry not found"
251
- f" ({fallback}), falling back to HTTP: {url}",
252
- file=sys.stderr,
253
- )
254
- else:
255
- print(f"[registry_loader] using HTTP registry: {url}", file=sys.stderr)
256
- return _load_from_url(url, ttl=ttl_seconds, timeout=http_timeout)
257
-
258
- # 第 ③ 级:monorepo 相对路径兜底。仅在该文件【实际存在】时生效
259
- # (私有 monorepo 本地源码可见的场景)。独立开源仓库 clone / npm 安装
260
- # 后该路径不存在,这里静默跳过,不抛错、不中断,落到下方的可理解失败。
261
- if os.path.exists(fallback):
262
- print(
263
- f"[registry_loader] using monorepo registry (default fallback): {fallback}",
264
- file=sys.stderr,
265
- )
266
- return _load_from_file(fallback)
267
-
268
- raise RuntimeError(
269
- "找不到模板 registry。请设置 VIDEO_TEMPLATE_REGISTRY_URL(ab-api HTTP 接口)"
270
- " 并配置有效的 PRIV_TOKEN,或用 VIDEO_TEMPLATE_REGISTRY 指向一份本地"
271
- " registry.json。(monorepo 内本地源码可见时会自动走 template-library 兜底。)"
272
- )
288
+ return _load_from_url(url, ttl=ttl_seconds, timeout=http_timeout)
273
289
 
274
290
 
275
291
  # ════════════════════════════════════════════════════════════════════════════
@@ -291,6 +307,11 @@ _DEFAULT_STATUS = "stable"
291
307
  _BETA_GATE_ENV = "ENABLE_BETA_TEMPLATES"
292
308
 
293
309
 
310
+ def _truthy(value: str) -> bool:
311
+ """统一解析布尔型环境变量:1 / true / yes / on(大小写不敏感)。"""
312
+ return value.strip().lower() in ("1", "true", "yes", "on")
313
+
314
+
294
315
  def _truthy_env(name: str) -> bool:
295
316
  return _truthy(os.environ.get(name, ""))
296
317
 
@@ -136,6 +136,18 @@ def get_job(job_id: int, priv_token: str) -> dict:
136
136
  return _post("/renderJob/get", {"jobId": job_id}, priv_token)
137
137
 
138
138
 
139
+ def presign_template_source(template_key: str, priv_token: str) -> dict:
140
+ """
141
+ 为已注册私有模板的源码包申请临时 GET 下载 URL(渲染取包用)。
142
+
143
+ 调 ab-api /remotionTemplate/presignSource,返回 { tarballUrl, sourceOssKey, version }。
144
+ ab-render 用 tarballUrl 走 /renderDraft 动态 bundle 渲染。
145
+
146
+ 注意:presignSource 端点不在 /renderJob 下,路径以 / 开头直接拼到 _api_base。
147
+ """
148
+ return _post("/remotionTemplate/presignSource", {"templateKey": template_key}, priv_token)
149
+
150
+
139
151
  # ─── CLI self-test ────────────────────────────────────────────────────────────
140
152
 
141
153
  if __name__ == "__main__":
@@ -2,19 +2,21 @@
2
2
  "name": "template-registry",
3
3
  "toolName": "template_registry",
4
4
  "tier": "orchestration",
5
+ "category": "authoring",
5
6
  "title": "Video Template Registry",
6
7
  "description": "List all available video templates (templateId / name / aspect ratio / style tags). Template-to-DSL binding is no longer exposed as a separate step — once prepare_video_assets receives a template_id it runs the full DSL→RenderPlan pipeline internally.",
7
- "envVars": ["PRIV_TOKEN", "VIDEO_TEMPLATE_REGISTRY", "VIDEO_TEMPLATE_REGISTRY_URL", "VIDEO_TEMPLATE_REGISTRY_HTTP_METHOD"],
8
+ "envVars": ["PRIV_TOKEN", "VIDEO_TEMPLATE_REGISTRY_URL", "MM_API_BASE_URL", "VIDEO_TEMPLATE_REGISTRY_HTTP_METHOD"],
8
9
  "entry": { "type": "python", "scriptPath": "scripts/list_templates.py" },
9
10
  "parameters": {
10
11
  "type": "object",
11
12
  "properties": {
12
13
  "list_templates": { "type": "boolean", "description": "List available templates (default behavior; also implied when other flags are passed)." },
14
+ "list_examples": { "type": "boolean", "description": "List the *.dsl.json / *.binding.json reference examples shipped under template-registry/video_dsl/schema/examples/, grouped by templateId. Useful for downstream agents (e.g. a creation agent) that want to read a template's reference shape before producing new DSL." },
13
15
  "filter_tag": { "type": "string", "description": "Show only templates whose styleTags contain (or are contained in) this string. Case-insensitive. E.g. 'tech' / '科普' / 'walkthrough'." },
14
16
  "filter_aspect": { "type": "string", "description": "Show only templates that declare this aspect ratio. E.g. '9:16' / '16:9' / '1:1'." },
15
17
  "filter_language": { "type": "string", "description": "Show only templates whose contentLanguage includes this code ('zh' or 'en'). Templates with no declared language are always shown (treated as language-agnostic)." },
16
18
  "include_beta": { "type": "boolean", "description": "Also list templates with status='beta'. Default off (only 'stable' shows). The ENABLE_BETA_TEMPLATES env var has the same effect process-wide." },
17
- "json_output": { "type": "boolean", "description": "Emit a JSON result ({ templates: [...] }) instead of the human-readable table." }
19
+ "json_output": { "type": "boolean", "description": "Emit a JSON result ({ templates: [...] } or { examples: [...] }) instead of the human-readable table." }
18
20
  },
19
21
  "required": []
20
22
  }
@@ -2,6 +2,6 @@
2
2
  "skillName": "template-registry",
3
3
  "repoName": "agent-skill-media-maker",
4
4
  "skillId": "475",
5
- "version": "V12",
5
+ "version": "V13",
6
6
  "skillDescription": "视频模板仓库(列表查询)。存储所有视频模板定义,对外只暴露「列出可用模板」一个能力;DSL→TemplateBinding 的绑定逻辑已内嵌进 prepare-video-assets,不再作为独立步骤暴露。同时是跨 skill 共享 Python 库(registry_loader / match_template / template_paths / video_dsl 等)的存放位置。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- 查看可用模板、列出所有模板"
7
7
  }
@@ -17,7 +17,7 @@ DSL 校验器 - 对 Video DSL v1alpha1 做结构校验与标准化。
17
17
  ``lineSyncSlides`` 注册表查询、items 数对齐、模板专属语言约束等代码在三份
18
18
  之间已经静默漂移。统一到本文件后,所有维度只有一份实现。所有模板差异通过
19
19
  ``template.json`` 的 ``capabilities`` 字段声明,本文件读取并应用 —— 新增需要特殊
20
- 处理的模板时**不需要再改 ab-skill 代码**。
20
+ 处理的模板时**不需要再改 remixmate 代码**。
21
21
  """
22
22
 
23
23
  import re
@@ -93,7 +93,7 @@ def _line_sync_slides_for_template(template_id: Optional[str]) -> dict[str, str]
93
93
  """Look up ``lineSyncSlides`` for a template from registry.json.
94
94
 
95
95
  新增多项卡片幻灯片只需在 template.json 加一行 ``lineSyncSlides[slideId] = key``,
96
- 不再需要改 ab-skill。registry 读取失败(环境缺 registry_loader、HTTP 不通等)
96
+ 不再需要改 remixmate。registry 读取失败(环境缺 registry_loader、HTTP 不通等)
97
97
  时返回空 dict,调用方将跳过相关校验。
98
98
 
99
99
  O(1) lookup via ``registry_loader.get_template``; safe to call once per
@@ -2,6 +2,7 @@
2
2
  "name": "video-parser",
3
3
  "toolName": "video_parser",
4
4
  "tier": "tool",
5
+ "category": "consuming",
5
6
  "title": "Video Deconstruction",
6
7
  "description": "Video deconstruction: split a video into reusable assets (audio extraction, ASR transcript, keyframe extraction, scene segmentation).",
7
8
  "envVars": ["RENDER_API_URL", "PRIV_TOKEN", "CONVERSATION_ID"],
@@ -2,11 +2,11 @@
2
2
  "name": "web-capture",
3
3
  "toolName": "web_capture",
4
4
  "tier": "tool",
5
+ "category": "consuming",
5
6
  "title": "Web Page Capture",
6
7
  "description": "Drive a headless browser (Playwright Python) to capture any URL to local files: full-page / element / region screenshots, fixed-duration / condition-triggered / auto-scroll recordings, and storyboard videos (highlight / focus / zoom / scroll / virtual-cursor click / caption / title-card / arrow / numbered sequence / redact / code-line highlight). Two entry scripts: scripts/screenshot.py (stills) and scripts/record.py (webm video, storyboards, templates).",
7
8
  "envVars": ["WEB_CAPTURE_BROWSER", "WEB_CAPTURE_OUTPUT_BASE", "WEB_CAPTURE_NO_SANDBOX", "WEB_CAPTURE_ALLOW_PRIVATE_HOSTS", "PLAYWRIGHT_BROWSERS_PATH"],
8
9
  "entry": { "type": "python", "scriptPath": "scripts/screenshot.py" },
9
- "scriptPath": "scripts/screenshot.py",
10
10
  "parameters": {
11
11
  "type": "object",
12
12
  "properties": {
@@ -2,6 +2,6 @@
2
2
  "skillName": "web-capture",
3
3
  "repoName": "agent-skill-media-maker",
4
4
  "skillId": "555",
5
- "version": "V3",
5
+ "version": "V4",
6
6
  "skillDescription": "网页截屏 / 录屏 / 分镜视频技能,基于 Playwright Python,对任意 URL 落盘到本地。支持整页 / 元素 / 区域截屏、固定时长 / 条件触发 / 自动滚动录屏、分镜视频(高亮 / 聚焦 / 放大 / 滚动 / 虚拟光标点击 / 字幕 / 标题卡 / 箭头 / 编号序列 / 打码 / 代码行高亮)以及参数化模板。两个入口脚本:scripts/screenshot.py(截图)与 scripts/record.py(webm 录屏 / storyboard / 模板)。\n\n当用户提到网页截图、整页 / 长截图、元素 / 区域截屏、录屏、滚动录屏、分镜 / storyboard 视频、虚拟光标点击 / 输入 / 悬停演示、加箭头 / 字幕 / 标题卡 / 编号高亮、隐藏或打码敏感信息、代码行高亮、移动端模拟、带登录态截屏 / 录屏等需求时,立即使用本 skill。"
7
7
  }