@starreel/mcp 0.1.14 → 0.1.16

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/SKILL.md CHANGED
@@ -2,7 +2,7 @@
2
2
  name: starreel-drama-production
3
3
  description: >-
4
4
  Operating skill for any AI agent driving the StarReel short-drama production
5
- pipeline (script → rewrite → extract → portraits → storyboards → frames →
5
+ pipeline (script → rewrite → extract → portraits + sheets → storyboards → frames →
6
6
  video → voiceover → final cut) over MCP or REST. Covers the ordered workflow,
7
7
  the ten operating disciplines (prepaid billing, quote-before-spend, retryable
8
8
  failure handling, content compliance, tenancy), and a failure playbook.
@@ -28,7 +28,7 @@ One episode, the **full** pipeline — nothing skipped:
28
28
 
29
29
  ```
30
30
  create_drama → set_script(raw) → rewrite_script(AI draft, user may edit)
31
- → extract_assets(cast/scenes/props) → generate_character_portraits(identity anchor)
31
+ → extract_assets(cast/scenes/props) → generate_portraits_and_sheets(portraits + sheets = the shot consistency anchor)
32
32
  → storyboards → frames → videos → generate_tts(voiceover) → compose_episode → final cut (.mp4 link)
33
33
  ```
34
34
 
@@ -90,10 +90,13 @@ content that will be rejected.
90
90
  somewhere else.
91
91
 
92
92
  6. **Follow the pipeline order — do not skip.** `set_script` → `rewrite_script`
93
- → `extract_assets` → portraits → storyboards → frames → videos. Always
93
+ → `extract_assets` → portraits **+ sheets** → storyboards → frames → videos. Always
94
94
  generate frames **before** videos; skipping frames degrades video into
95
- anchorless t2v — wasted money. Lock character portraits before video for
96
- identity consistency. `generate_frames` makes **first frames only** — you do
95
+ anchorless t2v — wasted money. Lock character portraits **and sheets** before
96
+ video: a portrait is one image, but **character sheets (multi-view turnarounds)
97
+ are the shot consistency anchor every frame references** — portraits alone
98
+ leave characters drifting across angle / lighting / wardrobe.
99
+ `generate_portraits_and_sheets` does both (portraits first, then sheets). `generate_frames` makes **first frames only** — you do
97
100
  NOT generate first + last together. A **last frame** is optional and never
98
101
  auto-made; upload it via `upload_shot_frame` (`frame_type=last_frame`) only to
99
102
  pin a shot's ending (a big camera move or reveal). `generate_videos` needs at
@@ -23,7 +23,7 @@ const CONFIRM_HINT = '⚠️ 批量报价确认流程:先调对应的 quote_*
23
23
  // → compose_episode → get_final_cut / get_export
24
24
  // 项目设定随时可 update_project_settings;剧目级资产(色彩脚本/动作模板/世界观图/美术圣经)可选增强。
25
25
  const WORKFLOW_HINT = '照完整工作流按序推进,别跳步:set_script(原始)→ rewrite_script(AI改写)→ extract_assets →' +
26
- ' generate_character_portraits → storyboards → frames → videos → compose。用 get_pipeline_status 查进度。';
26
+ ' generate_portraits_and_sheets(定妆图+设定图·镜头一致性根锚,别只出定妆图)→ storyboards → frames → videos → compose。用 get_pipeline_status 查进度。';
27
27
  const ETHNICITY_CODES = [
28
28
  'east_asian', 'southeast_asian', 'south_asian', 'central_asian',
29
29
  'caucasian', 'middle_eastern', 'african', 'latin_american',
@@ -100,7 +100,16 @@ export function registerProduceTools(server, client) {
100
100
  // ---------- 角色定妆图(一致性锚) ----------
101
101
  server.tool('quote_character_portraits', '报价:给缺定妆图的角色批量出定妆图要多少点。返回 portraits_to_generate、estimated_points、quote_id。零扣费。' +
102
102
  '定妆图是身份一致性的锚(缺它角色会漂移),强烈建议出视频前先出。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/portraits/quote`)));
103
- server.tool('generate_character_portraits', '确认后批量出角色定妆图:后台异步。用 get_pipeline_status/get_storyboards 查进度。' + CONFIRM_HINT, { episode_id: z.number().int().positive(), quote_id: z.string().describe('来自 quote_character_portraits') }, async ({ episode_id, quote_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/portraits/generate`, { quote_id })));
103
+ server.tool('generate_character_portraits', '确认后批量出角色定妆图(★仅定妆图):后台异步。定妆图只是单张身份锚——镜头一致性(尤其服装)还需**设定图**,' +
104
+ '出完定妆图强烈建议 generate_character_sheets;或直接用 generate_portraits_and_sheets 一步到位。' +
105
+ '用 get_pipeline_status/get_storyboards 查进度。' + CONFIRM_HINT, { episode_id: z.number().int().positive(), quote_id: z.string().describe('来自 quote_character_portraits') }, async ({ episode_id, quote_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/portraits/generate`, { quote_id })));
106
+ // ---------- 设定图(镜头一致性根锚·批量 / 一键) ----------
107
+ server.tool('generate_character_sheets', '★批量给全剧角色出设定图(多视角 turnaround)。设定图是镜头帧/视频引用的**一致性根锚**——只出定妆图不出设定图,' +
108
+ '镜头人物换角度/换光/服装会漂移(2.5 更直接用设定图切片做骨相锚)。只对缺设定图的角色出(不重复扣费)。' +
109
+ '前置:角色须已有定妆图(缺则拦并提示先出定妆图)。图片步,按用量后付不欠费。轮询 get_characters 看 sheet_url 就绪。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/character-sheets`)));
110
+ server.tool('generate_portraits_and_sheets', '★一键:定妆图 + 设定图(推荐,产线标配)。设定图强依赖定妆图,故智能两阶段——有角色缺定妆图就先派定妆图并提示,' +
111
+ '定妆图齐了再调一次即批量出设定图。避免只出定妆图导致镜头漂移。图片步,按用量后付不欠费。' +
112
+ '轮询 get_characters 看 image/sheet_url 就绪;每调一次推进一步。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/portraits-and-sheets`)));
104
113
  // ---------- 拆镜(storyboards) ----------
105
114
  server.tool('quote_storyboards', '报价:把某一集的剧本拆成分镜(storyboards)要多少点。返回 estimated_points 与 quote_id。零扣费。' +
106
115
  '拿到后把点数告诉用户征求同意,再用 quote_id 调 generate_storyboards。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/storyboards/quote`)));
@@ -191,9 +200,18 @@ export function registerProduceTools(server, client) {
191
200
  return jsonResult({ image_url: url });
192
201
  });
193
202
  server.tool('set_character_portrait', '用客户自有图片作为角色定妆图(身份锚,优先级高于 AI 生成;之后 AI 重生默认不覆盖)。' +
194
- '自动上传本地图 + 登记。免费。', { character_id: z.number().int().positive(), file_path: z.string().describe('本地定妆图路径') }, async ({ character_id, file_path }) => {
195
- const image_url = await client.uploadLocalFile(file_path, 'image');
196
- return jsonResult(await client.producePost(`/characters/${character_id}/portrait`, { image_url }));
203
+ '换图会自动失效并重建派生资产(三视图设定图/发型·身材参考)、重建人脸锁。' +
204
+ '传本地文件(file_path,自动上传 COS)或已托管的图片 URL(image_url),二选一。免费。', {
205
+ character_id: z.number().int().positive(),
206
+ file_path: z.string().optional().describe('本地定妆图路径(与 image_url 二选一;自动上传 COS)'),
207
+ image_url: z.string().optional().describe('已上传的定妆图 URL(与 file_path 二选一)'),
208
+ }, async ({ character_id, file_path, image_url }) => {
209
+ const url = image_url && image_url.trim()
210
+ ? image_url.trim()
211
+ : (file_path ? await client.uploadLocalFile(file_path, 'image') : '');
212
+ if (!url)
213
+ throw new Error('file_path 或 image_url 至少提供一个');
214
+ return jsonResult(await client.producePost(`/characters/${character_id}/portrait`, { image_url: url }));
197
215
  });
198
216
  server.tool('upload_shot_frame', '用客户自有图片作为某镜的首帧(first_frame)或尾帧(last_frame)。尾帧可选、系统不自动生成——仅在想固定某镜结尾画面(大运镜/揭示镜)时传;常规只需首帧。会把该镜已有视频标为过期待重生。自动上传+登记。免费。', {
199
217
  storyboard_id: z.number().int().positive(),
@@ -283,7 +301,8 @@ export function registerProduceTools(server, client) {
283
301
  mood: z.string().optional(),
284
302
  }, async ({ scene_id, ...fields }) => jsonResult(await client.producePut(`/scenes/${scene_id}`, fields)));
285
303
  server.tool('delete_scene', '删除一个场景。免费。', { scene_id: z.number().int().positive() }, async ({ scene_id }) => jsonResult(await client.produceDelete(`/scenes/${scene_id}`)));
286
- server.tool('generate_character_sheet', '给角色出三视图设定图(比定妆图更完整的身份锚,一致性更稳)。图片步,按用量后付不欠费。', { character_id: z.number().int().positive(), episode_id: z.number().int().positive().optional() }, async ({ character_id, episode_id }) => jsonResult(await client.producePost(`/characters/${character_id}/sheet`, episode_id ? { episode_id } : {})));
304
+ server.tool('generate_character_sheet', '给**单个**角色出三视图设定图(镜头一致性根锚,所有镜头帧都会引用;比定妆图更完整)。整集批量用 generate_character_sheets。' +
305
+ '前置:该角色已有定妆图。图片步,按用量后付不欠费。', { character_id: z.number().int().positive(), episode_id: z.number().int().positive().optional() }, async ({ character_id, episode_id }) => jsonResult(await client.producePost(`/characters/${character_id}/sheet`, episode_id ? { episode_id } : {})));
287
306
  server.tool('generate_prop_sheet', '给道具 AI 出设定图。图片步,按用量后付不欠费。', { prop_id: z.number().int().positive() }, async ({ prop_id }) => jsonResult(await client.producePost(`/props/${prop_id}/generate-sheet`)));
288
307
  // ========== P2 · 连续性 / 场景组 / 多画幅 ==========
289
308
  server.tool('chain_frames', '整集首尾帧接力链:让每镜首帧承接上镜尾帧,镜间画面连续(比各镜独立出帧更顺)。按用量后付。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/chain-frames`)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starreel/mcp",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "mcpName": "ai.starreel/starreel",
5
5
  "description": "StarReel MCP server — drive the AI short-drama production pipeline (script → storyboards → frames → video → final cut) from Claude, Cursor, or any MCP client",
6
6
  "license": "MIT",