@remixmate/cli 0.12.8 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/README.zh-CN.md +1 -1
- package/dist/manifest.json +21 -8
- package/dist/template/preview.js +7 -7
- package/dist/template/publish.js +8 -8
- package/dist/template/scene-props.js +1 -0
- package/dist/template/still-cases.js +1 -1
- package/package.json +1 -1
- package/skills/export-jianying/scripts/gen_jianying_draft.py +38 -33
- package/skills/export-jianying/version.json +1 -1
- package/skills/gen-script/SKILL.md +15 -13
- package/skills/gen-script/scripts/gen_script.py +906 -547
- package/skills/gen-script/skill.json +19 -6
- package/skills/gen-script/version.json +1 -1
- package/skills/render-video/scripts/_video_probe.py +0 -1
- package/skills/render-video/scripts/remote_renderer_client.py +9 -7
- package/skills/render-video/scripts/render_video.py +553 -391
- package/skills/render-video/version.json +1 -1
- package/skills/template-registry/SKILL.md +1 -1
- package/skills/template-registry/scripts/match_template.py +2 -2
- package/skills/template-registry/scripts/payload_hydrator.py +9 -1
- package/skills/template-registry/scripts/render_job_client.py +4 -0
- package/skills/template-registry/version.json +1 -1
- package/skills/template-registry/video_dsl/runtime/dsl_validator.py +50 -24
- package/skills/template-registry/video_dsl/schema/render-plan-v1alpha1.json +7 -1
- package/skills/video-parser/scripts/analyze_video.py +2 -0
- package/skills/video-parser/version.json +1 -1
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "render-video",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "473",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V39",
|
|
6
6
|
"skillDescription": "Final-render skill: loads a persisted RenderPlan by `job_id` and drives the Remotion engine to produce the final video.\n\nUse this skill as soon as the user mentions any of these intents (after assets are already prepared):\n- Render the video, composite the video, export the video\n- Turn the prepared assets into the final clip\n- Render with Remotion\n\nPrerequisite: assets must already be generated via `prepare_video_assets`. This skill never resolves or regenerates assets — pass it a `job_id` from a previous `prepare_video_assets` call.\n\n⚠️ Stop-and-confirm gate: never call this skill until the user has explicitly confirmed the assets prepared by `prepare_video_assets`. If those assets were prepared in the current turn and the user has not replied since, stop and ask instead of rendering."
|
|
7
7
|
}
|
|
@@ -140,7 +140,7 @@ remixmate template-registry --template-id <templateId> # then re
|
|
|
140
140
|
remixmate template-registry --template-id <templateId> --slide-id key-points --slide-id timeline # exact schemas of the chosen layouts
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
Detail mode used to pretty-print, which nearly doubled the size (
|
|
143
|
+
Detail mode used to pretty-print, which nearly doubled the size (a multi-layout template: 37 K → 65 K characters) and pushed the plain call past the agent's tool-result cap — the result was spilled to a file the agent cannot open, so it re-called with other flags, and re-read the whole contract on the next turn too (session review 2026-09-27). Output is now always compact, and `slideSchemas` — two thirds of a multi-layout template — is a menu until you name the layouts.
|
|
144
144
|
|
|
145
145
|
This mirrors the list/detail split described in `scripts/registry_loader.py` (P1.2), realized CLI-side so it holds even while the backend still serves one merged registry payload.
|
|
146
146
|
|
|
@@ -102,8 +102,6 @@ def build_binding(template: dict, dsl: dict) -> dict:
|
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
105
|
custom = scene.get("customPayload") or {}
|
|
108
106
|
template_data = custom.get("templateData") or scene.get("templateData") or {}
|
|
109
107
|
|
|
@@ -131,6 +129,8 @@ def build_binding(template: dict, dsl: dict) -> dict:
|
|
|
131
129
|
dual_channel = sorted(dual_channel)
|
|
132
130
|
|
|
133
131
|
|
|
132
|
+
|
|
133
|
+
|
|
134
134
|
for k, v in template_data.items():
|
|
135
135
|
if k not in props:
|
|
136
136
|
props[k] = v
|
|
@@ -129,11 +129,19 @@ def hydration_spec(template_config: Optional[dict]) -> Optional[dict]:
|
|
|
129
129
|
"Upgrade @remixmate/cli or fix the template."
|
|
130
130
|
)
|
|
131
131
|
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
doc_kind = spec.get("docKind")
|
|
135
|
+
if not isinstance(doc_kind, str) or not doc_kind:
|
|
136
|
+
raise HydrationError(
|
|
137
|
+
"template declares capabilities.payloadHydration without docKind (e.g. the file "
|
|
138
|
+
"extension the extractor should parse). Fix the template's payloadHydration."
|
|
139
|
+
)
|
|
132
140
|
index_field = spec.get("indexField")
|
|
133
141
|
return {
|
|
134
142
|
"payload_field": payload_field,
|
|
135
143
|
"source": source,
|
|
136
|
-
"doc_kind":
|
|
144
|
+
"doc_kind": doc_kind,
|
|
137
145
|
"fields": spec.get("fields") or "content,layout",
|
|
138
146
|
"index_field": index_field if isinstance(index_field, str) and index_field else DEFAULT_INDEX_FIELD,
|
|
139
147
|
}
|
|
@@ -77,6 +77,10 @@ def _post(path: str, payload: dict, priv_token: str, timeout: int = 30) -> dict:
|
|
|
77
77
|
except urllib.error.URLError as e:
|
|
78
78
|
raise RuntimeError(f"network request failed ({path}): {e.reason}") from e
|
|
79
79
|
|
|
80
|
+
|
|
81
|
+
except (OSError, ValueError) as e:
|
|
82
|
+
raise RuntimeError(f"request failed ({path}): {type(e).__name__}: {e}") from e
|
|
83
|
+
|
|
80
84
|
_record_billing(result)
|
|
81
85
|
|
|
82
86
|
if result.get("code") != 0:
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "template-registry",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "475",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V30",
|
|
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
|
}
|
|
@@ -573,6 +573,30 @@ def _check_slide_id_chosen(dsl: dict) -> list[ValidationError]:
|
|
|
573
573
|
return errors
|
|
574
574
|
|
|
575
575
|
|
|
576
|
+
def _cross_field_marks(slide_schema: dict) -> tuple[list, list]:
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
line_marks: list = []
|
|
584
|
+
substring_marks: list = []
|
|
585
|
+
props = (slide_schema or {}).get("properties") or {}
|
|
586
|
+
for key, spec in props.items():
|
|
587
|
+
if not isinstance(spec, dict):
|
|
588
|
+
continue
|
|
589
|
+
if isinstance(spec.get("x-lineIndexOf"), str):
|
|
590
|
+
line_marks.append((None, key, spec["x-lineIndexOf"]))
|
|
591
|
+
if isinstance(spec.get("x-substringOf"), str):
|
|
592
|
+
substring_marks.append((key, spec["x-substringOf"]))
|
|
593
|
+
item_props = ((spec.get("items") or {}).get("properties") or {}) if spec.get("type") == "array" else {}
|
|
594
|
+
for sub_key, sub_spec in item_props.items():
|
|
595
|
+
if isinstance(sub_spec, dict) and isinstance(sub_spec.get("x-lineIndexOf"), str):
|
|
596
|
+
line_marks.append((key, sub_key, sub_spec["x-lineIndexOf"]))
|
|
597
|
+
return line_marks, substring_marks
|
|
598
|
+
|
|
599
|
+
|
|
576
600
|
def _check_slide_cross_field(dsl: dict) -> list[ValidationError]:
|
|
577
601
|
|
|
578
602
|
|
|
@@ -611,23 +635,31 @@ def _check_slide_cross_field(dsl: dict) -> list[ValidationError]:
|
|
|
611
635
|
if not tdata:
|
|
612
636
|
continue
|
|
613
637
|
base = f"scenes[{idx}].customPayload.templateData"
|
|
638
|
+
line_marks, substring_marks = _cross_field_marks(schemas.get(slide_id) or {})
|
|
614
639
|
|
|
615
640
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
641
|
+
for array_key, key, ref in line_marks:
|
|
642
|
+
text = tdata.get(ref)
|
|
643
|
+
if not isinstance(text, str):
|
|
644
|
+
continue
|
|
645
|
+
total = len(text.split("\n"))
|
|
646
|
+
if array_key is None:
|
|
647
|
+
targets = [(f"{base}.{key}", tdata.get(key))]
|
|
648
|
+
else:
|
|
649
|
+
rows = tdata.get(array_key)
|
|
650
|
+
targets = [
|
|
651
|
+
(f"{base}.{array_key}[{i}].{key}", row.get(key))
|
|
652
|
+
for i, row in enumerate(rows if isinstance(rows, list) else [])
|
|
653
|
+
if isinstance(row, dict)
|
|
654
|
+
]
|
|
655
|
+
for path, line in targets:
|
|
624
656
|
if not isinstance(line, int) or isinstance(line, bool):
|
|
625
657
|
continue
|
|
626
658
|
if line < 1 or line > total:
|
|
627
659
|
errors.append(ValidationError(
|
|
628
|
-
|
|
629
|
-
f"scene '{sid}':
|
|
630
|
-
f"{total} line(s) — while that narration line plays,
|
|
660
|
+
path,
|
|
661
|
+
f"scene '{sid}': {key} points at line {line} of '{ref}', which has "
|
|
662
|
+
f"{total} line(s) — while that narration line plays, nothing lights "
|
|
631
663
|
"up at all. Line numbers are 1-based.",
|
|
632
664
|
))
|
|
633
665
|
|
|
@@ -648,20 +680,14 @@ def _check_slide_cross_field(dsl: dict) -> list[ValidationError]:
|
|
|
648
680
|
))
|
|
649
681
|
|
|
650
682
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
title = tdata.get("title")
|
|
655
|
-
if (
|
|
656
|
-
isinstance(highlight, str)
|
|
657
|
-
and highlight.strip()
|
|
658
|
-
and isinstance(title, str)
|
|
659
|
-
and highlight not in title
|
|
660
|
-
):
|
|
683
|
+
for key, ref in substring_marks:
|
|
684
|
+
part, whole = tdata.get(key), tdata.get(ref)
|
|
685
|
+
if isinstance(part, str) and part.strip() and isinstance(whole, str) and part not in whole:
|
|
661
686
|
errors.append(ValidationError(
|
|
662
|
-
f"{base}.
|
|
663
|
-
f"scene '{sid}':
|
|
664
|
-
f"'{
|
|
687
|
+
f"{base}.{key}",
|
|
688
|
+
f"scene '{sid}': {key} '{part}' is not a substring of {ref} "
|
|
689
|
+
f"'{whole}' — the template declares it must be, and silently drops "
|
|
690
|
+
"the emphasis otherwise.",
|
|
665
691
|
severity="warning",
|
|
666
692
|
))
|
|
667
693
|
|
|
@@ -122,7 +122,13 @@
|
|
|
122
122
|
},
|
|
123
123
|
"layers": {
|
|
124
124
|
"type": "array",
|
|
125
|
-
"items": { "$ref": "#/definitions/Layer" }
|
|
125
|
+
"items": { "$ref": "#/definitions/Layer" },
|
|
126
|
+
"description": "已废弃:render_video 不再写入,读到旧 RenderPlan 里的也会丢掉。场景用到的素材以 props 里的 assetId 引用为准"
|
|
127
|
+
},
|
|
128
|
+
"textLayers": {
|
|
129
|
+
"type": "array",
|
|
130
|
+
"items": { "type": "object" },
|
|
131
|
+
"description": "DSL 场景 textLayers 的原样拷贝(渲染不读,供剪映导出等只拿到 RenderPlan 的下游还原文本图层)"
|
|
126
132
|
},
|
|
127
133
|
"subtitleSegments": {
|
|
128
134
|
"type": "array",
|
|
@@ -808,11 +808,13 @@ def build_assets_summary(decon: dict) -> dict:
|
|
|
808
808
|
"url": audio.get("url", ""),
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
+
|
|
811
812
|
kf_list = []
|
|
812
813
|
for kf in keyframes:
|
|
813
814
|
kf_list.append({
|
|
814
815
|
"index": kf["index"],
|
|
815
816
|
"localPath": kf.get("localPath", ""),
|
|
817
|
+
"url": kf.get("url", ""),
|
|
816
818
|
"timestampSec": kf.get("timestampSec", 0.0),
|
|
817
819
|
})
|
|
818
820
|
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "video-parser",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "553",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V4",
|
|
6
6
|
"skillDescription": "Video deconstruction skill. Splits a video into reusable content assets — audio, ASR transcript, scene segments, keyframe images.\n\nUse this skill as soon as the user mentions any of these intents:\n- Deconstruct / split / analyze / parse a video\n- Extract keyframes, extract the script from a video, transcribe a video\n- Pull content assets or raw material out of a video\n\nEven when the user does not say \"deconstruct\" explicitly, use this skill whenever they want to extract script text, keyframes, or structured information from a video."
|
|
7
7
|
}
|