@remixmate/cli 0.1.1 → 0.1.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.
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.1.1",
4
- "generatedAt": "2026-06-08T05:59:50.921Z",
3
+ "version": "0.1.2",
4
+ "generatedAt": "2026-06-08T08:37:23.147Z",
5
5
  "skills": [
6
6
  {
7
7
  "id": "export-jianying",
8
8
  "tier": "orchestration",
9
+ "category": "consuming",
9
10
  "title": "Jianying (CapCut) Draft Export",
10
11
  "summary": "Jianying (CapCut) draft export: package asset URLs into a draft ZIP that Jianying can import. Supports automatic conversion from a RenderPlan.",
11
12
  "triggers": [
@@ -28,6 +29,7 @@
28
29
  {
29
30
  "id": "gen-digital-human",
30
31
  "tier": "atomic",
32
+ "category": "asset",
31
33
  "title": "Digital-Human Talking-Head",
32
34
  "summary": "Digital-human video: list available avatars; produce a talking-head video from text via TTS, or drive an avatar from an existing audio URL.",
33
35
  "triggers": [
@@ -50,6 +52,7 @@
50
52
  {
51
53
  "id": "gen-image",
52
54
  "tier": "atomic",
55
+ "category": "asset",
53
56
  "title": "AI Image Generation",
54
57
  "summary": "AI image generation: produce an image from a text prompt. Supports Seedream and Gemini models, plus image-to-image with reference images.",
55
58
  "triggers": [
@@ -73,6 +76,7 @@
73
76
  {
74
77
  "id": "gen-script",
75
78
  "tier": "orchestration",
79
+ "category": "authoring",
76
80
  "title": "Video Script Generation",
77
81
  "summary": "Video script generation: turn a topic into a structured Video DSL (JSON) that describes the full video — scene structure, asset requirements, and narrative flow.",
78
82
  "triggers": [
@@ -95,6 +99,7 @@
95
99
  {
96
100
  "id": "gen-video",
97
101
  "tier": "atomic",
102
+ "category": "asset",
98
103
  "title": "AI Video Generation",
99
104
  "summary": "AI video generation: produce a short video clip from a text prompt. Supports Seedance and Veo models, plus first/last frame and reference images.",
100
105
  "triggers": [
@@ -117,6 +122,7 @@
117
122
  {
118
123
  "id": "gen-voice",
119
124
  "tier": "atomic",
125
+ "category": "asset",
120
126
  "title": "Text-to-Speech (Minimax)",
121
127
  "summary": "Text-to-speech (TTS): synthesize narration audio from text via the Minimax TTS model. Returns the persisted audio URL — no download needed.",
122
128
  "triggers": [
@@ -138,6 +144,7 @@
138
144
  {
139
145
  "id": "prepare-video-assets",
140
146
  "tier": "orchestration",
147
+ "category": "authoring",
141
148
  "title": "Video Asset Preparation",
142
149
  "summary": "Resolves and generates every asset (image / audio / video) referenced by a Video DSL, persists a RenderPlan to the database, and returns a job_id for the subsequent render_video call. This is Phase 1 of the two-phase video pipeline; Phase 3 (Remotion render) lives in render_video.",
143
150
  "triggers": [
@@ -165,6 +172,7 @@
165
172
  {
166
173
  "id": "render-video",
167
174
  "tier": "orchestration",
175
+ "category": "authoring",
168
176
  "title": "Remotion Video Renderer",
169
177
  "summary": "Loads a persisted RenderPlan by job_id and drives the Remotion engine to produce the final video. Assets must already be generated via prepare_video_assets — this skill never resolves or regenerates assets.",
170
178
  "triggers": [
@@ -192,6 +200,7 @@
192
200
  {
193
201
  "id": "template-registry",
194
202
  "tier": "orchestration",
203
+ "category": "authoring",
195
204
  "title": "Video Template Registry",
196
205
  "summary": "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.",
197
206
  "triggers": [
@@ -212,6 +221,7 @@
212
221
  {
213
222
  "id": "video-parser",
214
223
  "tier": "tool",
224
+ "category": "consuming",
215
225
  "title": "Video Deconstruction",
216
226
  "summary": "Video deconstruction: split a video into reusable assets (audio extraction, ASR transcript, keyframe extraction, scene segmentation).",
217
227
  "triggers": [
@@ -233,6 +243,7 @@
233
243
  {
234
244
  "id": "web-capture",
235
245
  "tier": "tool",
246
+ "category": "consuming",
236
247
  "title": "Web Page Capture",
237
248
  "summary": "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).",
238
249
  "triggers": [
@@ -21,12 +21,30 @@ export type SkillEntry = {
21
21
  type: 'builtin';
22
22
  handler: string;
23
23
  };
24
+ /**
25
+ * Skill 类别 — 区分"创作期 / 消费期 / 元数据型" skill。
26
+ *
27
+ * - "authoring": 创建 / 编辑模板期间使用,例如 template-registry / gen-script /
28
+ * render-video(用于 try_render) / prepare-video-assets。
29
+ * - "consuming": 消费已有模板生成媒体,例如 export-jianying / video-parser /
30
+ * web-capture(与"创建模板"无关,是消费侧场景)。
31
+ * - "asset": 生成单一类型素材的原子 skill:gen-image / gen-voice /
32
+ * gen-video / gen-digital-human。authoring 也会用,但通过 stub
33
+ * 方式占位;consuming 场景下是真调用。
34
+ * - "meta": 元 skill(如未来加入 doc-only 的 template-creator)。
35
+ *
36
+ * 下游消费方(如 ab-template-studio)按 category 自动挑选白名单,避免每加一个
37
+ * skill 就要改两侧 hardcode。
38
+ */
39
+ export type SkillCategory = 'authoring' | 'consuming' | 'asset' | 'meta';
40
+ export declare const CATEGORY_VALUES: readonly ["authoring", "consuming", "asset", "meta"];
24
41
  export interface RawSkillJson {
25
42
  name: string;
26
43
  toolName: string;
27
44
  description: string;
28
45
  title?: string;
29
46
  tier?: string;
47
+ category?: SkillCategory;
30
48
  parameters?: Record<string, unknown>;
31
49
  scriptPath?: string;
32
50
  entry?: SkillEntry;
@@ -11,6 +11,7 @@
11
11
  * human-readable problems (empty = OK). The runtime loader skips + warns;
12
12
  * the build treats them as fatal.
13
13
  */
14
+ export const CATEGORY_VALUES = ['authoring', 'consuming', 'asset', 'meta'];
14
15
  export const TIER_VALUES = ['atomic', 'orchestration', 'tool'];
15
16
  export const REQUIRED_SKILL_JSON_FIELDS = ['name', 'tier', 'title', 'description'];
16
17
  /**
@@ -39,6 +40,9 @@ export function validateSkillJson(raw, skillId) {
39
40
  if (raw.tier != null && !TIER_VALUES.includes(raw.tier)) {
40
41
  errors.push(`skill.json.tier must be one of ${TIER_VALUES.join(' | ')}, got '${raw.tier}'`);
41
42
  }
43
+ if (raw.category != null && !CATEGORY_VALUES.includes(raw.category)) {
44
+ errors.push(`skill.json.category must be one of ${CATEGORY_VALUES.join(' | ')}, got '${raw.category}'`);
45
+ }
42
46
  if (raw.name && raw.name !== skillId) {
43
47
  errors.push(`skill.json.name='${raw.name}' does not match directory name '${skillId}'`);
44
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remixmate/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "AI media generation skills for Claude Code / Codex — 11 skills covering image, video, voice, digital human, web capture, script, template registry, rendering, Jianying export, and video deconstruction.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -2,6 +2,7 @@
2
2
  "name": "export-jianying",
3
3
  "toolName": "export_jianying",
4
4
  "tier": "orchestration",
5
+ "category": "consuming",
5
6
  "title": "Jianying (CapCut) Draft Export",
6
7
  "description": "Jianying (CapCut) draft export: package asset URLs into a draft ZIP that Jianying can import. Supports automatic conversion from a RenderPlan.",
7
8
  "envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME"],
@@ -2,6 +2,7 @@
2
2
  "name": "gen-digital-human",
3
3
  "toolName": "gen_digital_human",
4
4
  "tier": "atomic",
5
+ "category": "asset",
5
6
  "title": "Digital-Human Talking-Head",
6
7
  "description": "Digital-human video: list available avatars; produce a talking-head video from text via TTS, or drive an avatar from an existing audio URL.",
7
8
  "envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME"],
@@ -2,6 +2,7 @@
2
2
  "name": "gen-image",
3
3
  "toolName": "gen_image",
4
4
  "tier": "atomic",
5
+ "category": "asset",
5
6
  "title": "AI Image Generation",
6
7
  "description": "AI image generation: produce an image from a text prompt. Supports Seedream and Gemini models, plus image-to-image with reference images.",
7
8
  "envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME", "MM_IMAGE_MODEL"],
@@ -1054,6 +1054,11 @@ Examples:
1054
1054
  default=None,
1055
1055
  help="On-screen subheadline / project name (e.g. 'Pixelle-Video'). Stored at meta.subheadline and pushed into textLayers[role=subheadline]. Independent from CC subtitles (global.subtitle).",
1056
1056
  )
1057
+ parser.add_argument(
1058
+ "--skip-asset-generation",
1059
+ action="store_true",
1060
+ help="Skill-creator / template-creator helper: when set, every produced AssetRef is marked as already generated with a stub URL — no gen-image / gen-voice / gen-video calls are needed. Implies --stub-image-url + --stub-video-url with default sentinels (https://placeholder.local/stub.png|.mp4) when those flags are absent, and additionally rewrites every gen-voice asset to source=existing + status=generated + a placeholder audio URL. Useful when a downstream agent only wants the DSL shape (e.g. to feed into try_render with all assets pre-stubbed).",
1061
+ )
1057
1062
  parser.add_argument(
1058
1063
  "--stub-image-url",
1059
1064
  default=None,
@@ -1157,6 +1162,22 @@ Examples:
1157
1162
  print(f"⚠️ STUB_VIDEO_URL env var detected ({env_v}); using it as the video stub. Prefer passing --stub-video-url explicitly, or unset the env var.", file=sys.stderr)
1158
1163
  stub_video_url = env_v
1159
1164
 
1165
+ # --skip-asset-generation 是为下游"只想要 DSL shape"的 agent 设计的
1166
+ # 一键开关:等价于 --stub-image-url + --stub-video-url + 把 gen-voice 资产
1167
+ # 也写成 source=existing + status=generated。当用户没显式提供 stub URL 时
1168
+ # 用一组 sentinel 占位(https://placeholder.local/...),模板创作 / 调试场景
1169
+ # 不会真的去 fetch 这些 URL。
1170
+ if args.skip_asset_generation:
1171
+ if not stub_image_url:
1172
+ stub_image_url = "https://placeholder.local/stub.png"
1173
+ if not stub_video_url:
1174
+ stub_video_url = "https://placeholder.local/stub.mp4"
1175
+ print(
1176
+ "ℹ️ --skip-asset-generation: forcing all assets to source=existing/status=generated "
1177
+ f"(image={stub_image_url}, video={stub_video_url}, audio=https://placeholder.local/stub.mp3)",
1178
+ file=sys.stderr,
1179
+ )
1180
+
1160
1181
  dsl = build_dsl(
1161
1182
  topic=args.topic,
1162
1183
  platform=args.platform,
@@ -1177,6 +1198,24 @@ Examples:
1177
1198
  caption_lines=args.caption_lines,
1178
1199
  )
1179
1200
 
1201
+ # Post-process for --skip-asset-generation: rewrite all gen-voice / gen-digital-human
1202
+ # assets to be already-generated stubs. Image / video are already covered by the
1203
+ # stub_image_url / stub_video_url params threaded through build_dsl above.
1204
+ if args.skip_asset_generation:
1205
+ _AUDIO_STUB = "https://placeholder.local/stub.mp3"
1206
+ _VIDEO_STUB = stub_video_url # same sentinel for digital-human placeholder
1207
+ for asset in dsl.get("assets", []):
1208
+ src = asset.get("source")
1209
+ if src in ("gen-voice",):
1210
+ asset["source"] = "existing"
1211
+ asset["status"] = "generated"
1212
+ asset["url"] = _AUDIO_STUB
1213
+ # payload 留作 reference(renderer 不会再读它,因为 status=generated)
1214
+ elif src in ("gen-digital-human",):
1215
+ asset["source"] = "existing"
1216
+ asset["status"] = "generated"
1217
+ asset["url"] = _VIDEO_STUB
1218
+
1180
1219
  errors = validate_dsl(dsl)
1181
1220
  if errors:
1182
1221
  print("❌ generated DSL failed validation:", file=sys.stderr)
@@ -2,6 +2,7 @@
2
2
  "name": "gen-script",
3
3
  "toolName": "gen_script",
4
4
  "tier": "orchestration",
5
+ "category": "authoring",
5
6
  "title": "Video Script Generation",
6
7
  "description": "Video script generation: turn a topic into a structured Video DSL (JSON) that describes the full video — scene structure, asset requirements, and narrative flow.",
7
8
  "envVars": ["DEFAULT_IMAGE_MODEL", "DEFAULT_VIDEO_MODEL", "STUB_IMAGE_URL", "STUB_VIDEO_URL"],
@@ -34,7 +35,8 @@
34
35
  "description": "Bottom typewriter text lines for templates that support a caption/typewriter area (e.g. spotlight-card). Each element is one line of text. Supports **emphasis** syntax (rendered with accent color). **Must** pass when the user explicitly provides bullet-point text / bottom copy for the video."
35
36
  },
36
37
  "stub_image_url": { "type": "string", "description": "Test-mode image stub URL. Only pass when the user explicitly says things like 'just testing / don't actually generate / use a placeholder image / stub URL / save credits' AND provides a concrete URL. With this set, every image AssetRef in the produced DSL is written as source=existing, status=generated, url=<this URL> — no gen-image call. Do not pass otherwise; if the user expressed the intent without a URL, ask for one — do not invent one." },
37
- "stub_video_url": { "type": "string", "description": "Test-mode video stub URL. Only pass when the user explicitly says things like 'just testing / don't actually generate the video / placeholder clip / save credits' AND provides a concrete URL. With this set, every video AssetRef in the produced DSL is written as source=existing, status=generated, url=<this URL> — no gen-video call. Do not pass otherwise; if the user expressed the intent without a URL, ask for one — do not invent one." }
38
+ "stub_video_url": { "type": "string", "description": "Test-mode video stub URL. Only pass when the user explicitly says things like 'just testing / don't actually generate the video / placeholder clip / save credits' AND provides a concrete URL. With this set, every video AssetRef in the produced DSL is written as source=existing, status=generated, url=<this URL> — no gen-video call. Do not pass otherwise; if the user expressed the intent without a URL, ask for one — do not invent one." },
39
+ "skip_asset_generation": { "type": "boolean", "description": "All-in-one switch for downstream agents (e.g. template-creator) that only want the DSL shape: every produced AssetRef is marked as already generated with placeholder URLs (image: https://placeholder.local/stub.png, video: stub.mp4, audio: stub.mp3). Implies the equivalent of --stub-image-url + --stub-video-url with sentinel defaults plus the same rewrite for gen-voice / gen-digital-human assets. Useful when the agent only needs to inspect DSL structure or feed it into try_render_local with all assets pre-stubbed." }
38
40
  },
39
41
  "required": ["topic"]
40
42
  }
@@ -2,6 +2,7 @@
2
2
  "name": "gen-video",
3
3
  "toolName": "gen_video",
4
4
  "tier": "atomic",
5
+ "category": "asset",
5
6
  "title": "AI Video Generation",
6
7
  "description": "AI video generation: produce a short video clip from a text prompt. Supports Seedance and Veo models, plus first/last frame and reference images.",
7
8
  "envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME", "MM_VIDEO_MODEL"],
@@ -2,6 +2,7 @@
2
2
  "name": "gen-voice",
3
3
  "toolName": "gen_voice",
4
4
  "tier": "atomic",
5
+ "category": "asset",
5
6
  "title": "Text-to-Speech (Minimax)",
6
7
  "description": "Text-to-speech (TTS): synthesize narration audio from text via the Minimax TTS model. Returns the persisted audio URL — no download needed.",
7
8
  "envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME"],
@@ -2,6 +2,7 @@
2
2
  "name": "prepare-video-assets",
3
3
  "toolName": "prepare_video_assets",
4
4
  "tier": "orchestration",
5
+ "category": "authoring",
5
6
  "title": "Video Asset Preparation",
6
7
  "description": "Resolves and generates every asset (image / audio / video) referenced by a Video DSL, persists a RenderPlan to the database, and returns a job_id for the subsequent render_video call. This is Phase 1 of the two-phase video pipeline; Phase 3 (Remotion render) lives in render_video.",
7
8
  "envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "MM_BACKEND_API_URL", "AGENT_NAME", "REMOTION_RENDER_API_URL", "REMOTION_RENDER_MODE", "REMOTION_OUTPUT_DIR", "ASSET_CACHE_DIR"],
@@ -2,6 +2,7 @@
2
2
  "name": "render-video",
3
3
  "toolName": "render_video",
4
4
  "tier": "orchestration",
5
+ "category": "authoring",
5
6
  "title": "Remotion Video Renderer",
6
7
  "description": "Loads a persisted RenderPlan by job_id and drives the Remotion engine to produce the final video. Assets must already be generated via prepare_video_assets — this skill never resolves or regenerates assets.",
7
8
  "envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "MM_BACKEND_API_URL", "AGENT_NAME", "REMOTION_RENDER_API_URL", "REMOTION_RENDER_MODE", "REMOTION_OUTPUT_DIR", "ASSET_CACHE_DIR"],
@@ -15,12 +15,18 @@ in-process by ``render-video``; it is intentionally NOT exposed as a CLI verb.
15
15
 
16
16
  Flags:
17
17
  --list-templates (accepted; listing is the only verb)
18
+ --list-examples list *.dsl.json / *.binding.json reference
19
+ examples grouped by templateId (consumed
20
+ by downstream agents that want to read a
21
+ template's reference shape before producing
22
+ new DSL)
18
23
  --filter-tag <substr> keep templates whose styleTags match
19
24
  --filter-aspect <ratio> keep templates supporting this aspect ratio
20
25
  --filter-language <zh|en|...> keep templates tagged with this content lang
21
26
  (templates with no contentLanguage are kept)
22
27
  --include-beta also show beta templates (else stable-only)
23
- --json-output emit {"templates": [...]} instead of a table
28
+ --json-output emit {"templates": [...]} or {"examples": [...]}
29
+ instead of a table
24
30
  """
25
31
 
26
32
  from __future__ import annotations
@@ -29,6 +35,7 @@ import argparse
29
35
  import json
30
36
  import os
31
37
  import sys
38
+ from pathlib import Path
32
39
 
33
40
  # When run as `python3 <skillDir>/scripts/list_templates.py`, this script's own
34
41
  # directory is sys.path[0], so the sibling shared modules import directly.
@@ -61,17 +68,69 @@ def _status_of(tpl: dict) -> str:
61
68
  return "stable"
62
69
 
63
70
 
71
+ # ----- Examples discovery (--list-examples) ---------------------------------
72
+ #
73
+ # Examples live under <SkillDir>/video_dsl/schema/examples/ as `*.dsl.json` and
74
+ # `*.binding.json` files. Naming convention (per gen-script SKILL.md) is
75
+ # `<templateId>.dsl.json` / `<templateId>.binding.json`, occasionally with
76
+ # variant suffixes (`<templateId>.<variant>.dsl.json`).
77
+ #
78
+ # We do not parse the JSON content here (downstream agents read the raw files
79
+ # they care about); we just enumerate paths so the agent doesn't have to guess
80
+ # the directory layout. When the directory does not exist (e.g. inside a slim
81
+ # package distribution), we return an empty list — non-fatal.
82
+
83
+ # Resolve the examples directory relative to this script.
84
+ # <skill>/scripts/list_templates.py → <skill>/video_dsl/schema/examples/
85
+ _EXAMPLES_DIR = Path(__file__).resolve().parent.parent / "video_dsl" / "schema" / "examples"
86
+
87
+
88
+ def _collect_examples() -> list[dict]:
89
+ if not _EXAMPLES_DIR.is_dir():
90
+ return []
91
+ by_template: dict[str, dict] = {}
92
+ for entry in sorted(_EXAMPLES_DIR.iterdir()):
93
+ if not entry.is_file():
94
+ continue
95
+ name = entry.name
96
+ # Recognise *.dsl.json / *.binding.json
97
+ if name.endswith(".dsl.json"):
98
+ kind = "dsl"
99
+ base = name[: -len(".dsl.json")]
100
+ elif name.endswith(".binding.json"):
101
+ kind = "binding"
102
+ base = name[: -len(".binding.json")]
103
+ else:
104
+ continue
105
+ # Variant: 'foo.bar.dsl.json' → templateId='foo', variant='bar'
106
+ if "." in base:
107
+ template_id, variant = base.split(".", 1)
108
+ else:
109
+ template_id, variant = base, None
110
+ bucket = by_template.setdefault(template_id, {"templateId": template_id, "files": []})
111
+ bucket["files"].append({
112
+ "kind": kind,
113
+ "variant": variant,
114
+ "path": str(entry.relative_to(_EXAMPLES_DIR.parent.parent.parent)), # relative to skill dir
115
+ "absolutePath": str(entry),
116
+ "sizeBytes": entry.stat().st_size,
117
+ })
118
+ return list(by_template.values())
119
+
120
+
64
121
  def main() -> None:
65
122
  ap = argparse.ArgumentParser(
66
123
  description="List available video templates from the registry.",
67
124
  )
68
125
  ap.add_argument("--list-templates", action="store_true",
69
126
  help="List every available template (the only CLI verb).")
127
+ ap.add_argument("--list-examples", action="store_true",
128
+ help="List reference examples (*.dsl.json / *.binding.json) grouped by templateId.")
70
129
  ap.add_argument("--filter-tag", help="Keep templates whose styleTags match this substring.")
71
130
  ap.add_argument("--filter-aspect", help="Keep templates supporting this aspect ratio (e.g. 9:16).")
72
131
  ap.add_argument("--filter-language", help="Keep templates tagged with this content language (zh|en|...).")
73
132
  ap.add_argument("--include-beta", action="store_true", help="Also show beta templates (default: stable only).")
74
- ap.add_argument("--json-output", action="store_true", help='Emit {"templates": [...]} JSON instead of a table.')
133
+ ap.add_argument("--json-output", action="store_true", help='Emit JSON ({"templates":[...]} or {"examples":[...]}) instead of a table.')
75
134
  args = ap.parse_args()
76
135
 
77
136
  # --include-beta flips registry_loader's documented status gate via env, so
@@ -79,6 +138,32 @@ def main() -> None:
79
138
  if args.include_beta:
80
139
  os.environ["ENABLE_BETA_TEMPLATES"] = "1"
81
140
 
141
+ # ----- examples mode -----------------------------------------------------
142
+ if args.list_examples:
143
+ examples = _collect_examples()
144
+ if args.json_output:
145
+ print(json.dumps({"examples": examples}, ensure_ascii=False))
146
+ return
147
+ if not examples:
148
+ print(
149
+ f"⚠️ No examples found under {_EXAMPLES_DIR}.\n"
150
+ " This package may have shipped without reference examples; "
151
+ "check the cli source repo or upgrade @remixmate/cli.",
152
+ )
153
+ return
154
+ print(f"\n{'Template ID':<28} Files")
155
+ print(f"{'-' * 28} {'-' * 60}")
156
+ for bucket in examples:
157
+ tid = str(bucket["templateId"])[:28].ljust(28)
158
+ files = bucket["files"]
159
+ for i, f in enumerate(files):
160
+ marker = tid if i == 0 else " " * 28
161
+ kind = f["kind"]
162
+ variant = f"@{f['variant']}" if f.get("variant") else ""
163
+ print(f"{marker} [{kind}{variant}] {f['path']} ({f['sizeBytes']}B)")
164
+ print(f"\n{sum(len(b['files']) for b in examples)} example file(s) across {len(examples)} template(s)")
165
+ return
166
+
82
167
  try:
83
168
  templates = load_visible_templates()
84
169
  except RuntimeError as exc:
@@ -2,6 +2,7 @@
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
8
  "envVars": ["PRIV_TOKEN", "VIDEO_TEMPLATE_REGISTRY", "VIDEO_TEMPLATE_REGISTRY_URL", "VIDEO_TEMPLATE_REGISTRY_HTTP_METHOD"],
@@ -10,11 +11,12 @@
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,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,6 +2,7 @@
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"],