cerevox 2.29.0 → 2.30.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.
Files changed (26) hide show
  1. package/dist/core/ai.d.ts +5 -0
  2. package/dist/core/ai.d.ts.map +1 -1
  3. package/dist/core/ai.js +232 -13
  4. package/dist/core/ai.js.map +1 -1
  5. package/dist/mcp/servers/prompts/knowledge/best-practices.md +0 -0
  6. package/dist/mcp/servers/prompts/knowledge/troubleshooting.md +0 -0
  7. package/dist/mcp/servers/prompts/rules/anime-series.md +2 -2
  8. package/dist/mcp/servers/prompts/rules/creative-ad.md +2 -2
  9. package/dist/mcp/servers/prompts/rules/freeform.md +45 -45
  10. package/dist/mcp/servers/prompts/rules/general-video.md +2 -2
  11. package/dist/mcp/servers/prompts/rules/music-video.md +1 -1
  12. package/dist/mcp/servers/prompts/rules/professional.md +1 -1
  13. package/dist/mcp/servers/prompts/rules/stage-play.md +1 -1
  14. package/dist/mcp/servers/prompts/rules/story-telling.md +3 -3
  15. package/dist/mcp/servers/prompts/skills/storyboard/art-style-references.md +35 -0
  16. package/dist/mcp/servers/prompts/skills/storyboard/storyboard-optimization-skill.md +282 -0
  17. package/dist/mcp/servers/prompts/skills/video/camera-movements.md +29 -0
  18. package/dist/mcp/servers/prompts/skills/video/continuity-techniques.md +18 -0
  19. package/dist/mcp/servers/prompts/skills/video/scene-composition-reference.md +109 -0
  20. package/dist/mcp/servers/prompts/skills/video/scene-composition-skill.md +79 -0
  21. package/dist/mcp/servers/prompts/skills/workflows/general-video.md +187 -0
  22. package/dist/mcp/servers/prompts/skills/workflows/music-video.md +169 -0
  23. package/dist/mcp/servers/zerocut.d.ts.map +1 -1
  24. package/dist/mcp/servers/zerocut.js +66 -211
  25. package/dist/mcp/servers/zerocut.js.map +1 -1
  26. package/package.json +1 -1
@@ -490,6 +490,47 @@ server.registerTool('retrieve-rules-context', {
490
490
  await (0, promises_1.mkdir)((0, node_path_1.dirname)(projectRulesFile), { recursive: true });
491
491
  await (0, promises_1.writeFile)(projectRulesFile, promptContent);
492
492
  }
493
+ // 如果 purpose 为 freeform,复制 skills 和 knowledge 目录
494
+ if (purpose === 'freeform') {
495
+ // 递归复制目录的通用函数
496
+ const copyDirectory = async (src, dest) => {
497
+ const entries = await (0, promises_1.readdir)(src, { withFileTypes: true });
498
+ for (const entry of entries) {
499
+ const srcPath = (0, node_path_1.resolve)(src, entry.name);
500
+ const destPath = (0, node_path_1.resolve)(dest, entry.name);
501
+ if (entry.isDirectory()) {
502
+ await (0, promises_1.mkdir)(destPath, { recursive: true });
503
+ await copyDirectory(srcPath, destPath);
504
+ }
505
+ else {
506
+ const content = await (0, promises_1.readFile)(srcPath, 'utf-8');
507
+ await (0, promises_1.writeFile)(destPath, content);
508
+ }
509
+ }
510
+ };
511
+ // 复制 skills 目录
512
+ const sourceSkillsDir = (0, node_path_1.resolve)(__dirname, './prompts/skills');
513
+ const targetSkillsDir = (0, node_path_1.resolve)(projectLocalDir, '.trae', 'skills');
514
+ try {
515
+ await (0, promises_1.mkdir)(targetSkillsDir, { recursive: true });
516
+ await copyDirectory(sourceSkillsDir, targetSkillsDir);
517
+ console.log(`Skills directory copied to ${targetSkillsDir}`);
518
+ }
519
+ catch (skillsError) {
520
+ console.warn(`Failed to copy skills directory: ${skillsError}`);
521
+ }
522
+ // 复制 knowledge 目录
523
+ const sourceKnowledgeDir = (0, node_path_1.resolve)(__dirname, './prompts/knowledge');
524
+ const targetKnowledgeDir = (0, node_path_1.resolve)(projectLocalDir, '.trae', 'knowledge');
525
+ try {
526
+ await (0, promises_1.mkdir)(targetKnowledgeDir, { recursive: true });
527
+ await copyDirectory(sourceKnowledgeDir, targetKnowledgeDir);
528
+ console.log(`Knowledge directory copied to ${targetKnowledgeDir}`);
529
+ }
530
+ catch (knowledgeError) {
531
+ console.warn(`Failed to copy knowledge directory: ${knowledgeError}`);
532
+ }
533
+ }
493
534
  return {
494
535
  content: [
495
536
  {
@@ -2303,135 +2344,45 @@ server.registerTool('generate-sound-effect', {
2303
2344
  return createErrorResponse(error, 'generate-sound-effect');
2304
2345
  }
2305
2346
  });
2306
- server.registerTool('generate-song', {
2307
- title: 'Generate Song',
2308
- description: 'Generate a song with vocals and customizable parameters.',
2347
+ server.registerTool('generate-music', {
2348
+ title: 'Generate Music',
2349
+ description: 'Generate the music. Include background music or song.',
2309
2350
  inputSchema: {
2351
+ prompt: zod_1.z.string().describe('The prompt to generate.'),
2310
2352
  type: zod_1.z
2353
+ .enum(['bgm', 'song'])
2354
+ .describe('The type of music. Defaults to background music.')
2355
+ .default('bgm'),
2356
+ model: zod_1.z
2311
2357
  .enum(['doubao', 'minimax'])
2312
- .default('doubao')
2313
- .describe('The model type of AI to use.'),
2314
- lyrics: zod_1.z.string().describe(`The lyrics to generate the song.
2315
-
2316
- - 完整歌词通常包括以下桥段:
2317
- - 前奏: intro,歌曲开始的音乐部分,主要用于引导歌曲的整体氛围。
2318
- - 主歌: verse,通常在前奏之后,歌曲中叙述歌曲故事或主题的部分。
2319
- - 副歌: chorus,一般在主歌之后,旋律有记忆点和感染力,是整首歌的高潮,进一步强化歌曲的主题和情感。
2320
- - 间奏: inst,歌曲中的纯音乐段落,用于连接不同的演唱部分。
2321
- - 尾奏: outro,歌曲结束后的音乐段落,用于营造歌曲结束的氛围。
2322
- - 桥段: bridge,通常出现在歌曲中段或接近结尾处,是一个过渡部分,用于连接不同的歌曲段落。
2323
-
2324
- ### 歌词示例 lyrics.txt
2325
-
2326
- \`\`\`txt
2327
- [intro]
2328
- [verse]
2329
- 记得那一天 那一天我们相恋
2330
- 说好彼此都不说再见
2331
- 遵守诺言 用心去相恋
2332
- 我为你撑伞 你为我取暖
2333
- [inst]
2334
- [chorus]
2335
- 当我把心交给你的那一天
2336
- 你却消失在我的眼前
2337
- 事到如今已经过了好多年
2338
- 是否你还像从前
2339
- [outro]
2340
- \`\`\`
2341
- `),
2358
+ .optional()
2359
+ .describe('The model to use. Defaults to doubao.')
2360
+ .default('doubao'),
2342
2361
  duration: zod_1.z
2343
2362
  .number()
2344
2363
  .min(30)
2345
2364
  .max(240)
2346
- .describe('The duration of the song in seconds (30-240).'),
2347
- genre: zod_1.z
2348
- .enum([
2349
- 'Folk',
2350
- 'Pop',
2351
- 'Rock',
2352
- 'Chinese Style',
2353
- 'Hip Hop/Rap',
2354
- 'R&B/Soul',
2355
- 'Punk',
2356
- 'Electronic',
2357
- 'Jazz',
2358
- 'Reggae',
2359
- 'DJ',
2360
- 'Pop Punk',
2361
- 'Disco',
2362
- 'Future Bass',
2363
- 'Pop Rap',
2364
- 'Trap Rap',
2365
- 'R&B Rap',
2366
- 'Chinoiserie Electronic',
2367
- 'GuFeng Music',
2368
- 'Pop Rock',
2369
- 'Jazz Pop',
2370
- 'Bossa Nova',
2371
- 'Contemporary R&B',
2372
- ])
2373
- .optional()
2374
- .describe('The genre of the song.'),
2375
- mood: zod_1.z
2376
- .enum([
2377
- 'Happy',
2378
- 'Dynamic/Energetic',
2379
- 'Sentimental/Melancholic/Lonely',
2380
- 'Inspirational/Hopeful',
2381
- 'Nostalgic/Memory',
2382
- 'Excited',
2383
- 'Sorrow/Sad',
2384
- 'Chill',
2385
- 'Relaxing',
2386
- 'Romantic',
2387
- 'Miss',
2388
- 'Groovy/Funky',
2389
- 'Dreamy/Ethereal',
2390
- 'Calm/Relaxing',
2391
- ])
2392
- .optional()
2393
- .describe('The mood of the song.'),
2394
- gender: zod_1.z
2395
- .enum(['Female', 'Male'])
2396
- .optional()
2397
- .describe('The gender of the vocalist.'),
2398
- timbre: zod_1.z
2399
- .enum([
2400
- 'Warm',
2401
- 'Bright',
2402
- 'Husky',
2403
- 'Electrified voice',
2404
- 'Sweet_AUDIO_TIMBRE',
2405
- 'Cute_AUDIO_TIMBRE',
2406
- 'Loud and sonorous',
2407
- 'Powerful',
2408
- 'Sexy/Lazy',
2409
- ])
2410
- .optional()
2411
- .describe('The timbre/voice quality of the vocalist.'),
2365
+ .describe('The duration of the bgm or music.'),
2412
2366
  skipCopyCheck: zod_1.z
2413
2367
  .boolean()
2414
- .optional()
2415
2368
  .default(false)
2416
2369
  .describe('Whether to skip copyright check.'),
2417
2370
  saveToFileName: zod_1.z.string().describe('The filename to save.'),
2418
2371
  },
2419
- }, async ({ type = 'doubao', lyrics, duration, genre, mood, gender, timbre, skipCopyCheck, saveToFileName, }, context) => {
2372
+ }, async ({ prompt, type, model, duration, skipCopyCheck, saveToFileName }, context) => {
2420
2373
  try {
2421
2374
  // 验证session状态
2422
- const currentSession = await validateSession('generate-song');
2375
+ const currentSession = await validateSession('generate-music');
2423
2376
  const validatedFileName = validateFileName(saveToFileName);
2424
- console.log(`Generating Song with lyrics: ${lyrics.substring(0, 100)}... (${duration}s, genre: ${genre || 'auto'}, mood: ${mood || 'auto'})`);
2377
+ console.log(`Generating Music with prompt: ${prompt.substring(0, 100)}... (${duration}s)`);
2425
2378
  const ai = currentSession.ai;
2426
2379
  let progress = 0;
2427
- const res = await ai.generateSong({
2428
- type,
2429
- lyrics: lyrics.trim(),
2430
- duration,
2431
- genre,
2432
- mood,
2433
- gender,
2434
- timbre,
2380
+ if (type === 'bgm' && duration > 120) {
2381
+ throw new Error('BGM duration must be at most 120 seconds.');
2382
+ }
2383
+ const finalPrompt = `${prompt.trim()} ${type === 'bgm' ? `纯音乐无歌词,时长${duration}秒` : `时长${duration}秒,使用${model}模型`}`;
2384
+ const res = await ai.generateMusic({
2385
+ prompt: finalPrompt,
2435
2386
  skipCopyCheck,
2436
2387
  onProgress: async (metaData) => {
2437
2388
  try {
@@ -2443,18 +2394,12 @@ server.registerTool('generate-song', {
2443
2394
  },
2444
2395
  });
2445
2396
  if (!res) {
2446
- throw new Error('Failed to generate Song: no response from AI service');
2397
+ throw new Error('Failed to generate BGM: no response from AI service');
2447
2398
  }
2448
2399
  if (res.url) {
2449
- console.log('Song generated successfully, saving to materials...');
2400
+ console.log('BGM generated successfully, saving to materials...');
2450
2401
  const uri = await saveMaterial(currentSession, res.url, validatedFileName);
2451
- if (!res.captions) {
2452
- // 歌词获取失败,获取字幕
2453
- res.captions = await ai.voiceToCaptions({
2454
- url: res.url,
2455
- });
2456
- }
2457
- const { url, duration: songDuration, captions, ...opts } = res;
2402
+ const { url, duration: bgmDuration, captions, ...opts } = res;
2458
2403
  // 保存captions到本地
2459
2404
  if (captions) {
2460
2405
  const captionsText = JSON.stringify(captions, null, 2);
@@ -2463,103 +2408,13 @@ server.registerTool('generate-song', {
2463
2408
  // 保存到本地
2464
2409
  await (0, promises_1.writeFile)(localPath, captionsText);
2465
2410
  }
2466
- const result = {
2467
- success: true,
2468
- // source: url,
2469
- uri,
2470
- durationMs: Math.floor((songDuration || duration) * 1000),
2471
- lyrics,
2472
- requestedDuration: duration,
2473
- genre,
2474
- mood,
2475
- gender,
2476
- timbre,
2477
- captions,
2478
- timestamp: new Date().toISOString(),
2479
- ...opts,
2480
- };
2481
- // Update media_logs.json
2482
- try {
2483
- await updateMediaLogs(currentSession, validatedFileName, result, 'audio');
2484
- }
2485
- catch (error) {
2486
- console.warn(`Failed to update media_logs.json for ${validatedFileName}:`, error);
2487
- }
2488
- return {
2489
- content: [
2490
- {
2491
- type: 'text',
2492
- text: JSON.stringify(result),
2493
- },
2494
- ],
2495
- };
2496
- }
2497
- else {
2498
- console.warn('Song generation completed but no URL returned');
2499
- return {
2500
- content: [
2501
- {
2502
- type: 'text',
2503
- text: JSON.stringify({
2504
- success: false,
2505
- error: 'No Song URL returned from AI service',
2506
- response: res,
2507
- timestamp: new Date().toISOString(),
2508
- }),
2509
- },
2510
- ],
2511
- };
2512
- }
2513
- }
2514
- catch (error) {
2515
- return createErrorResponse(error, 'generate-song');
2516
- }
2517
- });
2518
- server.registerTool('generate-bgm', {
2519
- title: 'Generate BGM',
2520
- description: 'Generate the bgm.',
2521
- inputSchema: {
2522
- prompt: zod_1.z.string().describe('The prompt to generate.'),
2523
- duration: zod_1.z
2524
- .number()
2525
- .min(30)
2526
- .max(120)
2527
- .describe('The duration of the bgm.'),
2528
- saveToFileName: zod_1.z.string().describe('The filename to save.'),
2529
- },
2530
- }, async ({ prompt, duration, saveToFileName }, context) => {
2531
- try {
2532
- // 验证session状态
2533
- const currentSession = await validateSession('generate-bgm');
2534
- const validatedFileName = validateFileName(saveToFileName);
2535
- console.log(`Generating BGM with prompt: ${prompt.substring(0, 100)}... (${duration}s)`);
2536
- const ai = currentSession.ai;
2537
- let progress = 0;
2538
- const res = await ai.generateBGM({
2539
- prompt: prompt.trim(),
2540
- duration,
2541
- onProgress: async (metaData) => {
2542
- try {
2543
- await sendProgress(context, metaData.Result?.Progress ?? ++progress, metaData.Result?.Progress ? 100 : undefined, JSON.stringify(metaData));
2544
- }
2545
- catch (progressError) {
2546
- console.warn('Failed to send progress update:', progressError);
2547
- }
2548
- },
2549
- });
2550
- if (!res) {
2551
- throw new Error('Failed to generate BGM: no response from AI service');
2552
- }
2553
- if (res.url) {
2554
- console.log('BGM generated successfully, saving to materials...');
2555
- const uri = await saveMaterial(currentSession, res.url, validatedFileName);
2556
- const { url, duration: bgmDuration, ...opts } = res;
2557
2411
  const result = {
2558
2412
  success: true,
2559
2413
  // source: url,
2560
2414
  uri,
2561
2415
  durationMs: Math.floor((bgmDuration || duration) * 1000),
2562
2416
  prompt,
2417
+ captions,
2563
2418
  requestedDuration: duration,
2564
2419
  timestamp: new Date().toISOString(),
2565
2420
  ...opts,