zerocut-cli 0.1.1 → 0.2.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/package.json +1 -1
- package/src/commands/video.ts +57 -9
- package/src/skill/SKILL.md +42 -4
package/package.json
CHANGED
package/src/commands/video.ts
CHANGED
|
@@ -7,7 +7,27 @@ import { createProgressSpinner } from "../utils/progress";
|
|
|
7
7
|
export const name = "video";
|
|
8
8
|
export const description = "Video command: create video";
|
|
9
9
|
|
|
10
|
+
function resolveResultUrl(result: unknown): string | undefined {
|
|
11
|
+
if (!result || typeof result !== "object") {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const record = result as Record<string, unknown>;
|
|
15
|
+
if (typeof record.url === "string" && record.url.length > 0) {
|
|
16
|
+
return record.url;
|
|
17
|
+
}
|
|
18
|
+
const data = record.data;
|
|
19
|
+
if (data && typeof data === "object") {
|
|
20
|
+
const dataRecord = data as Record<string, unknown>;
|
|
21
|
+
if (typeof dataRecord.url === "string" && dataRecord.url.length > 0) {
|
|
22
|
+
return dataRecord.url;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
10
28
|
export function register(program: Command): void {
|
|
29
|
+
const avatarModels = ["zerocut-avatar-1.0", "zerocut-avatar-1.5"] as const;
|
|
30
|
+
const mvModels = ["zerocut-mv-1.0"] as const;
|
|
11
31
|
const parent = program.command("video").description("Create a new video; requires --prompt");
|
|
12
32
|
|
|
13
33
|
const allowedTypes = [
|
|
@@ -25,6 +45,8 @@ export function register(program: Command): void {
|
|
|
25
45
|
"sora2-pro",
|
|
26
46
|
"veo3.1",
|
|
27
47
|
"veo3.1-pro",
|
|
48
|
+
...avatarModels,
|
|
49
|
+
...mvModels,
|
|
28
50
|
] as const;
|
|
29
51
|
|
|
30
52
|
async function videoCreateAction(
|
|
@@ -68,10 +90,21 @@ export function register(program: Command): void {
|
|
|
68
90
|
const durationStr = typeof opts.duration === "string" ? opts.duration.trim() : undefined;
|
|
69
91
|
const sourceVideo = typeof opts.sourceVideo === "string" ? opts.sourceVideo.trim() : undefined;
|
|
70
92
|
let duration: number = 0;
|
|
93
|
+
const durationRange = ((): { min: number; max: number } => {
|
|
94
|
+
if ((avatarModels as readonly string[]).includes(model)) {
|
|
95
|
+
return { min: 5, max: 240 };
|
|
96
|
+
}
|
|
97
|
+
if ((mvModels as readonly string[]).includes(model)) {
|
|
98
|
+
return { min: 1, max: 240 };
|
|
99
|
+
}
|
|
100
|
+
return { min: 1, max: 16 };
|
|
101
|
+
})();
|
|
71
102
|
if (durationStr) {
|
|
72
103
|
const n = Number.parseInt(durationStr, 10);
|
|
73
|
-
if (!Number.isFinite(n) || n <
|
|
74
|
-
process.stderr.write(
|
|
104
|
+
if (!Number.isFinite(n) || n < durationRange.min || n > durationRange.max) {
|
|
105
|
+
process.stderr.write(
|
|
106
|
+
`Invalid value for --duration: model ${model} supports integer ${durationRange.min}-${durationRange.max}\n`
|
|
107
|
+
);
|
|
75
108
|
process.exitCode = 1;
|
|
76
109
|
return;
|
|
77
110
|
}
|
|
@@ -119,7 +152,7 @@ export function register(program: Command): void {
|
|
|
119
152
|
}
|
|
120
153
|
const res = await session.ai.generateVideo({
|
|
121
154
|
prompt,
|
|
122
|
-
model: model as
|
|
155
|
+
model: model as unknown as Parameters<typeof session.ai.generateVideo>[0]["model"],
|
|
123
156
|
duration: duration || undefined,
|
|
124
157
|
resolution: opts.resolution,
|
|
125
158
|
aspect_ratio: aspectRatio,
|
|
@@ -137,11 +170,12 @@ export function register(program: Command): void {
|
|
|
137
170
|
: undefined,
|
|
138
171
|
onProgress: createProgressSpinner("inferencing"),
|
|
139
172
|
});
|
|
173
|
+
const initialUrl = resolveResultUrl(res);
|
|
140
174
|
try {
|
|
141
|
-
if (
|
|
142
|
-
const tosUrl = await syncToTOS(
|
|
175
|
+
if (initialUrl) {
|
|
176
|
+
const tosUrl = await syncToTOS(initialUrl);
|
|
143
177
|
if (tosUrl) {
|
|
144
|
-
res.url = tosUrl;
|
|
178
|
+
(res as Record<string, unknown>).url = tosUrl;
|
|
145
179
|
}
|
|
146
180
|
}
|
|
147
181
|
} catch {}
|
|
@@ -149,7 +183,15 @@ export function register(program: Command): void {
|
|
|
149
183
|
const output = typeof opts.output === "string" ? opts.output : undefined;
|
|
150
184
|
if (output) {
|
|
151
185
|
const dir = process.cwd();
|
|
152
|
-
const url = res
|
|
186
|
+
const url = resolveResultUrl(res);
|
|
187
|
+
if (!url) {
|
|
188
|
+
process.stderr.write(
|
|
189
|
+
"Cannot save --output because no video URL was returned. Please retry later or run without --output to inspect raw response.\n"
|
|
190
|
+
);
|
|
191
|
+
process.exitCode = 1;
|
|
192
|
+
console.log(res);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
153
195
|
const response = await fetch(url);
|
|
154
196
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
155
197
|
const filePath = path.resolve(dir, output);
|
|
@@ -165,7 +207,10 @@ export function register(program: Command): void {
|
|
|
165
207
|
// default action on `zerocut video`
|
|
166
208
|
parent
|
|
167
209
|
.option("--prompt <prompt>", "Text prompt for video generation (required)")
|
|
168
|
-
.option(
|
|
210
|
+
.option(
|
|
211
|
+
"--duration <duration>",
|
|
212
|
+
"Video duration in seconds (default models: 1-16, avatar: 5-240, mv: 1-240)"
|
|
213
|
+
)
|
|
169
214
|
.option("--model <model>", `Video model: ${allowedTypes.join("|")} (default: vidu)`)
|
|
170
215
|
.option("--sourceVideo <video>", "Base video path/url for edit mode (requires --duration 3-10)")
|
|
171
216
|
.option("--seed <seed>", "Random seed")
|
|
@@ -184,7 +229,10 @@ export function register(program: Command): void {
|
|
|
184
229
|
.command("create")
|
|
185
230
|
.description("Create a new video; requires --prompt")
|
|
186
231
|
.option("--prompt <prompt>", "Text prompt for video generation (required)")
|
|
187
|
-
.option(
|
|
232
|
+
.option(
|
|
233
|
+
"--duration <duration>",
|
|
234
|
+
"Video duration in seconds (default models: 1-16, avatar: 5-240, mv: 1-240)"
|
|
235
|
+
)
|
|
188
236
|
.option("--model <model>", `Video model: ${allowedTypes.join("|")} (default: vidu)`)
|
|
189
237
|
.option("--sourceVideo <video>", "Base video path/url for edit mode (requires --duration 3-10)")
|
|
190
238
|
.option("--seed <seed>", "Random seed")
|
package/src/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
|
|
@@ -26,6 +31,32 @@ Invoke this skill when the user asks to:
|
|
|
26
31
|
- sync local/remote resources into sandbox
|
|
27
32
|
- save generated results to local output files
|
|
28
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
|
+
|
|
29
60
|
## Required Pre-Check
|
|
30
61
|
|
|
31
62
|
Before every task, the agent must check configuration first:
|
|
@@ -73,7 +104,9 @@ Validation rules:
|
|
|
73
104
|
- `--prompt` must be non-empty
|
|
74
105
|
- `--model` allowed: `seedream|seedream-pro|seedream-5l|banana|banana2|banana-pro|wan`
|
|
75
106
|
- `--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`
|
|
107
|
+
- unless user specifies aspect ratio, default to `16:9`
|
|
76
108
|
- `--resolution` allowed: `1K|2K|4K`
|
|
109
|
+
- unless user specifies resolution, default to `1K`
|
|
77
110
|
|
|
78
111
|
### video
|
|
79
112
|
|
|
@@ -89,7 +122,7 @@ Options:
|
|
|
89
122
|
|
|
90
123
|
- `--prompt <prompt>` required
|
|
91
124
|
- `--model <model>`
|
|
92
|
-
- `--duration <seconds>` integer
|
|
125
|
+
- `--duration <seconds>` model-dependent integer
|
|
93
126
|
- `--sourceVideo <video>` base video for edit mode
|
|
94
127
|
- `--seed <seed>`
|
|
95
128
|
- `--firstFrame <image>`
|
|
@@ -104,13 +137,18 @@ Options:
|
|
|
104
137
|
Validation rules:
|
|
105
138
|
|
|
106
139
|
- `--prompt` must be non-empty
|
|
107
|
-
- `--model` allowed: `zerocut3.0|seedance-1.5-pro|vidu|vidu-pro|viduq3|viduq3-turbo|kling|kling-v3|wan|wan-flash|sora2|sora2-pro|veo3.1|veo3.1-pro`
|
|
108
|
-
- `--duration` must
|
|
140
|
+
- `--model` allowed: `zerocut3.0|seedance-1.5-pro|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`
|
|
141
|
+
- `--duration` must follow model range:
|
|
142
|
+
- default models: `1-16`
|
|
143
|
+
- `zerocut-avatar-1.0` / `zerocut-avatar-1.5`: `5-240`
|
|
144
|
+
- `zerocut-mv-1.0`: `1-240`
|
|
109
145
|
- `--aspectRatio` allowed: `9:16|16:9|1:1`
|
|
146
|
+
- unless user specifies aspect ratio, default to `16:9`
|
|
147
|
+
- unless user specifies resolution, default to `720p`
|
|
110
148
|
|
|
111
149
|
Long video guidance:
|
|
112
150
|
|
|
113
|
-
- if required duration is over 16s, split into multiple
|
|
151
|
+
- for default models, if required duration is over 16s, split into multiple generations (each 1-16s)
|
|
114
152
|
- then concatenate clips with ffmpeg
|
|
115
153
|
- example:
|
|
116
154
|
|