zerocut-cli 0.3.0 → 0.3.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.
- package/dist/commands/image.js +2 -0
- package/dist/commands/skill.js +22 -9
- package/dist/commands/video.js +109 -14
- package/dist/services/config.js +7 -2
- package/dist/skill/SKILL.md +153 -18
- package/dist/skill/edit-video/SKILL.md +111 -0
- package/dist/skill/one-click-video/SKILL.md +140 -0
- package/package.json +1 -1
- package/scripts/copy-skill-md.cjs +4 -4
package/dist/commands/image.js
CHANGED
|
@@ -21,6 +21,7 @@ function register(program) {
|
|
|
21
21
|
"banana2",
|
|
22
22
|
"banana-pro",
|
|
23
23
|
"wan",
|
|
24
|
+
"wan-pro",
|
|
24
25
|
];
|
|
25
26
|
const allowedAspectRatios = [
|
|
26
27
|
"1:1",
|
|
@@ -46,6 +47,7 @@ function register(program) {
|
|
|
46
47
|
aspect_ratio: aspectRatio,
|
|
47
48
|
resolution,
|
|
48
49
|
reference_images: referenceImages,
|
|
50
|
+
sequential_image_generation: "disabled",
|
|
49
51
|
onProgress,
|
|
50
52
|
};
|
|
51
53
|
const res = await session.ai.generateImage(payload);
|
package/dist/commands/skill.js
CHANGED
|
@@ -9,16 +9,29 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
10
|
exports.name = "skill";
|
|
11
11
|
exports.description = "Print built-in SKILL.md content";
|
|
12
|
+
function printSkill(relativePath) {
|
|
13
|
+
const filePath = node_path_1.default.resolve(__dirname, relativePath);
|
|
14
|
+
const content = node_fs_1.default.readFileSync(filePath, "utf8");
|
|
15
|
+
process.stdout.write(content);
|
|
16
|
+
if (!content.endsWith("\n")) {
|
|
17
|
+
process.stdout.write("\n");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
12
20
|
function register(program) {
|
|
13
|
-
program
|
|
14
|
-
|
|
15
|
-
.
|
|
21
|
+
const parent = program.command("skill").description("Print built-in skill markdown");
|
|
22
|
+
parent
|
|
23
|
+
.command("one-click-video")
|
|
24
|
+
.description("Print one-click-video skill markdown")
|
|
25
|
+
.action(() => {
|
|
26
|
+
printSkill("../skill/one-click-video/SKILL.md");
|
|
27
|
+
});
|
|
28
|
+
parent
|
|
29
|
+
.command("edit-video")
|
|
30
|
+
.description("Print edit-video skill markdown")
|
|
16
31
|
.action(() => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
process.stdout.write("\n");
|
|
22
|
-
}
|
|
32
|
+
printSkill("../skill/edit-video/SKILL.md");
|
|
33
|
+
});
|
|
34
|
+
parent.action(() => {
|
|
35
|
+
printSkill("../skill/SKILL.md");
|
|
23
36
|
});
|
|
24
37
|
}
|
package/dist/commands/video.js
CHANGED
|
@@ -11,11 +11,35 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
11
11
|
const progress_1 = require("../utils/progress");
|
|
12
12
|
exports.name = "video";
|
|
13
13
|
exports.description = "Video command: create video";
|
|
14
|
+
function resolveResultUrl(result) {
|
|
15
|
+
if (!result || typeof result !== "object") {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const record = result;
|
|
19
|
+
if (typeof record.url === "string" && record.url.length > 0) {
|
|
20
|
+
return record.url;
|
|
21
|
+
}
|
|
22
|
+
const data = record.data;
|
|
23
|
+
if (data && typeof data === "object") {
|
|
24
|
+
const dataRecord = data;
|
|
25
|
+
if (typeof dataRecord.url === "string" && dataRecord.url.length > 0) {
|
|
26
|
+
return dataRecord.url;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
14
31
|
function register(program) {
|
|
32
|
+
const avatarModels = ["zerocut-avatar-1.0", "zerocut-avatar-1.5"];
|
|
33
|
+
const mvModels = ["zerocut-mv-1.0"];
|
|
15
34
|
const parent = program.command("video").description("Create a new video; requires --prompt");
|
|
16
35
|
const allowedTypes = [
|
|
17
36
|
"zerocut3.0",
|
|
37
|
+
"zerocut3.0-pro",
|
|
38
|
+
"zerocut3.0-pro-fast",
|
|
39
|
+
"zerocut3.0-turbo",
|
|
18
40
|
"seedance-1.5-pro",
|
|
41
|
+
"seedance-2.0",
|
|
42
|
+
"seedance-2.0-fast",
|
|
19
43
|
"vidu",
|
|
20
44
|
"vidu-pro",
|
|
21
45
|
"viduq3",
|
|
@@ -28,6 +52,8 @@ function register(program) {
|
|
|
28
52
|
"sora2-pro",
|
|
29
53
|
"veo3.1",
|
|
30
54
|
"veo3.1-pro",
|
|
55
|
+
...avatarModels,
|
|
56
|
+
...mvModels,
|
|
31
57
|
];
|
|
32
58
|
async function videoCreateAction(opts) {
|
|
33
59
|
const session = (0, cerevox_1.getSessionFromCommand)(this);
|
|
@@ -41,20 +67,30 @@ function register(program) {
|
|
|
41
67
|
process.exitCode = 1;
|
|
42
68
|
return;
|
|
43
69
|
}
|
|
44
|
-
let model = typeof opts.
|
|
70
|
+
let model = typeof opts.model === "string" ? opts.model.trim() : undefined;
|
|
45
71
|
if (model && !allowedTypes.includes(model)) {
|
|
46
|
-
process.stderr.write(`Invalid value for --
|
|
72
|
+
process.stderr.write(`Invalid value for --model: ${model}. Allowed: ${allowedTypes.join("|")}\n`);
|
|
47
73
|
process.exitCode = 1;
|
|
48
74
|
return;
|
|
49
75
|
}
|
|
50
76
|
if (!model)
|
|
51
77
|
model = "vidu";
|
|
52
78
|
const durationStr = typeof opts.duration === "string" ? opts.duration.trim() : undefined;
|
|
79
|
+
const sourceVideo = typeof opts.sourceVideo === "string" ? opts.sourceVideo.trim() : undefined;
|
|
53
80
|
let duration = 0;
|
|
81
|
+
const durationRange = (() => {
|
|
82
|
+
if (avatarModels.includes(model)) {
|
|
83
|
+
return { min: 5, max: 240 };
|
|
84
|
+
}
|
|
85
|
+
if (mvModels.includes(model)) {
|
|
86
|
+
return { min: 1, max: 240 };
|
|
87
|
+
}
|
|
88
|
+
return { min: 1, max: 16 };
|
|
89
|
+
})();
|
|
54
90
|
if (durationStr) {
|
|
55
91
|
const n = Number.parseInt(durationStr, 10);
|
|
56
|
-
if (!Number.isFinite(n) || n <
|
|
57
|
-
process.stderr.write(
|
|
92
|
+
if (!Number.isFinite(n) || n < durationRange.min || n > durationRange.max) {
|
|
93
|
+
process.stderr.write(`Invalid value for --duration: model ${model} supports integer ${durationRange.min}-${durationRange.max}\n`);
|
|
58
94
|
process.exitCode = 1;
|
|
59
95
|
return;
|
|
60
96
|
}
|
|
@@ -68,6 +104,21 @@ function register(program) {
|
|
|
68
104
|
return;
|
|
69
105
|
}
|
|
70
106
|
const aspectRatio = ar;
|
|
107
|
+
let withBGM = true;
|
|
108
|
+
if (typeof opts.withBGM === "string") {
|
|
109
|
+
const withBGMRaw = opts.withBGM.trim().toLowerCase();
|
|
110
|
+
if (withBGMRaw === "true") {
|
|
111
|
+
withBGM = true;
|
|
112
|
+
}
|
|
113
|
+
else if (withBGMRaw === "false") {
|
|
114
|
+
withBGM = false;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
process.stderr.write("Invalid value for --withBGM: expected true|false\n");
|
|
118
|
+
process.exitCode = 1;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
71
122
|
const images = [];
|
|
72
123
|
if (opts.firstFrame) {
|
|
73
124
|
images.push({
|
|
@@ -81,6 +132,24 @@ function register(program) {
|
|
|
81
132
|
url: await (0, cerevox_1.getMaterialUri)(session, opts.lastFrame),
|
|
82
133
|
});
|
|
83
134
|
}
|
|
135
|
+
if (opts.storyboard) {
|
|
136
|
+
images.push({
|
|
137
|
+
type: "storyboard",
|
|
138
|
+
url: await (0, cerevox_1.getMaterialUri)(session, opts.storyboard),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const personList = typeof opts.persons === "string" && opts.persons.length > 0
|
|
142
|
+
? opts.persons
|
|
143
|
+
.split(",")
|
|
144
|
+
.map((s) => s.trim())
|
|
145
|
+
.filter((s) => s.length > 0)
|
|
146
|
+
: [];
|
|
147
|
+
for (const person of personList) {
|
|
148
|
+
images.push({
|
|
149
|
+
type: "person",
|
|
150
|
+
url: await (0, cerevox_1.getMaterialUri)(session, person),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
84
153
|
const refsList = typeof opts.refs === "string" && opts.refs.length > 0
|
|
85
154
|
? opts.refs
|
|
86
155
|
.split(",")
|
|
@@ -93,21 +162,33 @@ function register(program) {
|
|
|
93
162
|
url: await (0, cerevox_1.getMaterialUri)(session, ref),
|
|
94
163
|
});
|
|
95
164
|
}
|
|
96
|
-
const
|
|
165
|
+
const request = {
|
|
97
166
|
prompt,
|
|
98
167
|
model: model,
|
|
99
168
|
duration: duration || undefined,
|
|
100
169
|
resolution: opts.resolution,
|
|
101
170
|
aspect_ratio: aspectRatio,
|
|
102
|
-
mute: !opts.withAudio,
|
|
171
|
+
mute: !(opts.withAudio ?? true),
|
|
172
|
+
bgm: withBGM,
|
|
103
173
|
optimize_camera: opts.optimizeCameraMotion,
|
|
104
174
|
seed: opts.seed ? Number.parseInt(opts.seed, 10) : undefined,
|
|
105
175
|
images: images.length > 0 ? images : undefined,
|
|
176
|
+
videos: sourceVideo
|
|
177
|
+
? [
|
|
178
|
+
{
|
|
179
|
+
type: "base",
|
|
180
|
+
url: await (0, cerevox_1.getMaterialUri)(session, sourceVideo),
|
|
181
|
+
},
|
|
182
|
+
]
|
|
183
|
+
: undefined,
|
|
106
184
|
onProgress: (0, progress_1.createProgressSpinner)("inferencing"),
|
|
107
|
-
|
|
185
|
+
timeout: 7200000,
|
|
186
|
+
};
|
|
187
|
+
const res = await session.ai.generateVideo(request);
|
|
188
|
+
const initialUrl = resolveResultUrl(res);
|
|
108
189
|
try {
|
|
109
|
-
if (
|
|
110
|
-
const tosUrl = await (0, cerevox_1.syncToTOS)(
|
|
190
|
+
if (initialUrl) {
|
|
191
|
+
const tosUrl = await (0, cerevox_1.syncToTOS)(initialUrl);
|
|
111
192
|
if (tosUrl) {
|
|
112
193
|
res.url = tosUrl;
|
|
113
194
|
}
|
|
@@ -118,7 +199,13 @@ function register(program) {
|
|
|
118
199
|
const output = typeof opts.output === "string" ? opts.output : undefined;
|
|
119
200
|
if (output) {
|
|
120
201
|
const dir = process.cwd();
|
|
121
|
-
const url = res
|
|
202
|
+
const url = resolveResultUrl(res);
|
|
203
|
+
if (!url) {
|
|
204
|
+
process.stderr.write("Cannot save --output because no video URL was returned. Please retry later or run without --output to inspect raw response.\n");
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
console.log(res);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
122
209
|
const response = await fetch(url);
|
|
123
210
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
124
211
|
const filePath = node_path_1.default.resolve(dir, output);
|
|
@@ -133,15 +220,19 @@ function register(program) {
|
|
|
133
220
|
// default action on `zerocut video`
|
|
134
221
|
parent
|
|
135
222
|
.option("--prompt <prompt>", "Text prompt for video generation (required)")
|
|
136
|
-
.option("--duration <duration>", "Video duration in seconds")
|
|
137
|
-
.option("--
|
|
223
|
+
.option("--duration <duration>", "Video duration in seconds (default models: 1-16, avatar: 5-240, mv: 1-240)")
|
|
224
|
+
.option("--model <model>", `Video model: ${allowedTypes.join("|")} (default: vidu)`)
|
|
225
|
+
.option("--sourceVideo <video>", "Base video path/url for edit mode (requires --duration 3-10)")
|
|
138
226
|
.option("--seed <seed>", "Random seed")
|
|
139
227
|
.option("--firstFrame <image>", "First frame image path/url")
|
|
140
228
|
.option("--lastFrame <image>", "Last frame image path/url")
|
|
229
|
+
.option("--storyboard <image>", "Storyboard image path/url")
|
|
230
|
+
.option("--persons <persons>", "Comma-separated person image paths/urls")
|
|
141
231
|
.option("--refs <refs>", "Comma-separated reference image/video paths/urls")
|
|
142
232
|
.option("--resolution <resolution>", "Resolution, e.g., 720p")
|
|
143
233
|
.option("--aspectRatio <ratio>", "Aspect ratio: 9:16|16:9|1:1")
|
|
144
234
|
.option("--withAudio", "Include audio track")
|
|
235
|
+
.option("--withBGM <withBGM>", "Include background music: true|false (default: true)")
|
|
145
236
|
.option("--optimizeCameraMotion", "Optimize camera motion")
|
|
146
237
|
.option("--output <file>", "Output file path")
|
|
147
238
|
.action(videoCreateAction);
|
|
@@ -150,15 +241,19 @@ function register(program) {
|
|
|
150
241
|
.command("create")
|
|
151
242
|
.description("Create a new video; requires --prompt")
|
|
152
243
|
.option("--prompt <prompt>", "Text prompt for video generation (required)")
|
|
153
|
-
.option("--duration <duration>", "Video duration in seconds")
|
|
154
|
-
.option("--
|
|
244
|
+
.option("--duration <duration>", "Video duration in seconds (default models: 1-16, avatar: 5-240, mv: 1-240)")
|
|
245
|
+
.option("--model <model>", `Video model: ${allowedTypes.join("|")} (default: vidu)`)
|
|
246
|
+
.option("--sourceVideo <video>", "Base video path/url for edit mode (requires --duration 3-10)")
|
|
155
247
|
.option("--seed <seed>", "Random seed")
|
|
156
248
|
.option("--firstFrame <image>", "First frame image path/url")
|
|
157
249
|
.option("--lastFrame <image>", "Last frame image path/url")
|
|
250
|
+
.option("--storyboard <image>", "Storyboard image path/url")
|
|
251
|
+
.option("--persons <persons>", "Comma-separated person image paths/urls")
|
|
158
252
|
.option("--refs <refs>", "Comma-separated reference image/video paths/urls")
|
|
159
253
|
.option("--resolution <resolution>", "Resolution, e.g., 720p")
|
|
160
254
|
.option("--aspectRatio <ratio>", "Aspect ratio: 9:16|16:9|1:1")
|
|
161
255
|
.option("--withAudio", "Include audio track")
|
|
256
|
+
.option("--withBGM <withBGM>", "Include background music: true|false (default: true)")
|
|
162
257
|
.option("--optimizeCameraMotion", "Optimize camera motion")
|
|
163
258
|
.option("--output <file>", "Output file path")
|
|
164
259
|
.action(videoCreateAction);
|
package/dist/services/config.js
CHANGED
|
@@ -207,7 +207,11 @@ function applyConfigInterceptor(program) {
|
|
|
207
207
|
const current = (actionCommand ?? thisCommand);
|
|
208
208
|
const name = current?.name?.();
|
|
209
209
|
const parentName = current?.parent?.name?.();
|
|
210
|
-
if (name === "help" ||
|
|
210
|
+
if (name === "help" ||
|
|
211
|
+
name === "skill" ||
|
|
212
|
+
name === "config" ||
|
|
213
|
+
parentName === "config" ||
|
|
214
|
+
parentName === "skill")
|
|
211
215
|
return;
|
|
212
216
|
const ok = await ensureConfig();
|
|
213
217
|
if (!ok) {
|
|
@@ -221,7 +225,8 @@ function applyConfigInterceptor(program) {
|
|
|
221
225
|
});
|
|
222
226
|
program.hook("postAction", async (thisCommand, actionCommand) => {
|
|
223
227
|
const name = actionCommand?.name?.() ?? thisCommand?.name?.();
|
|
224
|
-
|
|
228
|
+
const parentName = actionCommand?.parent?.name?.() ?? thisCommand?.parent?.name?.();
|
|
229
|
+
if (name === "help" || name === "skill" || parentName === "skill")
|
|
225
230
|
return;
|
|
226
231
|
try {
|
|
227
232
|
const cmd = (actionCommand ?? thisCommand);
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "zerocut-cli-tools"
|
|
3
3
|
description: "Use ZeroCut CLI media and document tools. Invoke when user needs generate media, run ffmpeg/pandoc, sync resources, or save outputs."
|
|
4
|
+
homepage: "https://github.com/liubei-ai/zerocut-cli"
|
|
5
|
+
source: "https://github.com/liubei-ai/zerocut-cli"
|
|
6
|
+
requires_binaries:
|
|
7
|
+
- "zerocut-cli"
|
|
8
|
+
- "npx"
|
|
4
9
|
---
|
|
5
10
|
|
|
6
11
|
# ZeroCut CLI Tools
|
|
@@ -8,6 +13,7 @@ description: "Use ZeroCut CLI media and document tools. Invoke when user needs g
|
|
|
8
13
|
## Purpose
|
|
9
14
|
|
|
10
15
|
This skill provides a single reference for using ZeroCut CLI commands:
|
|
16
|
+
|
|
11
17
|
- image generation
|
|
12
18
|
- video generation
|
|
13
19
|
- music generation
|
|
@@ -18,24 +24,89 @@ This skill provides a single reference for using ZeroCut CLI commands:
|
|
|
18
24
|
## When To Invoke
|
|
19
25
|
|
|
20
26
|
Invoke this skill when the user asks to:
|
|
27
|
+
|
|
21
28
|
- generate image, video, music, or speech audio
|
|
22
29
|
- run ffmpeg or ffprobe command in sandbox
|
|
23
30
|
- run pandoc conversion in sandbox
|
|
24
31
|
- sync local/remote resources into sandbox
|
|
25
32
|
- save generated results to local output files
|
|
26
33
|
|
|
34
|
+
## Runtime Requirements
|
|
35
|
+
|
|
36
|
+
- Runtime expects `zerocut-cli` to be available in current environment.
|
|
37
|
+
- If `zerocut-cli` is unavailable, use one of:
|
|
38
|
+
- `pnpm dlx zerocut-cli help`
|
|
39
|
+
- `pnpm add -g zerocut-cli && zerocut-cli help`
|
|
40
|
+
- `npx zerocut-cli help`
|
|
41
|
+
- This skill is instruction-only and relies on the installed CLI binary for actual enforcement.
|
|
42
|
+
|
|
43
|
+
## Safety Boundaries
|
|
44
|
+
|
|
45
|
+
- Only sync files or URLs that user explicitly requests for the current task.
|
|
46
|
+
- Never auto-discover, crawl, or fetch unrelated remote URLs.
|
|
47
|
+
- Treat remote resources as untrusted input and pass through CLI validation.
|
|
48
|
+
- Never sync secrets, key files, token files, or unrelated private directories.
|
|
49
|
+
- Keep all output writes in user-requested path or current working directory naming rules.
|
|
50
|
+
- Do not bypass CLI command guards; ffmpeg/pandoc restrictions are enforced by the CLI implementation.
|
|
51
|
+
|
|
52
|
+
## Credentials And Data Transfer
|
|
53
|
+
|
|
54
|
+
- Required credential is `apiKey` in local ZeroCut config.
|
|
55
|
+
- If `apiKey` is missing, stop immediately and request OTT token exchange.
|
|
56
|
+
- `TOS` in this document means object storage used by ZeroCut backend for media URLs.
|
|
57
|
+
- No extra credential beyond ZeroCut config is required for normal media sync/download flows.
|
|
58
|
+
- Do not send data to any external service other than endpoints used by configured ZeroCut session.
|
|
59
|
+
|
|
60
|
+
## Required Pre-Check
|
|
61
|
+
|
|
62
|
+
Before every task, the agent must check configuration first:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx zerocut-cli config list
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If `apiKey` is missing or empty, the agent must immediately stop task execution and request an OTT token from the user. Do not continue any generation, conversion, or sandbox command until configuration is completed.
|
|
69
|
+
|
|
70
|
+
Required user action:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npx zerocut-cli config --ott <token> --region <cn|us>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Notes:
|
|
77
|
+
|
|
78
|
+
- `region` must be `cn` or `us`
|
|
79
|
+
- OTT exchange writes `apiKey` and `region` into config
|
|
80
|
+
- when running `config key` without direct key, region must be `cn|us` and OTT is required
|
|
81
|
+
|
|
27
82
|
## Command Reference
|
|
28
83
|
|
|
84
|
+
### skill
|
|
85
|
+
|
|
86
|
+
Use `skill` command to fetch built-in skill markdown:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npx zerocut-cli skill
|
|
90
|
+
npx zerocut-cli skill one-click-video
|
|
91
|
+
npx zerocut-cli skill edit-video
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Routing rules:
|
|
95
|
+
|
|
96
|
+
- When user requests one-click video creation, run `npx zerocut-cli skill one-click-video` to get the sub-skill and execute.
|
|
97
|
+
- When user requests video editing, run `npx zerocut-cli skill edit-video` to get the sub-skill and execute.
|
|
98
|
+
|
|
29
99
|
### image
|
|
30
100
|
|
|
31
101
|
Default action: `create`
|
|
32
102
|
|
|
33
103
|
```bash
|
|
34
|
-
zerocut image --prompt "a cat on a bike" --output out.png
|
|
35
|
-
zerocut image create --prompt "a cat on a bike" --model seedream-5l --aspectRatio 1:1 --resolution 1K --refs ref1.png,ref2.jpg --output out.png
|
|
104
|
+
npx zerocut-cli image --prompt "a cat on a bike" --output out.png
|
|
105
|
+
npx zerocut-cli image create --prompt "a cat on a bike" --model seedream-5l --aspectRatio 1:1 --resolution 1K --refs ref1.png,ref2.jpg --output out.png
|
|
36
106
|
```
|
|
37
107
|
|
|
38
108
|
Options:
|
|
109
|
+
|
|
39
110
|
- `--prompt <prompt>` required
|
|
40
111
|
- `--model <model>`
|
|
41
112
|
- `--aspectRatio <ratio>`
|
|
@@ -43,91 +114,155 @@ Options:
|
|
|
43
114
|
- `--refs <refs>` comma-separated local paths or URLs
|
|
44
115
|
- `--output <file>` save generated file
|
|
45
116
|
|
|
117
|
+
Validation rules:
|
|
118
|
+
|
|
119
|
+
- `--prompt` must be non-empty
|
|
120
|
+
- `--model` allowed: `seedream|seedream-pro|seedream-5l|banana|banana2|banana-pro|wan|wan-pro`
|
|
121
|
+
- `--aspectRatio` allowed: `1:1|3:4|4:3|16:9|9:16|2:3|3:2|21:9|1:4|4:1|1:8|8:1`
|
|
122
|
+
- unless user specifies aspect ratio, default to `16:9`
|
|
123
|
+
- `--resolution` allowed: `1K|2K|4K`
|
|
124
|
+
- unless user specifies resolution, default to `1K`
|
|
125
|
+
|
|
46
126
|
### video
|
|
47
127
|
|
|
48
128
|
Default action: `create`
|
|
49
129
|
|
|
50
130
|
```bash
|
|
51
|
-
zerocut video --prompt "city night drive" --
|
|
52
|
-
zerocut video create --prompt "city night drive" --
|
|
131
|
+
npx zerocut-cli video --prompt "city night drive" --model vidu --duration 8 --output out.mp4
|
|
132
|
+
npx zerocut-cli video create --prompt "city night drive" --model vidu --aspectRatio 1:1 --refs ref1.png,ref2.png --output out.mp4
|
|
133
|
+
npx zerocut-cli video --prompt "remix this clip" --model vidu --sourceVideo input.mp4 --duration 6 --output edited.mp4
|
|
53
134
|
```
|
|
54
135
|
|
|
55
136
|
Options:
|
|
137
|
+
|
|
56
138
|
- `--prompt <prompt>` required
|
|
57
|
-
- `--
|
|
58
|
-
- `--duration <seconds>`
|
|
139
|
+
- `--model <model>`
|
|
140
|
+
- `--duration <seconds>` model-dependent integer
|
|
141
|
+
- `--sourceVideo <video>` base video for edit mode
|
|
59
142
|
- `--seed <seed>`
|
|
60
143
|
- `--firstFrame <image>`
|
|
61
144
|
- `--lastFrame <image>`
|
|
145
|
+
- `--storyboard <image>`
|
|
146
|
+
- `--persons <persons>`
|
|
62
147
|
- `--refs <assets>`
|
|
63
148
|
- `--resolution <resolution>`
|
|
64
149
|
- `--aspectRatio <ratio>`
|
|
65
150
|
- `--withAudio`
|
|
151
|
+
- `--withBGM <withBGM>`
|
|
66
152
|
- `--optimizeCameraMotion`
|
|
67
153
|
- `--output <file>`
|
|
68
154
|
|
|
155
|
+
Validation rules:
|
|
156
|
+
|
|
157
|
+
- `--prompt` must be non-empty
|
|
158
|
+
- `--model` allowed: `zerocut3.0|zerocut3.0-pro|zerocut3.0-pro-fast|zerocut3.0-turbo|seedance-1.5-pro|seedance-2.0|seedance-2.0-fast|vidu|vidu-pro|viduq3|viduq3-turbo|kling|kling-v3|wan|wan-flash|sora2|sora2-pro|veo3.1|veo3.1-pro|zerocut-avatar-1.0|zerocut-avatar-1.5|zerocut-mv-1.0`
|
|
159
|
+
- `--duration` must follow model range:
|
|
160
|
+
- default models: `1-16`
|
|
161
|
+
- `zerocut-avatar-1.0` / `zerocut-avatar-1.5`: `5-240`
|
|
162
|
+
- `zerocut-mv-1.0`: `1-240`
|
|
163
|
+
- `--aspectRatio` allowed: `9:16|16:9|1:1`
|
|
164
|
+
- unless user specifies aspect ratio, default to `16:9`
|
|
165
|
+
- unless user specifies resolution, default to `720p`
|
|
166
|
+
- `--withBGM` allowed: `true|false`, default to `true`
|
|
167
|
+
|
|
168
|
+
Long video guidance:
|
|
169
|
+
|
|
170
|
+
- for default models, if required duration is over 16s, split into multiple generations (each 1-16s)
|
|
171
|
+
- then concatenate clips with ffmpeg
|
|
172
|
+
- example:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
printf "file 'part1.mp4'\nfile 'part2.mp4'\nfile 'part3.mp4'\n" > concat.txt
|
|
176
|
+
npx zerocut-cli ffmpeg --args -f concat -safe 0 -i concat.txt -c copy final.mp4 --resources concat.txt part1.mp4 part2.mp4 part3.mp4
|
|
177
|
+
```
|
|
178
|
+
|
|
69
179
|
### music
|
|
70
180
|
|
|
71
181
|
Default action: `create`
|
|
72
182
|
|
|
73
183
|
```bash
|
|
74
|
-
zerocut music --prompt "lofi beat" --output music.mp3
|
|
75
|
-
zerocut music create --prompt "lofi beat" --output music.mp3
|
|
184
|
+
npx zerocut-cli music --prompt "lofi beat" --output music.mp3
|
|
185
|
+
npx zerocut-cli music create --prompt "lofi beat" --output music.mp3
|
|
76
186
|
```
|
|
77
187
|
|
|
78
188
|
Options:
|
|
189
|
+
|
|
79
190
|
- `--prompt <prompt>` required
|
|
80
191
|
- `--output <file>`
|
|
81
192
|
|
|
193
|
+
Validation rules:
|
|
194
|
+
|
|
195
|
+
- `--prompt` must be non-empty
|
|
196
|
+
|
|
82
197
|
### tts
|
|
83
198
|
|
|
84
199
|
Default action: `create`
|
|
85
200
|
|
|
86
201
|
```bash
|
|
87
|
-
zerocut tts --text "你好,欢迎使用 ZeroCut" --voiceId voice_xxx --output speech.mp3
|
|
88
|
-
zerocut tts create --prompt "calm tone" --text "Hello world" --voiceId voice_xxx --output speech.mp3
|
|
202
|
+
npx zerocut-cli tts --text "你好,欢迎使用 ZeroCut" --voiceId voice_xxx --output speech.mp3
|
|
203
|
+
npx zerocut-cli tts create --prompt "calm tone" --text "Hello world" --voiceId voice_xxx --output speech.mp3
|
|
89
204
|
```
|
|
90
205
|
|
|
91
206
|
Options:
|
|
207
|
+
|
|
92
208
|
- `--prompt <prompt>`
|
|
93
209
|
- `--text <text>` required
|
|
94
210
|
- `--voiceId <voiceId>`
|
|
95
211
|
- `--output <file>`
|
|
96
212
|
|
|
213
|
+
Validation rules:
|
|
214
|
+
|
|
215
|
+
- `--text` must be non-empty
|
|
216
|
+
|
|
97
217
|
### ffmpeg
|
|
98
218
|
|
|
99
219
|
```bash
|
|
100
|
-
zerocut ffmpeg --args -i input.mp4 -vn output.mp3 --resources input.mp4
|
|
101
|
-
zerocut ffmpeg --args -i input.mp4 -vf scale=1280:720 output.mp4 --resources input.mp4
|
|
220
|
+
npx zerocut-cli ffmpeg --args -i input.mp4 -vn output.mp3 --resources input.mp4
|
|
221
|
+
npx zerocut-cli ffmpeg --args -i input.mp4 -vf scale=1280:720 output.mp4 --resources input.mp4
|
|
102
222
|
```
|
|
103
223
|
|
|
104
224
|
Options:
|
|
225
|
+
|
|
105
226
|
- `--args <args...>` required, arguments appended after `ffmpeg`
|
|
106
227
|
- `--resources <resources...>` optional, files/URLs to sync into sandbox materials
|
|
107
228
|
|
|
108
229
|
Behavior:
|
|
109
|
-
|
|
230
|
+
|
|
231
|
+
- `--args` must be provided
|
|
232
|
+
- command prefix is fixed as `ffmpeg`
|
|
110
233
|
- for `ffmpeg`, `-y` is auto-injected when absent
|
|
111
234
|
- output file is auto-downloaded from sandbox to local current directory
|
|
112
235
|
|
|
113
236
|
### pandoc
|
|
114
237
|
|
|
115
238
|
```bash
|
|
116
|
-
zerocut pandoc --args input.md -o output.pdf --resources input.md
|
|
117
|
-
zerocut pandoc --args input.md --output=output.docx --resources input.md template.docx
|
|
239
|
+
npx zerocut-cli pandoc --args input.md -o output.pdf --resources input.md
|
|
240
|
+
npx zerocut-cli pandoc --args input.md --output=output.docx --resources input.md template.docx
|
|
118
241
|
```
|
|
119
242
|
|
|
120
243
|
Options:
|
|
244
|
+
|
|
121
245
|
- `--args <args...>` required, arguments appended after `pandoc`
|
|
122
246
|
- `--resources <resources...>` optional, files/URLs to sync into sandbox materials
|
|
123
247
|
|
|
124
248
|
Behavior:
|
|
125
|
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
249
|
+
|
|
250
|
+
- `--args` must be provided
|
|
251
|
+
- command prefix is fixed as `pandoc`
|
|
252
|
+
- output file is auto-downloaded only when args include `-o`, `--output`, or `--output=...`
|
|
128
253
|
|
|
129
254
|
## Output And Sync Rules
|
|
130
255
|
|
|
131
256
|
- Media URLs from generation are synced to TOS when available.
|
|
132
257
|
- `--output` saves files to an absolute path resolved from current working directory.
|
|
133
258
|
- Missing parent directories for `--output` are created automatically.
|
|
259
|
+
- File type constraints:
|
|
260
|
+
- image output uses `.png`
|
|
261
|
+
- video output uses `.mp4`
|
|
262
|
+
- audio output (`music`/`tts`) uses `.mp3`
|
|
263
|
+
- If user does not explicitly provide output file name, agent must generate one in current directory:
|
|
264
|
+
- use 3-digit incremental prefix to avoid collisions, like `001_...`, `002_...`
|
|
265
|
+
- keep file name meaningful by task content, e.g. `001_city-night-drive.mp4`, `002_lofi-beat.mp3`
|
|
266
|
+
- ffmpeg and pandoc outputs follow the same naming rule:
|
|
267
|
+
- if output path is not explicitly specified by user, agent should generate a meaningful file name with `NNN_` prefix and correct extension
|
|
268
|
+
- for pandoc, keep extension aligned with conversion target format
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: edit-video
|
|
3
|
+
description: Use this skill when the user wants to edit existing videos, replace visual elements, preserve camera language, or stitch multiple clips. Execute with zerocut-cli commands only.
|
|
4
|
+
homepage: "https://github.com/liubei-ai/zerocut-cli"
|
|
5
|
+
source: "https://github.com/liubei-ai/zerocut-cli"
|
|
6
|
+
requires_binaries:
|
|
7
|
+
- "zerocut-cli"
|
|
8
|
+
- "npx"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Edit Video
|
|
12
|
+
|
|
13
|
+
## Runtime Requirements
|
|
14
|
+
|
|
15
|
+
- Use CLI commands only.
|
|
16
|
+
- Do not use MCP tool names in instructions.
|
|
17
|
+
- Ensure CLI is available:
|
|
18
|
+
- `pnpm dlx zerocut-cli help`
|
|
19
|
+
- `pnpm add -g zerocut-cli && zerocut-cli help`
|
|
20
|
+
- `npx zerocut-cli help`
|
|
21
|
+
|
|
22
|
+
## Required Pre-Check
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx zerocut-cli config list
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If `apiKey` is missing, stop and request OTT token:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx zerocut-cli config --ott <token> --region <cn|us>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Video Edit Defaults
|
|
35
|
+
|
|
36
|
+
- Default model is `seedance-2.0` unless user explicitly specifies another legal video model.
|
|
37
|
+
- Unless user explicitly specifies, keep original visual specs by not forcing `--aspectRatio` and `--resolution`.
|
|
38
|
+
- Keep user-requested camera language and motion intent.
|
|
39
|
+
|
|
40
|
+
## Legal Video Parameters
|
|
41
|
+
|
|
42
|
+
Only use legal `video` command options:
|
|
43
|
+
|
|
44
|
+
- `--prompt <prompt>` required
|
|
45
|
+
- `--duration <seconds>`
|
|
46
|
+
- `--model <model>`
|
|
47
|
+
- `--sourceVideo <video>`
|
|
48
|
+
- `--seed <seed>`
|
|
49
|
+
- `--firstFrame <image>`
|
|
50
|
+
- `--lastFrame <image>`
|
|
51
|
+
- `--storyboard <image>`
|
|
52
|
+
- `--persons <persons>`
|
|
53
|
+
- `--refs <assets>`
|
|
54
|
+
- `--resolution <resolution>`
|
|
55
|
+
- `--aspectRatio <ratio>`
|
|
56
|
+
- `--withAudio`
|
|
57
|
+
- `--withBGM <withBGM>`
|
|
58
|
+
- `--optimizeCameraMotion`
|
|
59
|
+
- `--output <file>`
|
|
60
|
+
|
|
61
|
+
## Replace Elements In Existing Video
|
|
62
|
+
|
|
63
|
+
When user asks to replace objects/subjects in an existing clip, pass source video and references to `video` command:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx zerocut-cli video \
|
|
67
|
+
--prompt "Replace the perfume gift-box product with the cream from reference image, keep original camera movement." \
|
|
68
|
+
--model seedance-2.0 \
|
|
69
|
+
--sourceVideo input.mp4 \
|
|
70
|
+
--refs product_ref.png \
|
|
71
|
+
--withAudio \
|
|
72
|
+
--withBGM true \
|
|
73
|
+
--output edited.mp4
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Character-Aware Editing
|
|
77
|
+
|
|
78
|
+
If user provides character photos, pass them with `--persons` so they map to `type=person`:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx zerocut-cli video \
|
|
82
|
+
--prompt "Keep scene pacing, replace actor with provided character while preserving performance rhythm." \
|
|
83
|
+
--model seedance-2.0 \
|
|
84
|
+
--sourceVideo input.mp4 \
|
|
85
|
+
--persons actor_front.png,actor_side.png \
|
|
86
|
+
--withAudio \
|
|
87
|
+
--output edited_person.mp4
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Stitch Multiple Videos
|
|
91
|
+
|
|
92
|
+
Use ffmpeg command path for deterministic stitching.
|
|
93
|
+
|
|
94
|
+
Create concat list:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
printf "file 'clip1.mp4'\nfile 'clip2.mp4'\nfile 'clip3.mp4'\n" > concat.txt
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Concatenate:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx zerocut-cli ffmpeg --args -f concat -safe 0 -i concat.txt -c copy merged.mp4 --resources concat.txt clip1.mp4 clip2.mp4 clip3.mp4
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Hard Rules
|
|
107
|
+
|
|
108
|
+
- Never use non-CLI tool calls in this skill.
|
|
109
|
+
- Do not use unsupported video parameters.
|
|
110
|
+
- Keep edits faithful to user instructions and preserve continuity.
|
|
111
|
+
- If a command returns `Not enough credits`, stop immediately and ask user to recharge before continuing.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: one-click-video
|
|
3
|
+
description: Use this skill when the user wants to produce a complete short video from a topic with fast CLI-driven workflow: scene planning, storyboard creation, scene video generation, optional background music, and final ffmpeg composition.
|
|
4
|
+
homepage: "https://github.com/liubei-ai/zerocut-cli"
|
|
5
|
+
source: "https://github.com/liubei-ai/zerocut-cli"
|
|
6
|
+
requires_binaries:
|
|
7
|
+
- "zerocut-cli"
|
|
8
|
+
- "npx"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# One-Click Video
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Create a deliverable final video by orchestrating `zerocut-cli` commands only.
|
|
16
|
+
|
|
17
|
+
## Runtime Requirements
|
|
18
|
+
|
|
19
|
+
- Use CLI commands only, never MCP tool names.
|
|
20
|
+
- Ensure `zerocut-cli` is available:
|
|
21
|
+
- `pnpm dlx zerocut-cli help`
|
|
22
|
+
- `pnpm add -g zerocut-cli && zerocut-cli help`
|
|
23
|
+
- `npx zerocut-cli help`
|
|
24
|
+
|
|
25
|
+
## Required Pre-Check
|
|
26
|
+
|
|
27
|
+
Run config check first:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx zerocut-cli config list
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If `apiKey` is missing, stop and request user OTT token:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx zerocut-cli config --ott <token> --region <cn|us>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Video Parameter Contract
|
|
40
|
+
|
|
41
|
+
When generating scene videos, only use legal `video` command parameters:
|
|
42
|
+
|
|
43
|
+
- `--prompt <prompt>` required
|
|
44
|
+
- `--duration <seconds>`
|
|
45
|
+
- `--model <model>`
|
|
46
|
+
- `--sourceVideo <video>`
|
|
47
|
+
- `--seed <seed>`
|
|
48
|
+
- `--firstFrame <image>`
|
|
49
|
+
- `--lastFrame <image>`
|
|
50
|
+
- `--storyboard <image>`
|
|
51
|
+
- `--persons <persons>` comma-separated image paths/URLs, mapped to `type=person`
|
|
52
|
+
- `--refs <assets>`
|
|
53
|
+
- `--resolution <resolution>`
|
|
54
|
+
- `--aspectRatio <ratio>`
|
|
55
|
+
- `--withAudio`
|
|
56
|
+
- `--withBGM <withBGM>` `true|false`, default `true`
|
|
57
|
+
- `--optimizeCameraMotion`
|
|
58
|
+
- `--output <file>`
|
|
59
|
+
|
|
60
|
+
## Output Naming Rules
|
|
61
|
+
|
|
62
|
+
- If user does not provide output path, generate meaningful names with 3-digit prefix:
|
|
63
|
+
- `001_storyboard_scene1.png`
|
|
64
|
+
- `002_scene1.mp4`
|
|
65
|
+
- `003_scene2.mp4`
|
|
66
|
+
- `004_bgm.mp3`
|
|
67
|
+
- `005_final.mp4`
|
|
68
|
+
|
|
69
|
+
## Workflow
|
|
70
|
+
|
|
71
|
+
1. Understand topic, goal, duration, platform orientation, and style.
|
|
72
|
+
2. Split into 1-5 scenes with clear narrative progression.
|
|
73
|
+
3. Create one storyboard image for each scene.
|
|
74
|
+
4. Generate one video clip for each scene using only legal video parameters.
|
|
75
|
+
5. Optionally generate one background music track with `music` command.
|
|
76
|
+
6. Compose final video with `ffmpeg` command.
|
|
77
|
+
|
|
78
|
+
## Scene Storyboard Step
|
|
79
|
+
|
|
80
|
+
Generate storyboard for each scene:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx zerocut-cli image --prompt "<scene storyboard prompt>" --model banana2 --aspectRatio 16:9 --resolution 1K --output 001_storyboard_scene1.png
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Scene Video Step
|
|
87
|
+
|
|
88
|
+
Use storyboard as `--storyboard`, optional character images via `--persons`, and optional extra references via `--refs`.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx zerocut-cli video \
|
|
92
|
+
--prompt "<scene video prompt>" \
|
|
93
|
+
--model seedance-2.0 \
|
|
94
|
+
--duration 12 \
|
|
95
|
+
--resolution 720p \
|
|
96
|
+
--aspectRatio 16:9 \
|
|
97
|
+
--storyboard 001_storyboard_scene1.png \
|
|
98
|
+
--persons actor_front.png,actor_side.png \
|
|
99
|
+
--refs prop_ref.png,env_ref.png \
|
|
100
|
+
--withAudio \
|
|
101
|
+
--withBGM true \
|
|
102
|
+
--output 002_scene1.mp4
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Background Music Step
|
|
106
|
+
|
|
107
|
+
Generate one BGM track when needed:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx zerocut-cli music --prompt "<bgm prompt>" --output 004_bgm.mp3
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Final Composition Step (ffmpeg only)
|
|
114
|
+
|
|
115
|
+
Create concat list:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
printf "file '002_scene1.mp4'\nfile '003_scene2.mp4'\n" > concat.txt
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Concatenate scene clips:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npx zerocut-cli ffmpeg --args -f concat -safe 0 -i concat.txt -c copy 005_concat.mp4 --resources concat.txt 002_scene1.mp4 003_scene2.mp4
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Mix BGM with original video audio:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx zerocut-cli ffmpeg --args -i 005_concat.mp4 -i 004_bgm.mp3 -filter_complex "[1:a]volume=0.2[bgm];[0:a][bgm]amix=inputs=2:duration=first:dropout_transition=2[aout]" -map 0:v -map "[aout]" -c:v copy -c:a aac 005_final.mp4 --resources 005_concat.mp4 004_bgm.mp3
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Hard Rules
|
|
134
|
+
|
|
135
|
+
- Do not introduce non-CLI tool calls.
|
|
136
|
+
- Do not use parameters outside the legal `video` parameter contract.
|
|
137
|
+
- Keep single scene duration within model limits.
|
|
138
|
+
- Keep visual style consistent across all scenes.
|
|
139
|
+
- Keep role identity consistent when using `--persons`.
|
|
140
|
+
- Do not generate subtitles in this workflow.
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
2
|
const path = require("node:path");
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const srcDir = path.resolve(__dirname, "../src/skill");
|
|
5
|
+
const distDir = path.resolve(__dirname, "../dist/skill");
|
|
6
6
|
|
|
7
|
-
fs.mkdirSync(
|
|
8
|
-
fs.
|
|
7
|
+
fs.mkdirSync(distDir, { recursive: true });
|
|
8
|
+
fs.cpSync(srcDir, distDir, { recursive: true });
|