@wji.ai/cli 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +6 -0
- package/package.json +8 -9
- package/skill/short-drama/SKILL.md +43 -5
- package/skill/short-drama/dashboard.html +863 -0
- package/skill/short-drama/examples/night-shift/episodes/E01.json +1 -1
- package/skill/short-drama/reference/canvas-recipes.md +1 -1
- package/skill/short-drama/reference/edit-tools.md +65 -0
- package/skill/short-drama/reference/mix-over-video.md +5 -1
- package/skill/short-drama/reference/operations-cli.md +3 -2
- package/skill/short-drama/reference/schema.md +14 -10
- package/skill/short-drama/reference/stage-storyboard.md +3 -2
- package/skill/short-drama/scripts/selftest.mjs +333 -2
- package/skill/short-drama/scripts/short-drama.mjs +416 -64
package/dist/index.js
CHANGED
|
@@ -292,6 +292,10 @@ var MIME_TYPES = {
|
|
|
292
292
|
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
293
293
|
};
|
|
294
294
|
var mimeTypeOf = (filename) => MIME_TYPES[filename.split(".").pop()?.toLowerCase() || ""] || "application/octet-stream";
|
|
295
|
+
function clientVersion(version, env = process.env) {
|
|
296
|
+
const agent = (env.WJI_AGENT || "").trim() || (env.CLAUDECODE === "1" ? "claude-code" : "");
|
|
297
|
+
return agent ? `${version}; agent=${agent.replace(/[^\w.@-]/g, "_").slice(0, 40)}` : version;
|
|
298
|
+
}
|
|
295
299
|
var ApiError = class extends Error {
|
|
296
300
|
constructor(message, status, path, body) {
|
|
297
301
|
super(message);
|
|
@@ -346,6 +350,8 @@ var ApiClient = class {
|
|
|
346
350
|
headers(opts) {
|
|
347
351
|
const headers = {
|
|
348
352
|
Accept: "application/json",
|
|
353
|
+
"X-Client": this.spec.client ?? "cli",
|
|
354
|
+
"X-Client-Version": clientVersion(this.spec.version),
|
|
349
355
|
"X-Locale": this.globals.locale || readEnv(this.spec, "LOCALE") || this.profile.locale || "cht"
|
|
350
356
|
};
|
|
351
357
|
if (!opts.anonymous) headers.Authorization = `Bearer ${this.requireToken()}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wji.ai/cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Command line interface for the WJI AI platform",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "WJI AI",
|
|
@@ -30,17 +30,16 @@
|
|
|
30
30
|
"engines": {
|
|
31
31
|
"node": ">=20"
|
|
32
32
|
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "tsup && chmod +x dist/index.js",
|
|
35
|
-
"dev": "tsup --watch",
|
|
36
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
|
-
"start": "node dist/index.js",
|
|
38
|
-
"prepublishOnly": "pnpm run build"
|
|
39
|
-
},
|
|
40
33
|
"dependencies": {
|
|
41
34
|
"commander": "^12.1.0"
|
|
42
35
|
},
|
|
43
36
|
"publishConfig": {
|
|
44
37
|
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup && chmod +x dist/index.js",
|
|
41
|
+
"dev": "tsup --watch",
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
43
|
+
"start": "node dist/index.js"
|
|
45
44
|
}
|
|
46
|
-
}
|
|
45
|
+
}
|
|
@@ -59,7 +59,11 @@ ending), change the guideline first, then the episodes.
|
|
|
59
59
|
古装 / 年代 / 英文美式 / 英文英式 — it decides how the lines are written and the accent the video
|
|
60
60
|
model speaks), ratio (default 9:16 for short, 16:9 for medium and movie). Offer the defaults you will use unless
|
|
61
61
|
told otherwise: `video: h3` (MiniMax H3 ref), `style: realistic`, **`references: sheets`** (no
|
|
62
|
-
storyboard images) and **`videoDuration: auto`**.
|
|
62
|
+
storyboard images) and **`videoDuration: auto`**. That message is a gate. If the user left
|
|
63
|
+
something out — no video model, no episode count, no genre, no 语体 — ask for it, or name the
|
|
64
|
+
default you would use, in the same message. Do not `init`, and do not start Stage 1, until they
|
|
65
|
+
confirm the set. A default is a proposal, not a decision. A resumed `project.json` that already
|
|
66
|
+
has these params is not asked again unless a required field is empty.
|
|
63
67
|
|
|
64
68
|
**The video mode decides how the plot is cut up.** A segment is one video generation, so its
|
|
65
69
|
length is whatever the provider accepts — and that differs by a factor of two:
|
|
@@ -132,7 +136,8 @@ ending), change the guideline first, then the episodes.
|
|
|
132
136
|
`params.violence` is `blood` (default) or `implied`.
|
|
133
137
|
4. **Locate or create the project directory** (the user's choice, else next to the source):
|
|
134
138
|
```bash
|
|
135
|
-
node {baseDir}/scripts/short-drama.mjs init <dir> --title "<title>" --episodes N --minutes M --genre "<genre>" --register 台湾国语 [--adapt 抽核] [--ratio 9:16] [--video h3|seedance|seedance2|seedance2fast|wan] [--resolution 480P|…] [--accent "台湾口音国语"] [--style photoreal|realistic|ghibli] [--references sheets|keyframes] [--duration auto|fixed] [--look "<lens phrase>"] [--cinematography low-key|sweet-romance|period-nostalgia|costume-idol|costume-dark|scifi-hard|scifi-soft|none] [--action gun-fu|hk-kungfu|wuxia-fantasy|historical-realist|bullet-time|superhero|street-brawl|car-chase|none] [--violence blood|implied] [--grammar drama|action|faceslap|comedy] [--comedy slapstick|deadpan|romcom|none] [--composition standard|art-first] [--story revenge,sweet,…] [--market mainland|overseas] [--format short|medium|movie] [--lang zh]
|
|
139
|
+
node {baseDir}/scripts/short-drama.mjs init <dir> --title "<title>" --episodes N --minutes M --genre "<genre>" --register 台湾国语 [--adapt 抽核] [--ratio 9:16] [--video h3|seedance|seedance2|seedance2fast|wan] [--resolution 480P|…] [--accent "台湾口音国语"] [--style photoreal|realistic|ghibli] [--references sheets|keyframes] [--duration auto|fixed] [--look "<lens phrase>"] [--cinematography low-key|sweet-romance|period-nostalgia|costume-idol|costume-dark|scifi-hard|scifi-soft|none] [--action gun-fu|hk-kungfu|wuxia-fantasy|historical-realist|bullet-time|superhero|street-brawl|car-chase|none] [--violence blood|implied] [--grammar drama|action|faceslap|comedy] [--comedy slapstick|deadpan|romcom|none] [--composition standard|art-first] [--story revenge,sweet,…] [--market mainland|overseas] [--format short|medium|movie] [--lang zh] [--image-lang en|zh]
|
|
140
|
+
# --image-lang zh: character / scene / prop image prompts in Chinese (the default is English)
|
|
136
141
|
# params.camera (body / lens / aperture) is edited in project.json
|
|
137
142
|
```
|
|
138
143
|
An existing `project.json` means a resumed run: `validate` and `manifest` tell you where it stands.
|
|
@@ -159,6 +164,36 @@ write JSON → validate --stage <stage> → fix until green → render → sync
|
|
|
159
164
|
approving a sheet or moving to the next segment. The reference-repo lesson: one wrong sheet
|
|
160
165
|
corrupts every shot after it.
|
|
161
166
|
|
|
167
|
+
## Production dashboard
|
|
168
|
+
|
|
169
|
+
The dashboard is one static file, `{baseDir}/dashboard.html`. It does not bake `project.json`,
|
|
170
|
+
and it does not download images. **Every project keeps its own copy in the same folder as
|
|
171
|
+
`project.json`.** `init` copies it. On any later session, if that file is missing, copy it
|
|
172
|
+
again — do not overwrite a copy that is already there:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
node {baseDir}/scripts/short-drama.mjs dashboard {project}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
That command checks `{project}/dashboard.html`. Missing → copy. Already there → leave it
|
|
179
|
+
(`--force` replaces it with the skill's current page). Open the copy through a local static
|
|
180
|
+
server so it can `fetch` `./project.json` and `episodes/E01.json`. Refreshing re-reads the JSON.
|
|
181
|
+
|
|
182
|
+
Pictures and videos stay as asset ids on `wji.assets.sheet|headshot|keyframe|poster|video`
|
|
183
|
+
(and `lighting:` / `state:` keys). The page asks `POST /assets/check-status` for those ids
|
|
184
|
+
and uses the returned `url` — the same file address as `GET /assets/list/:id` (`wji asset get`).
|
|
185
|
+
Paste the bearer from `wji auth token` once; the browser then loads the CDN url. Do not run
|
|
186
|
+
`wji asset download` for the dashboard. An `https` url already stored on `image.url` /
|
|
187
|
+
`video.url` is used as-is. A relative file that is already in the chosen folder is shown from
|
|
188
|
+
that file. Anything else stays a placeholder. Video urls render as a player.
|
|
189
|
+
|
|
190
|
+
The left nav scrolls the page itself (the section links call `scrollTo` on the content column).
|
|
191
|
+
Bound WJI ids become links to `https://app.wji.ai/app/workspace/<workspaceId>`:
|
|
192
|
+
a canvas is `?app=InfiniteCanvas&canvas=<id>` (and `&node=<id>` when a node is bound);
|
|
193
|
+
a dataset is `?app=Dataset&dataset=<id>`.
|
|
194
|
+
|
|
195
|
+
Do not paste the HTML into a dataset or upload it as an asset.
|
|
196
|
+
|
|
162
197
|
## Stage 1 — Outline
|
|
163
198
|
|
|
164
199
|
Read `{baseDir}/reference/stage-outline.md`.
|
|
@@ -353,8 +388,10 @@ must be connected: pictures, then clips, then voices.
|
|
|
353
388
|
spotting notes for the score.
|
|
354
389
|
6. After each clip: `fs set <shot dataset> [--add-images <keyframes…>] --set primaryVideo=<clip>`;
|
|
355
390
|
bind asset ids.
|
|
356
|
-
7. **Score the edited episode.** When every clip is in,
|
|
357
|
-
`
|
|
391
|
+
7. **Score the edited episode.** When every clip is in, cut them to picture lock as in
|
|
392
|
+
`reference/edit-tools.md`: FilmCraft (`filmcraft-cli`), timeline kept at `edits/E0N.fcproj`,
|
|
393
|
+
or ffmpeg when that CLI is not installed. `wji asset upload` the export and bind
|
|
394
|
+
`wji.assets.edit`. `prompt score E0N [--fps 24]` prints the planned
|
|
358
395
|
spotting sheet — SMPTE rows for the scene beds, every line (where the music ducks), each
|
|
359
396
|
segment's music cues at episode time, the `post` sound design, the sfx already in the clips, the
|
|
360
397
|
hook / turns / 爽点 / cliff (起承转合) and the ≤120 s Seed Audio sections. Conform it to the edit's
|
|
@@ -362,7 +399,8 @@ must be connected: pictures, then clips, then voices.
|
|
|
362
399
|
`reference/bgm-sfx.md`, loudness and terms in `reference/film-mixing-guideline.md`): BGM, BGE /
|
|
363
400
|
ambience and sound design only — never what the clips already carry. One `canvas add audio -n
|
|
364
401
|
"E0N score K" -m seed-audio-1.0 --prompt-file …` per section (~0.15 credits a minute — quote
|
|
365
|
-
first),
|
|
402
|
+
first), lay the sections under the edit with SoundCraft, or ffmpeg when `soundcraft-cli` is
|
|
403
|
+
missing (`reference/edit-tools.md`), upload and bind `wji.assets.mix`.
|
|
366
404
|
`manifest --ep N` must come back clean before you call the episode done. (`audioTrack: bed` /
|
|
367
405
|
`full` instead make a Seed Audio node per segment from `prompt audio E0N-01` and put the music in
|
|
368
406
|
the clip.)
|