@remixmate/cli 0.9.71 → 0.9.73

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 (181) hide show
  1. package/LICENSE +45 -21
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/dist/argv.js +1 -51
  5. package/dist/auth/auth-lock.js +1 -100
  6. package/dist/auth/auto-login.js +7 -75
  7. package/dist/auth/commands.js +40 -290
  8. package/dist/auth/credential-store.js +1 -143
  9. package/dist/auth/device-flow-runner.js +13 -110
  10. package/dist/auth/device-flow.js +1 -132
  11. package/dist/auth/ensure.js +1 -62
  12. package/dist/auth/environment.js +1 -69
  13. package/dist/auth/pending-store.js +1 -45
  14. package/dist/auth/resolve.js +1 -44
  15. package/dist/billing.js +3 -76
  16. package/dist/capabilities.js +1 -75
  17. package/dist/cli.js +39 -211
  18. package/dist/diagnostics.js +2 -70
  19. package/dist/doctor.js +9 -188
  20. package/dist/errors.js +1 -33
  21. package/dist/exec.js +4 -47
  22. package/dist/handlers/gen-digital-human.js +33 -264
  23. package/dist/handlers/gen-image.js +9 -113
  24. package/dist/handlers/gen-post.js +15 -188
  25. package/dist/handlers/gen-video.js +7 -185
  26. package/dist/handlers/gen-voice.js +19 -133
  27. package/dist/handlers/index.js +1 -20
  28. package/dist/handlers/shared.js +1 -66
  29. package/dist/handlers/template-init.js +1 -21
  30. package/dist/http.js +3 -155
  31. package/dist/index.js +1 -8
  32. package/dist/install.js +40 -448
  33. package/dist/manifest.json +53 -13
  34. package/dist/progress.js +2 -15
  35. package/dist/project/commands.js +34 -156
  36. package/dist/project/host.js +1 -151
  37. package/dist/project/resolve.js +1 -65
  38. package/dist/project/store.js +2 -97
  39. package/dist/project/take.js +1 -106
  40. package/dist/project/trace.js +5 -278
  41. package/dist/registry.js +3 -70
  42. package/dist/runner.js +7 -225
  43. package/dist/skill-schema.js +1 -194
  44. package/dist/template/args.js +1 -69
  45. package/dist/template/check.js +2 -30
  46. package/dist/template/commands.js +34 -163
  47. package/dist/template/constants.js +1 -46
  48. package/dist/template/init.js +5 -133
  49. package/dist/template/list.js +1 -46
  50. package/dist/template/preview.js +7 -318
  51. package/dist/template/proc.js +1 -43
  52. package/dist/template/project.js +6 -161
  53. package/dist/template/publish.js +5 -185
  54. package/dist/template/render-client.js +2 -79
  55. package/dist/template/upgrade.js +4 -123
  56. package/dist/text.js +1 -15
  57. package/package.json +2 -35
  58. package/skills/doc-parse/scripts/extract_via_render.py +32 -32
  59. package/skills/export-jianying/scripts/gen_jianying_draft.py +188 -188
  60. package/skills/gen-post/SKILL.md +23 -13
  61. package/skills/gen-post/skill.json +9 -10
  62. package/skills/gen-script/SKILL.md +23 -1
  63. package/skills/gen-script/scripts/gen_script.py +644 -551
  64. package/skills/gen-script/skill.json +12 -0
  65. package/skills/gen-script/version.json +1 -1
  66. package/skills/prepare-video-assets/scripts/prepare_video_assets.py +21 -21
  67. package/skills/render-video/scripts/_chrome_vendor.py +17 -17
  68. package/skills/render-video/scripts/_digital_human_segments.py +34 -34
  69. package/skills/render-video/scripts/_video_probe.py +33 -33
  70. package/skills/render-video/scripts/_vod_polling.py +13 -13
  71. package/skills/render-video/scripts/remote_renderer_client.py +42 -42
  72. package/skills/render-video/scripts/render_video.py +639 -639
  73. package/skills/render-video/scripts/required_props.py +37 -37
  74. package/skills/render-video/scripts/upload_video.py +35 -35
  75. package/skills/render-video/version.json +1 -1
  76. package/skills/template-registry/SKILL.md +16 -0
  77. package/skills/template-registry/scripts/countdown_spec.py +92 -92
  78. package/skills/template-registry/scripts/doc_extract.py +40 -40
  79. package/skills/template-registry/scripts/list_templates.py +303 -191
  80. package/skills/template-registry/scripts/log_diagnostics.py +1 -1
  81. package/skills/template-registry/scripts/match_template.py +87 -87
  82. package/skills/template-registry/scripts/payload_hydrator.py +89 -89
  83. package/skills/template-registry/scripts/registry_loader.py +159 -159
  84. package/skills/template-registry/scripts/render_job_client.py +75 -75
  85. package/skills/template-registry/scripts/showcase_loader.py +44 -44
  86. package/skills/template-registry/skill.json +4 -1
  87. package/skills/template-registry/version.json +1 -1
  88. package/skills/template-registry/video_dsl/runtime/__init__.py +8 -8
  89. package/skills/template-registry/video_dsl/runtime/dsl_validator.py +329 -329
  90. package/skills/template-registry/video_dsl/runtime/narration_budget.py +36 -36
  91. package/skills/template-registry/video_dsl/runtime/payload_contract.py +7 -7
  92. package/skills/template-registry/video_dsl/runtime/prompt_enhancer.py +98 -98
  93. package/skills/template-registry/video_dsl/runtime/timeline_compiler.py +127 -127
  94. package/skills/template-registry/video_dsl/schema/video-dsl-v1alpha1.json +14 -1
  95. package/skills/video-parser/scripts/analyze_video.py +173 -173
  96. package/skills/video-parser/scripts/deconstruct_video.py +91 -91
  97. package/skills/video-parser/scripts/parse_via_render.py +21 -21
  98. package/skills/web-screenshot/scripts/_media_screenshot/__init__.py +4 -4
  99. package/skills/web-screenshot/scripts/_media_screenshot/bootstrap.py +7 -7
  100. package/skills/web-screenshot/scripts/_media_screenshot/browser.py +4 -4
  101. package/skills/web-screenshot/scripts/_media_screenshot/cli_args.py +4 -4
  102. package/skills/web-screenshot/scripts/_media_screenshot/js_loader.py +2 -2
  103. package/skills/web-screenshot/scripts/_media_screenshot/overlay.py +1 -1
  104. package/skills/web-screenshot/scripts/_media_screenshot/reader.py +40 -40
  105. package/skills/web-screenshot/scripts/_media_screenshot/recording.py +11 -11
  106. package/skills/web-screenshot/scripts/_media_screenshot/scenes/__init__.py +8 -8
  107. package/skills/web-screenshot/scripts/_media_screenshot/scenes/arrow.py +2 -2
  108. package/skills/web-screenshot/scripts/_media_screenshot/scenes/caption.py +1 -1
  109. package/skills/web-screenshot/scripts/_media_screenshot/scenes/click.py +1 -1
  110. package/skills/web-screenshot/scripts/_media_screenshot/scenes/code_lines.py +5 -5
  111. package/skills/web-screenshot/scripts/_media_screenshot/scenes/focus.py +1 -1
  112. package/skills/web-screenshot/scripts/_media_screenshot/scenes/highlight.py +3 -3
  113. package/skills/web-screenshot/scripts/_media_screenshot/scenes/hover.py +1 -1
  114. package/skills/web-screenshot/scripts/_media_screenshot/scenes/redact.py +1 -1
  115. package/skills/web-screenshot/scripts/_media_screenshot/scenes/scroll.py +1 -1
  116. package/skills/web-screenshot/scripts/_media_screenshot/scenes/sequence.py +1 -1
  117. package/skills/web-screenshot/scripts/_media_screenshot/scenes/title_card.py +1 -1
  118. package/skills/web-screenshot/scripts/_media_screenshot/scenes/type.py +1 -1
  119. package/skills/web-screenshot/scripts/_media_screenshot/scenes/wait.py +1 -1
  120. package/skills/web-screenshot/scripts/_media_screenshot/scenes/zoom.py +2 -2
  121. package/skills/web-screenshot/scripts/_media_screenshot/screenshot.py +15 -15
  122. package/skills/web-screenshot/scripts/_media_screenshot/storyboard.py +2 -2
  123. package/skills/web-screenshot/scripts/_media_screenshot/template.py +11 -11
  124. package/skills/web-screenshot/scripts/_media_screenshot/trim.py +10 -10
  125. package/skills/web-screenshot/scripts/_media_screenshot/urlguard.py +22 -22
  126. package/skills/web-screenshot/scripts/_media_upload.py +33 -33
  127. package/skills/web-screenshot/scripts/read_page.py +15 -15
  128. package/skills/web-screenshot/scripts/record.py +26 -26
  129. package/skills/web-screenshot/scripts/screenshot.py +5 -5
  130. package/dist/argv.d.ts +0 -15
  131. package/dist/auth/auth-lock.d.ts +0 -26
  132. package/dist/auth/auto-login.d.ts +0 -20
  133. package/dist/auth/commands.d.ts +0 -8
  134. package/dist/auth/credential-store.d.ts +0 -60
  135. package/dist/auth/device-flow-runner.d.ts +0 -58
  136. package/dist/auth/device-flow.d.ts +0 -52
  137. package/dist/auth/ensure.d.ts +0 -55
  138. package/dist/auth/environment.d.ts +0 -38
  139. package/dist/auth/pending-store.d.ts +0 -33
  140. package/dist/auth/resolve.d.ts +0 -30
  141. package/dist/billing.d.ts +0 -44
  142. package/dist/capabilities.d.ts +0 -63
  143. package/dist/cli.d.ts +0 -13
  144. package/dist/diagnostics.d.ts +0 -24
  145. package/dist/doctor.d.ts +0 -22
  146. package/dist/errors.d.ts +0 -29
  147. package/dist/exec.d.ts +0 -18
  148. package/dist/handlers/gen-digital-human.d.ts +0 -17
  149. package/dist/handlers/gen-image.d.ts +0 -20
  150. package/dist/handlers/gen-post.d.ts +0 -21
  151. package/dist/handlers/gen-video.d.ts +0 -19
  152. package/dist/handlers/gen-voice.d.ts +0 -26
  153. package/dist/handlers/index.d.ts +0 -20
  154. package/dist/handlers/shared.d.ts +0 -26
  155. package/dist/handlers/template-init.d.ts +0 -10
  156. package/dist/http.d.ts +0 -72
  157. package/dist/index.d.ts +0 -9
  158. package/dist/install.d.ts +0 -71
  159. package/dist/progress.d.ts +0 -23
  160. package/dist/project/commands.d.ts +0 -19
  161. package/dist/project/host.d.ts +0 -91
  162. package/dist/project/resolve.d.ts +0 -43
  163. package/dist/project/store.d.ts +0 -31
  164. package/dist/project/take.d.ts +0 -50
  165. package/dist/project/trace.d.ts +0 -98
  166. package/dist/registry.d.ts +0 -30
  167. package/dist/runner.d.ts +0 -39
  168. package/dist/skill-schema.d.ts +0 -138
  169. package/dist/template/args.d.ts +0 -25
  170. package/dist/template/check.d.ts +0 -23
  171. package/dist/template/commands.d.ts +0 -25
  172. package/dist/template/constants.d.ts +0 -39
  173. package/dist/template/init.d.ts +0 -28
  174. package/dist/template/list.d.ts +0 -23
  175. package/dist/template/preview.d.ts +0 -60
  176. package/dist/template/proc.d.ts +0 -26
  177. package/dist/template/project.d.ts +0 -47
  178. package/dist/template/publish.d.ts +0 -43
  179. package/dist/template/render-client.d.ts +0 -39
  180. package/dist/template/upgrade.d.ts +0 -44
  181. package/dist/text.d.ts +0 -8
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env python3
2
- """
3
- render_job_client.py — ab-api renderJob 接口 Python 客户端
4
2
 
5
- 封装对 ab-api /api/renderJob/* 的调用,供 render_video.py 和
6
- gen_jianying_draft.py 使用。
7
3
 
8
- 认证方式: X-Priv-Token header(与其他 skill 脚本一致)
9
- 接口地址: 优先读 MM_API_BASE_URL(executor 显式转发、全链路标准名),
10
- 回退 MM_BACKEND_API_URL,再回退默认 https://api.remixmate.ai/api。
11
- 两个变量语义相同,保留回退是为兼容只配了其中一个的部署环境。
12
- """
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
13
 
14
14
  from log_diagnostics import trace_headers
15
15
  import json
@@ -39,10 +39,10 @@ def _make_headers(priv_token: str) -> dict:
39
39
  return headers
40
40
 
41
41
 
42
- # ─── 扣费回传 ────────────────────────────────────────────────────────────────
43
- # ab-api 会在扣了积分的成功响应上挂 billing 字段(见 core.Success)。渲染积分是在
44
- # /renderJob/saveManifest 里扣的,所以这里是渲染花费唯一的可见入口——累加起来交给
45
- # render_video.py 在收尾时统一告知用户。
42
+
43
+
44
+
45
+
46
46
  _BILLING: dict = {"credits": 0, "balance": None}
47
47
 
48
48
 
@@ -60,12 +60,12 @@ def _record_billing(result: dict) -> None:
60
60
 
61
61
 
62
62
  def billing_summary() -> dict:
63
- """本进程通过本模块产生的累计扣费:{"credits": int, "balance": int|None}。"""
63
+
64
64
  return dict(_BILLING)
65
65
 
66
66
 
67
67
  def _post(path: str, payload: dict, priv_token: str, timeout: int = 30) -> dict:
68
- """发送 POST 请求并返回响应 data 字段;失败时抛出 RuntimeError。"""
68
+
69
69
  url = f"{_api_base()}{path}"
70
70
  body = json.dumps(payload).encode("utf-8")
71
71
  req = urllib.request.Request(url, data=body, headers=_make_headers(priv_token), method="POST")
@@ -86,33 +86,33 @@ def _post(path: str, payload: dict, priv_token: str, timeout: int = 30) -> dict:
86
86
  return result.get("data") or {}
87
87
 
88
88
 
89
- # ─────────────────────────────────────────────────────────────────────────────
89
+
90
90
 
91
91
 
92
92
  def create_job(priv_token: str, dsl: str = "", dsl_meta: dict = None) -> int:
93
- """
94
- 创建渲染任务。
95
93
 
96
- 会话归属:本函数会自动带上环境变量 CONVERSATION_ID(若已设置),让服务端在
97
- 创建时就把 job 挂到该会话的 take 上。
98
94
 
99
- 为什么要在这里传:渲染任务过去出生就是孤儿——归属全靠事后一次独立的补绑调用,
100
- 而那条路上有四个静默盲区(CLI 的 take 绑定在 job 出生前就跑完了;云端因为
101
- CONVERSATION_ID 已被注入而整段跳过它;兜底补绑的 jobId 末位来源是从 stdout
102
- 正则抠的)。归属断了,成片在旁白面板里就查不到已生成的音频。
103
- 而 CONVERSATION_ID 在这一刻本来就已经在环境里了——信息在场,以前只是没传。
104
- 见 ab-platform/docs/engineering/render-job-binding-fix.md。
105
95
 
106
- 服务端对该字段是软失败:绑不上只记日志,不影响任务创建。
107
96
 
108
- Args:
109
- priv_token: PrivToken
110
- dsl: 完整 DSL JSON 字符串(可选)
111
- dsl_meta: DSL 摘要字典(可选,将被序列化为 JSON)
112
97
 
113
- Returns:
114
- jobId (int)
115
- """
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
116
  payload: dict = {}
117
117
  if dsl:
118
118
  payload["dsl"] = dsl
@@ -131,28 +131,28 @@ def create_job(priv_token: str, dsl: str = "", dsl_meta: dict = None) -> int:
131
131
 
132
132
 
133
133
  def save_plan(job_id: int, render_plan: str, priv_token: str) -> None:
134
- """
135
- 保存 RenderPlan 到数据库(Phase 1 完成后调用)。
136
-
137
- Args:
138
- job_id: 渲染任务 ID
139
- render_plan: 完整 RenderPlan JSON 字符串
140
- priv_token: PrivToken
141
- """
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+
142
142
  _post("/renderJob/savePlan", {"jobId": job_id, "renderPlan": render_plan}, priv_token)
143
143
 
144
144
 
145
145
  def get_plan(job_id: int, priv_token: str) -> str:
146
- """
147
- 从数据库加载 RenderPlan(Phase 2 开始前调用)。
148
146
 
149
- Args:
150
- job_id: 渲染任务 ID
151
- priv_token: PrivToken
152
147
 
153
- Returns:
154
- RenderPlan JSON 字符串
155
- """
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
156
  data = _post("/renderJob/getPlan", {"jobId": job_id}, priv_token)
157
157
  render_plan = data.get("renderPlan")
158
158
  if not render_plan:
@@ -161,28 +161,28 @@ def get_plan(job_id: int, priv_token: str) -> str:
161
161
 
162
162
 
163
163
  def save_manifest(job_id: int, manifest: dict, priv_token: str) -> None:
164
- """
165
- 保存渲染结果到数据库(渲染完成后调用)。
166
-
167
- Args:
168
- job_id: 渲染任务 ID
169
- manifest: 渲染结果字典
170
- priv_token: PrivToken
171
- """
164
+
165
+
166
+
167
+
168
+
169
+
170
+
171
+
172
172
  _post("/renderJob/saveManifest", {"jobId": job_id, "manifest": manifest}, priv_token)
173
173
 
174
174
 
175
175
  def latest_job(conversation_id: str, priv_token: str) -> dict:
176
- """
177
- 按会话取最近一次**已存 RenderPlan** 的渲染任务摘要(POST /renderJob/latest)。
178
176
 
179
- 多轮对话里模型看不到之前的工具结果,拿不到 jobId;消费上一轮成果的 skill
180
- (如 export-jianying)用注入的 CONVERSATION_ID 反查最新一版,而不是让模型从
181
- 聊天记录里拼素材 URL —— 那样会拿到过期的旧版素材。
182
177
 
183
- Returns:
184
- {"jobId": int, "status": str, "attempt": int, "createTime": str, "updateTime": str}
185
- """
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
186
  data = _post("/renderJob/latest", {"conversationId": conversation_id}, priv_token)
187
187
  if not data.get("jobId"):
188
188
  raise RuntimeError("no render job with a saved RenderPlan in this conversation")
@@ -190,20 +190,20 @@ def latest_job(conversation_id: str, priv_token: str) -> dict:
190
190
 
191
191
 
192
192
  def get_job(job_id: int, priv_token: str) -> dict:
193
- """
194
- 获取渲染任务完整详情。
195
193
 
196
- Args:
197
- job_id: 渲染任务 ID
198
- priv_token: PrivToken
199
194
 
200
- Returns:
201
- 任务详情字典(含 status / renderPlan / manifest 等)
202
- """
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
203
  return _post("/renderJob/get", {"jobId": job_id}, priv_token)
204
204
 
205
205
 
206
- # ─── CLI self-test ────────────────────────────────────────────────────────────
206
+
207
207
 
208
208
  if __name__ == "__main__":
209
209
  import argparse
@@ -1,32 +1,32 @@
1
- """Showcase (sample video) loader — per-template samples + web detail-page links.
2
1
 
3
- Used by ``list_templates.py`` so an agent host (Codex CLI / Codex Desktop /
4
- Claude Code) can show the user how many samples a template has and a link to
5
- the web detail page where the samples play.
6
2
 
7
- Contract (ab-api ``POST /templateShowcase/listByTemplate``, X-Priv-Token):
8
3
 
9
- request {"templateKeys": [...], "limitPerTemplate": N}
10
- response {code, msg, data: {"templates": [
11
- {"templateKey", "pageUrl"?, "showcaseCount",
12
- "showcases": [{"showcaseId", "name", "coverImage", "videoUrl",
13
- "aspectRatio", "duration", "hasDemo", "pageUrl"?, ...}]}
14
- ]}}
15
4
 
16
- Links are built server-side; the CLI never knows the web origin or routes.
17
5
 
18
- Unlike the registry, samples are *enhancement* data: every failure (network,
19
- older ab-api without the endpoint, business error, bad JSON) returns ``None``
20
- with one stderr warning, and the caller keeps printing the template list.
21
- Auth failures are also degraded here — the registry call that precedes this
22
- one already surfaces them with the proper exit code.
23
6
 
24
- Env:
25
- VIDEO_TEMPLATE_SHOWCASE_URL explicit endpoint (tests point it at file://)
26
- MM_API_BASE_URL / MM_BACKEND_API_URL base, same resolution as the registry
27
- PRIV_TOKEN injected by the CLI runner
28
- VIDEO_TEMPLATE_REGISTRY_CACHE_DIR shared cache dir
29
- """
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
30
 
31
31
  from __future__ import annotations
32
32
 
@@ -41,14 +41,14 @@ from typing import Optional
41
41
 
42
42
  from registry_loader import api_base_url
43
43
 
44
- # Never longer than the registry TTL: a sample added in ShowcaseManager should
45
- # show up about as fast as a template change does.
44
+
45
+
46
46
  _TTL_SECONDS = 300
47
47
  _HTTP_TIMEOUT = 5
48
48
 
49
- # Item fields kept in CLI output. The endpoint returns the full wizard item
50
- # (replicateConfig, layoutPreview, tags …) for the web; an agent only needs
51
- # enough to describe and link a sample.
49
+
50
+
51
+
52
52
  SUMMARY_ITEM_FIELDS = (
53
53
  "showcaseId", "name", "coverImage", "videoUrl",
54
54
  "aspectRatio", "duration", "hasDemo", "pageUrl",
@@ -56,12 +56,12 @@ SUMMARY_ITEM_FIELDS = (
56
56
 
57
57
 
58
58
  def _endpoint() -> str:
59
- """Endpoint URL, or "" when samples should not be fetched at all.
60
59
 
61
- An offline registry (``VIDEO_TEMPLATE_REGISTRY_URL=file://…``, fixtures /
62
- air-gapped dev) never implies a network call for samples: the registry
63
- there is not ab-api's, so neither are its templates.
64
- """
60
+
61
+
62
+
63
+
64
+
65
65
  explicit = os.environ.get("VIDEO_TEMPLATE_SHOWCASE_URL", "").strip()
66
66
  if explicit:
67
67
  return explicit
@@ -78,8 +78,8 @@ def _cache_dir() -> str:
78
78
 
79
79
 
80
80
  def _cache_file(url: str, body: bytes, token: str) -> str:
81
- # Token identity is part of the key (hashed twice, never stored): two
82
- # accounts on one machine see different private templates.
81
+
82
+
83
83
  token_id = hashlib.sha256(token.encode("utf-8")).hexdigest()[:8]
84
84
  digest = hashlib.sha256(url.encode("utf-8") + b"\0" + body + b"\0" + token_id.encode()).hexdigest()[:16]
85
85
  return os.path.join(_cache_dir(), f"showcases-{digest}.json")
@@ -104,7 +104,7 @@ def _write_cache(path: str, data: dict) -> None:
104
104
  json.dump({"fetchedAt": time.time(), "data": data}, fh, ensure_ascii=False)
105
105
  os.replace(tmp, path)
106
106
  except OSError:
107
- pass # cache is best-effort
107
+ pass
108
108
 
109
109
 
110
110
  def _warn(reason: str) -> None:
@@ -112,18 +112,18 @@ def _warn(reason: str) -> None:
112
112
 
113
113
 
114
114
  def load_showcases(template_keys: list[str], limit_per_template: int) -> Optional[dict[str, dict]]:
115
- """Return ``{templateKey: group}`` for the visible templates, or ``None`` on any failure.
116
115
 
117
- Templates the caller cannot see are simply absent from the dict.
118
- """
116
+
117
+
118
+
119
119
  keys = [k for k in dict.fromkeys(template_keys) if isinstance(k, str) and k]
120
120
  if not keys:
121
121
  return {}
122
122
 
123
123
  url = _endpoint()
124
124
  token = os.environ.get("PRIV_TOKEN", "").strip()
125
- # Silent skips (not failures): offline registry, or no credential — the
126
- # endpoint is authenticated and the registry step already reported auth.
125
+
126
+
127
127
  if not url or (not token and not url.startswith("file://")):
128
128
  return None
129
129
  body = json.dumps(
@@ -141,8 +141,8 @@ def load_showcases(template_keys: list[str], limit_per_template: int) -> Optiona
141
141
  try:
142
142
  with urllib.request.urlopen(req, timeout=_HTTP_TIMEOUT) as resp:
143
143
  parsed = json.loads(resp.read().decode("utf-8"))
144
- except Exception as exc: # noqa: BLE001 — enhancement data, degrade on anything
145
- # Message only: exception text never includes the token header.
144
+ except Exception as exc:
145
+
146
146
  _warn(type(exc).__name__ + (f" {exc.code}" if hasattr(exc, "code") else ""))
147
147
  return None
148
148
  if not isinstance(parsed, dict) or parsed.get("code") not in (0, "0"):
@@ -164,7 +164,7 @@ def load_showcases(template_keys: list[str], limit_per_template: int) -> Optiona
164
164
 
165
165
 
166
166
  def summarize_group(group: dict, max_items: int) -> dict:
167
- """The CLI's view of one template's samples: count, link, a few slim items."""
167
+
168
168
  items = []
169
169
  for sc in (group.get("showcases") or [])[:max_items]:
170
170
  if isinstance(sc, dict):
@@ -18,8 +18,11 @@
18
18
  "filter_tag": { "type": "string", "description": "Show only templates whose styleTags contain (or are contained in) this string. Case-insensitive. E.g. 'tech' / '科普' / 'walkthrough'." },
19
19
  "filter_aspect": { "type": "string", "description": "Show only templates that declare this aspect ratio. E.g. '9:16' / '16:9' / '1:1'." },
20
20
  "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)." },
21
+ "user_media": { "type": "string", "enum": ["yes", "no"], "description": "Shortlisting when the user named no template. 'yes' = the user handed over their own images/videos: drops templates with nowhere to put them. 'no' = they did not: drops templates that cannot run without them. Leave unset when it does not matter." },
22
+ "source_doc": { "type": "string", "description": "Shortlisting: the user gave a source document of this kind (e.g. 'pptx') — keeps only templates that build their scenes from one. 'none' drops those templates. Leave unset otherwise." },
23
+ "narration": { "type": "string", "enum": ["yes", "no"], "description": "Shortlisting: 'yes' = the video needs voice-over (drops narration-free templates); 'no' = the user wants none (keeps only narration-free templates). Leave unset unless the user said so." },
21
24
  "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." },
22
- "json_output": { "type": "boolean", "description": "Emit a JSON result instead of the human-readable table: { templates: [...] } — summaries, or full definitions when template_id / full is set — or { examples: [...] }. List summaries carry pageUrl (the template's web detail page — show it to the user as a link) and, when the backend serves samples, showcases { count, pageUrl, items }; the template_id view carries top-level pageUrls / showcases maps." },
25
+ "json_output": { "type": "boolean", "description": "Emit a JSON result instead of the human-readable table: { templates: [...] } — summaries (each with notFor when the template declares which requests it is the wrong pick for), or full definitions when template_id / full is set — or { examples: [...] }. List summaries carry pageUrl (the template's web detail page — show it to the user as a link) and, when the backend serves samples, showcases { count, pageUrl, items }; the template_id view carries top-level pageUrls / showcases maps." },
23
26
  "open": { "type": "string", "description": "Print the web detail page URL of <templateId> (playable samples, layouts, copy-ready prompt) and open it in the browser when run from an interactive terminal. Relay the printed URL to the user." }
24
27
  },
25
28
  "required": []
@@ -2,6 +2,6 @@
2
2
  "skillName": "template-registry",
3
3
  "repoName": "agent-skill-media-maker",
4
4
  "skillId": "475",
5
- "version": "V27",
5
+ "version": "V28",
6
6
  "skillDescription": "Video-template registry skill. Stores every video-template definition and lists the available templates (templateId / name / aspect ratio / style tags).\n\nUse this skill as soon as the user mentions any of these intents:\n- View available templates / list every template\n\nNote: DSL→TemplateBinding is no longer a separate exposed step — once prepare_video_assets receives a template_id it builds the binding internally."
7
7
  }
@@ -1,10 +1,10 @@
1
- """Package marker for ``video_dsl.runtime`` — kept intentionally empty.
2
1
 
3
- This file exists so ``from video_dsl.runtime.<mod> import …`` resolves when
4
- ``skills/template-registry/`` is on sys.path (the pattern used by render-video
5
- and gen-script). Public modules:
6
2
 
7
- - timeline_compiler : DSL → Remotion frame-axis timeline + subtitle splits
8
- - prompt_enhancer : LLM image-prompt enrichment used by gen-script
9
- - dsl_validator : DSL validation (structural / integrity / full presets)
10
- """
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+