@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 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.0",
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`**. Do not start Stage 1 without the first two.
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, edit them into a locked cut (picture lock),
357
- `wji asset upload` it and bind `wji.assets.edit`. `prompt score E0N [--fps 24]` prints the planned
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), mix the sections under the edit at their offsets, upload and bind `wji.assets.mix`.
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.)