@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
package/dist/runner.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { ParsedArgs } from './argv.js';
9
9
  export interface RunOptions {
10
- /** Override the skills directory (defaults to ab-skill/skills). */
10
+ /** Override the skills directory (defaults to the package's bundled skills/). */
11
11
  baseDir?: string;
12
12
  /** Raw argv slice after the skill name (passed verbatim for python; parsed for handlers). */
13
13
  rawArgs: string[];
@@ -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.9.1",
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"],
@@ -21,7 +21,7 @@ triggers:
21
21
 
22
22
  Wraps ab-api's digital-human endpoints (the same ones the web studio uses), authenticated with the **Tianyan privateToken**. Two providers: **Jimeng** (image-driven) and **HiFly** (video-driven). Generation is async — the handler submits the task and polls `/digital-human/video/status` until completion.
23
23
 
24
- > This skill was migrated from a Python script to an ab-skill CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_digital_human`, same params as in `skill.json`); local repro goes through `ab-skill gen-digital-human ...`.
24
+ > This skill was migrated from a Python script to an remixmate CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_digital_human`, same params as in `skill.json`); local repro goes through `remixmate gen-digital-human ...`.
25
25
 
26
26
  ## Capabilities
27
27
 
@@ -54,24 +54,24 @@ By default only the URL is printed; generation is async and the handler polls un
54
54
  ### 1. List avatars
55
55
 
56
56
  ```bash
57
- ab-skill gen-digital-human --list-avatars
57
+ remixmate gen-digital-human --list-avatars
58
58
  ```
59
59
 
60
60
  Optional filters:
61
61
 
62
62
  ```bash
63
63
  # Filter by source (jimeng = image-driven, hifly = video-driven)
64
- ab-skill gen-digital-human --list-avatars --source jimeng
65
- ab-skill gen-digital-human --list-avatars --source hifly
64
+ remixmate gen-digital-human --list-avatars --source jimeng
65
+ remixmate gen-digital-human --list-avatars --source hifly
66
66
 
67
67
  # Filter by gender
68
- ab-skill gen-digital-human --list-avatars --gender female
68
+ remixmate gen-digital-human --list-avatars --gender female
69
69
 
70
70
  # Show your custom avatars
71
- ab-skill gen-digital-human --list-avatars --mine
71
+ remixmate gen-digital-human --list-avatars --mine
72
72
 
73
73
  # Filter by name
74
- ab-skill gen-digital-human --list-avatars --name "alice"
74
+ remixmate gen-digital-human --list-avatars --name "alice"
75
75
  ```
76
76
 
77
77
  > Custom avatars require `--mine`. When generating a video the handler auto-falls back from the public list to `mine: true` if needed.
@@ -81,7 +81,7 @@ ab-skill gen-digital-human --list-avatars --name "alice"
81
81
  #### TTS mode
82
82
 
83
83
  ```bash
84
- ab-skill gen-digital-human \
84
+ remixmate gen-digital-human \
85
85
  --avatar-id 7 \
86
86
  --text "Hi everyone, welcome to the live stream — today I'll introduce a new product." \
87
87
  --voice-id "male-qn-qingse"
@@ -90,7 +90,7 @@ ab-skill gen-digital-human \
90
90
  #### TTS + custom voice + aspect ratio
91
91
 
92
92
  ```bash
93
- ab-skill gen-digital-human \
93
+ remixmate gen-digital-human \
94
94
  --avatar-id 7 \
95
95
  --text "Hi class, here's our brand-new course." \
96
96
  --voice-id "female-shaonv" \
@@ -100,7 +100,7 @@ ab-skill gen-digital-human \
100
100
  #### Audio-driven mode
101
101
 
102
102
  ```bash
103
- ab-skill gen-digital-human \
103
+ remixmate gen-digital-human \
104
104
  --avatar-id 39 \
105
105
  --source hifly \
106
106
  --audio-url "https://example.com/voice.mp3" \
@@ -110,7 +110,7 @@ ab-skill gen-digital-human \
110
110
  ### 3. Check job status
111
111
 
112
112
  ```bash
113
- ab-skill gen-digital-human --check-status --generation-id 123
113
+ remixmate gen-digital-human --check-status --generation-id 123
114
114
  ```
115
115
 
116
116
  ## Common CLI flags
@@ -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,6 @@
2
2
  "skillName": "gen-digital-human",
3
3
  "repoName": "agent-skill-media-maker",
4
4
  "skillId": "336",
5
- "version": "V7",
5
+ "version": "V8",
6
6
  "skillDescription": "数字人口播视频技能,支持查询形象、TTS 口播、音频驱动口播和查询生成状态(调用 ab-api 数字人接口,即梦 / 飞影)。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- 数字人、数字人视频、数字人口播、生成数字人视频\n- 用户提供已有音频 URL(MP3 等)、用外链音频驱动数字人口型\n- AI 主播、虚拟主播、虚拟人物视频、口播视频\n- 让数字人说话、让虚拟人说一段话、让 AI 人物播报\n- 查看/列出数字人形象、有哪些数字人可以用\n- 使用即梦/飞影数字人\n\n即使用户没有明确说「使用 AI」,只要他们想要让一个虚拟人物朗读/播报一段文字并生成视频,也要使用本 skill。"
7
7
  }
@@ -51,7 +51,7 @@ No skill-local env file — the executing process inherits the system environmen
51
51
 
52
52
  ## Operations
53
53
 
54
- > This skill was migrated from a Python script to an ab-skill CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_image`, same params as in `skill.json`); local repro goes through `ab-skill gen-image ...`.
54
+ > This skill was migrated from a Python script to an remixmate CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_image`, same params as in `skill.json`); local repro goes through `remixmate gen-image ...`.
55
55
 
56
56
  1. **Prompt**: be specific about subject, style, lighting, composition. Either English or Chinese works.
57
57
  2. By default only the URL is printed (good for showing to the user); the legacy local-download flag has been dropped — image URLs are persisted in the cloud.
@@ -59,13 +59,13 @@ No skill-local env file — the executing process inherits the system environmen
59
59
  ### Text-to-image
60
60
 
61
61
  ```bash
62
- ab-skill gen-image \
62
+ remixmate gen-image \
63
63
  --prompt "<image description>" \
64
64
  --size "9:16"
65
65
  ```
66
66
 
67
67
  ```bash
68
- ab-skill gen-image \
68
+ remixmate gen-image \
69
69
  --prompt "<image description>" \
70
70
  --model gemini-3-pro-image \
71
71
  --size "16:9" \
@@ -81,14 +81,14 @@ Reference images accept local file paths, HTTPS URLs, or data URIs. Pass `--refe
81
81
 
82
82
  ```bash
83
83
  # URL reference
84
- ab-skill gen-image \
84
+ remixmate gen-image \
85
85
  --prompt "Convert this photo to an oil-painting style" \
86
86
  --reference "https://example.com/photo.jpg"
87
87
  ```
88
88
 
89
89
  ```bash
90
90
  # Local-file reference + reference strength
91
- ab-skill gen-image \
91
+ remixmate gen-image \
92
92
  --prompt "Match the style of this reference" \
93
93
  --reference ./ref.png \
94
94
  --image-strength 0.6
@@ -96,7 +96,7 @@ ab-skill gen-image \
96
96
 
97
97
  ```bash
98
98
  # Multiple references
99
- ab-skill gen-image \
99
+ remixmate gen-image \
100
100
  --prompt "Blend these styles" \
101
101
  --reference ./a.png \
102
102
  --reference ./b.png
@@ -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"],
@@ -2,6 +2,6 @@
2
2
  "skillName": "gen-image",
3
3
  "repoName": "agent-skill-media-maker",
4
4
  "skillId": "337",
5
- "version": "V8",
5
+ "version": "V9",
6
6
  "skillDescription": "AI 生图技能,根据文字描述生成图片,也支持参考图进行图生图(调用 ab-api /model/genImg,支持 Seedream 与 Gemini)。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- AI 生图、AI 画图、文生图、文字生成图片、生成图像、帮我画、生成一张图\n- 图生图、以图生图、参考图、风格迁移、图片变体\n- 使用 doubao / 豆包 / seedream、Gemini 等生成图片\n- 用户提供图片提示词并希望生成图片\n\n即使用户没有明确说「使用 AI」,只要他们想要根据描述生成图片,也要使用本 skill。"
7
7
  }
@@ -322,9 +322,9 @@ def generate_image_prompt(
322
322
  def _load_template_config(template_id: str) -> dict | None:
323
323
  """Load template definition for the given template ID.
324
324
 
325
- 解析顺序(与 match_template / template_binder 保持一致):
326
- 1. 通过 registry_loader 从 monorepo template-library/packages/metadata/registry.json
327
- (或 VIDEO_TEMPLATE_REGISTRY[_URL] 环境变量)加载,并按 templateId 匹配。
325
+ 解析顺序:
326
+ 1. 通过 registry_loader 从 ab-api(单一数据源,URL
327
+ VIDEO_TEMPLATE_REGISTRY_URL 或按 MM_API_BASE_URL 推导)加载,按 templateId 匹配。
328
328
  2. 兜底:旧路径 template-registry/video_dsl/templates/<id>/template.json
329
329
  (仅在仓库还残留旧目录时使用)。
330
330
  返回完整 template dict(含 supportedAspectRatios / assetRequirements / slotMapping 等),
@@ -384,6 +384,29 @@ def _template_primary_visual_type(template_config: dict | None) -> str:
384
384
  return "none"
385
385
 
386
386
 
387
+ def _template_needs_narration(template_config: dict | None) -> bool:
388
+ """模板是否需要旁白(TTS)。
389
+
390
+ 默认 True —— 保持历史行为:每个场景挂一个 gen-voice 素材 + 写入
391
+ ``audio.narration`` 骨架,由 agent 后续填真实文案。
392
+
393
+ 模板可通过 ``capabilities.needsNarration=false`` 声明"纯视觉 / 无旁白"
394
+ (如单图 Ken Burns、BGM-only 展示)。此时 gen_script:
395
+ - 不生成 gen-voice 素材;
396
+ - 场景不写 ``audio.narration``。
397
+ 于是骨架的 narrationSceneCount=0,ab-agent 的 prepare_video_assets 预校验
398
+ 会直接放行,不再强制用户为每个场景填旁白(与 spotlight-card 等无配音模板
399
+ 走的是同一条 pass-through 路径)。
400
+
401
+ 兼容历史脏数据:部分模板的 ``capabilities`` 是空列表 ``[]``(而非 dict),
402
+ 统一按"未声明"处理 → 返回 True。仅当显式为 JSON ``false`` 时才关闭旁白。
403
+ """
404
+ caps = (template_config or {}).get("capabilities")
405
+ if not isinstance(caps, dict):
406
+ return True
407
+ return caps.get("needsNarration", True) is not False
408
+
409
+
387
410
  def _template_needs_image(template_config: dict | None) -> bool:
388
411
  """Check if a template requires image assets.
389
412
 
@@ -786,6 +809,9 @@ def build_dsl(
786
809
  )
787
810
  primary_visual_type = _template_primary_visual_type(template_config)
788
811
  has_visual = primary_visual_type in ("image", "video")
812
+ # 旁白是模板能力(capabilities.needsNarration)。声明为 false 的模板(纯视觉 /
813
+ # BGM-only,如单图 Ken Burns)不分配 gen-voice 素材、场景不写 audio.narration。
814
+ needs_narration = _template_needs_narration(template_config)
789
815
 
790
816
  # ── Resolve template-driven output language + voice ────────────────────
791
817
  # outputLanguage is owned by the template (template.json). Missing/invalid
@@ -815,8 +841,11 @@ def build_dsl(
815
841
  visual_asset_id = f"video-{scene_id}"
816
842
  else:
817
843
  visual_asset_id = f"img-{scene_id}"
818
- narration_asset_id = f"narration-{scene_id}"
819
- narration_text = estimate_narration_text(plan["label"], plan["purpose"], plan["duration"], topic, language=output_language)
844
+ narration_asset_id = f"narration-{scene_id}" if needs_narration else None
845
+ narration_text = (
846
+ estimate_narration_text(plan["label"], plan["purpose"], plan["duration"], topic, language=output_language)
847
+ if needs_narration else ""
848
+ )
820
849
 
821
850
  # 根据模板 assetRequirements 生成对应类型的视觉素材
822
851
  if primary_visual_type == "image":
@@ -881,15 +910,17 @@ def build_dsl(
881
910
  # narration text 不再在 audio asset 的 payload 里冗余存放——
882
911
  # 唯一来源是下游 scenes[].audio.narration.text,render_video 在
883
912
  # 调用 TTS skill 前会按 assetRef 回查 scene 文本注入。
884
- assets.append({
885
- "assetId": narration_asset_id,
886
- "type": "audio",
887
- "source": "gen-voice",
888
- "status": "planned",
889
- "payload": {
890
- "voiceId": resolved_voice_id,
891
- },
892
- })
913
+ # 模板声明 needsNarration=false 时,完全不生成 gen-voice 素材。
914
+ if needs_narration:
915
+ assets.append({
916
+ "assetId": narration_asset_id,
917
+ "type": "audio",
918
+ "source": "gen-voice",
919
+ "status": "planned",
920
+ "payload": {
921
+ "voiceId": resolved_voice_id,
922
+ },
923
+ })
893
924
 
894
925
  if has_visual:
895
926
  layout = "text-overlay" if plan["purpose"] in ("opening", "cta") else "full-visual"
@@ -916,33 +947,35 @@ def build_dsl(
916
947
  if effective_subheadline:
917
948
  text_layers.append({"role": "subheadline", "content": effective_subheadline, "animation": "fade-in"})
918
949
 
919
- scenes.append({
950
+ scene = {
920
951
  "id": scene_id,
921
952
  "purpose": plan["purpose"],
922
953
  "duration": plan["duration"],
923
954
  "layout": layout,
924
955
  "visuals": {"background": {"assetRef": visual_asset_id}},
925
- "audio": {
956
+ "textLayers": text_layers,
957
+ "animationHints": {
958
+ "entrance": "fade",
959
+ "motion": "kenburns-in" if idx % 2 == 0 else "kenburns-out",
960
+ },
961
+ }
962
+ if needs_narration:
963
+ scene["audio"] = {
926
964
  "narration": {
927
965
  "text": narration_text,
928
966
  "assetRef": narration_asset_id,
929
967
  # 骨架标记:scenes[].audio.narration.text 同样需要被真实旁白替换
930
968
  "needsFill": True,
931
969
  },
932
- },
933
- "textLayers": text_layers,
934
- "animationHints": {
935
- "entrance": "fade",
936
- "motion": "kenburns-in" if idx % 2 == 0 else "kenburns-out",
937
- },
938
- })
970
+ }
971
+ scenes.append(scene)
939
972
  else:
940
973
  # The "no-visual" branch labels each scene with a layout hint.
941
974
  # Historical fallback was hardcoded "html-slide" — when no template
942
975
  # was specified, every audio-only scene defaulted to html-slide
943
976
  # styling. We replace the hardcoded fallback chain with:
944
977
  # 1. template.capabilities.defaultLayout ⇐ the template tells
945
- # ab-skill what layout name it wants on its no-visual scenes
978
+ # remixmate what layout name it wants on its no-visual scenes
946
979
  # 2. template_id ⇐ legacy: pass id as
947
980
  # layout name (existing behavior when no capability declared)
948
981
  # 3. "html-slide" ⇐ absolute fallback
@@ -966,22 +999,24 @@ def build_dsl(
966
999
 
967
1000
  custom_payload = _build_custom_payload(plan["purpose"], topic, plan["label"], idx, len(scene_plans), language=output_language)
968
1001
 
969
- scenes.append({
1002
+ scene = {
970
1003
  "id": scene_id,
971
1004
  "purpose": plan["purpose"],
972
1005
  "duration": plan["duration"],
973
1006
  "layout": layout,
974
- "audio": {
1007
+ "textLayers": text_layers,
1008
+ "customPayload": custom_payload,
1009
+ }
1010
+ if needs_narration:
1011
+ scene["audio"] = {
975
1012
  "narration": {
976
1013
  "text": narration_text,
977
1014
  "assetRef": narration_asset_id,
978
1015
  # 骨架标记:scenes[].audio.narration.text 同样需要被真实旁白替换
979
1016
  "needsFill": True,
980
1017
  },
981
- },
982
- "textLayers": text_layers,
983
- "customPayload": custom_payload,
984
- })
1018
+ }
1019
+ scenes.append(scene)
985
1020
 
986
1021
  dsl = {
987
1022
  "version": "v1alpha1",
@@ -1001,7 +1036,7 @@ def build_dsl(
1001
1036
  "aspectRatio": ratio,
1002
1037
  "resolution": resolution,
1003
1038
  "fps": 30,
1004
- "subtitle": {"enabled": True, "style": "bottom"},
1039
+ "subtitle": {"enabled": needs_narration, "style": "bottom"},
1005
1040
  "narration": {"voiceId": resolved_voice_id, "speed": 1.0},
1006
1041
  "bgm": {"enabled": True, "volume": 0.12},
1007
1042
  },
@@ -1054,6 +1089,11 @@ Examples:
1054
1089
  default=None,
1055
1090
  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
1091
  )
1092
+ parser.add_argument(
1093
+ "--skip-asset-generation",
1094
+ action="store_true",
1095
+ 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).",
1096
+ )
1057
1097
  parser.add_argument(
1058
1098
  "--stub-image-url",
1059
1099
  default=None,
@@ -1157,6 +1197,22 @@ Examples:
1157
1197
  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
1198
  stub_video_url = env_v
1159
1199
 
1200
+ # --skip-asset-generation 是为下游"只想要 DSL shape"的 agent 设计的
1201
+ # 一键开关:等价于 --stub-image-url + --stub-video-url + 把 gen-voice 资产
1202
+ # 也写成 source=existing + status=generated。当用户没显式提供 stub URL 时
1203
+ # 用一组 sentinel 占位(https://placeholder.local/...),模板创作 / 调试场景
1204
+ # 不会真的去 fetch 这些 URL。
1205
+ if args.skip_asset_generation:
1206
+ if not stub_image_url:
1207
+ stub_image_url = "https://placeholder.local/stub.png"
1208
+ if not stub_video_url:
1209
+ stub_video_url = "https://placeholder.local/stub.mp4"
1210
+ print(
1211
+ "ℹ️ --skip-asset-generation: forcing all assets to source=existing/status=generated "
1212
+ f"(image={stub_image_url}, video={stub_video_url}, audio=https://placeholder.local/stub.mp3)",
1213
+ file=sys.stderr,
1214
+ )
1215
+
1160
1216
  dsl = build_dsl(
1161
1217
  topic=args.topic,
1162
1218
  platform=args.platform,
@@ -1177,6 +1233,24 @@ Examples:
1177
1233
  caption_lines=args.caption_lines,
1178
1234
  )
1179
1235
 
1236
+ # Post-process for --skip-asset-generation: rewrite all gen-voice / gen-digital-human
1237
+ # assets to be already-generated stubs. Image / video are already covered by the
1238
+ # stub_image_url / stub_video_url params threaded through build_dsl above.
1239
+ if args.skip_asset_generation:
1240
+ _AUDIO_STUB = "https://placeholder.local/stub.mp3"
1241
+ _VIDEO_STUB = stub_video_url # same sentinel for digital-human placeholder
1242
+ for asset in dsl.get("assets", []):
1243
+ src = asset.get("source")
1244
+ if src in ("gen-voice",):
1245
+ asset["source"] = "existing"
1246
+ asset["status"] = "generated"
1247
+ asset["url"] = _AUDIO_STUB
1248
+ # payload 留作 reference(renderer 不会再读它,因为 status=generated)
1249
+ elif src in ("gen-digital-human",):
1250
+ asset["source"] = "existing"
1251
+ asset["status"] = "generated"
1252
+ asset["url"] = _VIDEO_STUB
1253
+
1180
1254
  errors = validate_dsl(dsl)
1181
1255
  if errors:
1182
1256
  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,6 @@
2
2
  "skillName": "gen-script",
3
3
  "repoName": "agent-skill-media-maker",
4
4
  "skillId": "474",
5
- "version": "V8",
5
+ "version": "V10",
6
6
  "skillDescription": "视频脚本生成技能,将用户主题转化为结构化 Video DSL(JSON),描述视频的完整结构、素材需求与叙事逻辑。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- 帮我写视频脚本、生成视频脚本、视频策划、写分镜脚本\n- 做一个短视频、帮我规划视频内容、生成视频 DSL\n- 把主题转成视频结构、视频内容规划\n\n即使用户没有明确说「生成 DSL」,只要他们想要把一个主题变成视频内容结构,也要使用本 skill。"
7
7
  }
@@ -19,7 +19,7 @@ triggers:
19
19
 
20
20
  Wraps ab-api's `POST /model/genVideo` (the same endpoint the web "Lingchuang AI Video" tool uses), authenticated with the **Tianyan privateToken**, routed through LiteLLM to **Seedance** or **Veo**. Generation is async — the handler submits the task and polls `/model/getVideoStatus` until completion.
21
21
 
22
- > This skill was migrated from a Python script to an ab-skill CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_video`, same params as in `skill.json`); local repro goes through `ab-skill gen-video ...`.
22
+ > This skill was migrated from a Python script to an remixmate CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_video`, same params as in `skill.json`); local repro goes through `remixmate gen-video ...`.
23
23
 
24
24
  ## Models
25
25
 
@@ -72,7 +72,7 @@ No skill-local env file — the executing process inherits the system environmen
72
72
  ### Seedance text-to-video (default model)
73
73
 
74
74
  ```bash
75
- ab-skill gen-video \
75
+ remixmate gen-video \
76
76
  --prompt "<video description>" \
77
77
  --duration 5 \
78
78
  --ratio "16:9"
@@ -83,7 +83,7 @@ ab-skill gen-video \
83
83
  Frame images accept local file paths, HTTPS URLs, or data URIs (local files are base64-encoded into a data URI).
84
84
 
85
85
  ```bash
86
- ab-skill gen-video \
86
+ remixmate gen-video \
87
87
  --prompt "<transition description>" \
88
88
  --first-frame ./start.png \
89
89
  --last-frame ./end.png \
@@ -94,7 +94,7 @@ ab-skill gen-video \
94
94
  ### Veo 3.1 high-resolution
95
95
 
96
96
  ```bash
97
- ab-skill gen-video \
97
+ remixmate gen-video \
98
98
  --model veo \
99
99
  --prompt "<video description>" \
100
100
  --duration 8 \
@@ -105,7 +105,7 @@ ab-skill gen-video \
105
105
  ### Veo 3.1 Fast for rapid iteration
106
106
 
107
107
  ```bash
108
- ab-skill gen-video \
108
+ remixmate gen-video \
109
109
  --model veo-fast \
110
110
  --prompt "<video description>" \
111
111
  --duration 6
@@ -116,7 +116,7 @@ ab-skill gen-video \
116
116
  Pass `--reference` multiple times (Veo only, up to 3).
117
117
 
118
118
  ```bash
119
- ab-skill gen-video \
119
+ remixmate gen-video \
120
120
  --model veo \
121
121
  --prompt "<video description>" \
122
122
  --reference ./ref1.png \
@@ -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,6 @@
2
2
  "skillName": "gen-video",
3
3
  "repoName": "agent-skill-media-maker",
4
4
  "skillId": "339",
5
- "version": "V7",
5
+ "version": "V8",
6
6
  "skillDescription": "AI 生视频技能,根据文字描述生成素材视频(调用 ab-api /model/genVideo,支持 Seedance 与 Veo)。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- AI 生视频、文生视频、文字生成视频、生成一段视频、AI 制作视频\n- 使用 doubao / 豆包 / seedance、Veo、Google 等生成视频\n- 用户提供视频提示词并希望生成视频\n- 图生视频、首帧生成视频、参考图生成视频\n\n即使用户没有明确说「使用 AI」,只要他们想要根据描述生成视频,也要使用本 skill。"
7
7
  }
@@ -34,7 +34,7 @@ There is no skill-local env file — the executing process inherits the system e
34
34
 
35
35
  ## Operations
36
36
 
37
- > This skill was migrated from a Python script to an ab-skill CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_voice`, same params as in `skill.json`); local repro goes through `ab-skill gen-voice ...`. The legacy `--download` flag has been removed — audio URLs are persisted in the cloud and play directly.
37
+ > This skill was migrated from a Python script to an remixmate CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_voice`, same params as in `skill.json`); local repro goes through `remixmate gen-voice ...`. The legacy `--download` flag has been removed — audio URLs are persisted in the cloud and play directly.
38
38
 
39
39
  1. **Text**: confirm what to synthesize. Punctuation drives pauses (commas short, periods long).
40
40
  2. **Voice**: if the user prefers a specific voice, run `--list-voices` first and pick a matching id.
@@ -43,13 +43,13 @@ There is no skill-local env file — the executing process inherits the system e
43
43
  ### List available voices
44
44
 
45
45
  ```bash
46
- ab-skill gen-voice --list-voices
46
+ remixmate gen-voice --list-voices
47
47
  ```
48
48
 
49
49
  To inspect the local language-tagged fallback catalog used by the voice resolver (no remote API call), add `--local`:
50
50
 
51
51
  ```bash
52
- ab-skill gen-voice --list-voices --local
52
+ remixmate gen-voice --list-voices --local
53
53
  ```
54
54
 
55
55
  The local catalog prints one voice per line as `<voice-id>\t<lang>\t<display-name>`.
@@ -57,13 +57,13 @@ The local catalog prints one voice per line as `<voice-id>\t<lang>\t<display-nam
57
57
  ### Default synthesis (URL output)
58
58
 
59
59
  ```bash
60
- ab-skill gen-voice --text "<text-to-synthesize>"
60
+ remixmate gen-voice --text "<text-to-synthesize>"
61
61
  ```
62
62
 
63
63
  ### With voice + speed
64
64
 
65
65
  ```bash
66
- ab-skill gen-voice \
66
+ remixmate gen-voice \
67
67
  --text "<text-to-synthesize>" \
68
68
  --voice-id "female-shaonv" \
69
69
  --speed 1.2
@@ -72,7 +72,7 @@ ab-skill gen-voice \
72
72
  ### JSON output (with subtitle timestamps)
73
73
 
74
74
  ```bash
75
- ab-skill gen-voice --text "<text-to-synthesize>" --json-output
75
+ remixmate gen-voice --text "<text-to-synthesize>" --json-output
76
76
  ```
77
77
 
78
78
  ## Common CLI flags
@@ -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"],