cerevox 3.0.0-beta.25 → 3.0.0-beta.27

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.
@@ -513,7 +513,7 @@ server.registerTool('project-close', {
513
513
  .min(0)
514
514
  .max(20)
515
515
  .default(5)
516
- .describe('Close the session after the specified number of minutes. Default is 5 minutes. 如果用户要求立即关闭会话,请将该参数设置为0'),
516
+ .describe('Close the session after the specified number of minutes. Default is 5 minutes. 除非用户要求立即关闭会话,将该参数设置为0,否则应默认设为5'),
517
517
  },
518
518
  }, async ({ inMinutes }) => {
519
519
  try {
@@ -662,69 +662,6 @@ server.registerTool('retrieve-rules-context', {
662
662
  return createErrorResponse(`Failed to load rules context prompt for ${prompt}: ${error}`, 'retrieve-rules-context');
663
663
  }
664
664
  });
665
- // 列出项目下的所有文件
666
- server.registerTool('list-project-files', {
667
- title: 'List Project Files',
668
- description: 'List all files in the materials directory.',
669
- inputSchema: {},
670
- }, async () => {
671
- try {
672
- // 验证session状态
673
- const currentSession = await validateSession('list-project-files');
674
- console.log('Listing project files...');
675
- const terminal = currentSession.terminal;
676
- if (!terminal) {
677
- throw new Error('Terminal not available in current session');
678
- }
679
- let cwd;
680
- try {
681
- cwd = await terminal.getCwd();
682
- }
683
- catch (cwdError) {
684
- console.error('Failed to get current working directory:', cwdError);
685
- throw new Error('Failed to get current working directory');
686
- }
687
- console.log(`Current working directory: ${cwd}`);
688
- // 安全地列出各目录文件,失败时返回空数组
689
- const listFilesWithFallback = async (path, dirName) => {
690
- try {
691
- const files = await currentSession.files.listFiles(path);
692
- console.log(`Found ${files?.length || 0} files in ${dirName}`);
693
- return files || [];
694
- }
695
- catch (error) {
696
- console.warn(`Failed to list files in ${dirName} (${path}):`, error);
697
- return [];
698
- }
699
- };
700
- const [rootFiles, materialsFiles, outputFiles] = await Promise.all([
701
- listFilesWithFallback(cwd, 'root'),
702
- listFilesWithFallback(`${cwd}/materials`, 'materials'),
703
- listFilesWithFallback(`${cwd}/output`, 'output'),
704
- ]);
705
- const result = {
706
- success: true,
707
- cwd,
708
- root: rootFiles,
709
- materials: materialsFiles,
710
- output: outputFiles,
711
- totalFiles: rootFiles.length + materialsFiles.length + outputFiles.length,
712
- timestamp: new Date().toISOString(),
713
- };
714
- console.log(`Total files found: ${result.totalFiles}`);
715
- return {
716
- content: [
717
- {
718
- type: 'text',
719
- text: JSON.stringify(result),
720
- },
721
- ],
722
- };
723
- }
724
- catch (error) {
725
- return createErrorResponse(error, 'list-project-files');
726
- }
727
- });
728
665
  server.registerTool('generate-character-image', {
729
666
  title: 'Generate Character Image',
730
667
  description: 'Generate a turnaround image or portrait for any character.',
@@ -931,49 +868,6 @@ ${roleDescriptionPrompt}
931
868
  return createErrorResponse(error, 'generate-character-image');
932
869
  }
933
870
  });
934
- server.registerTool('generate-line-sketch', {
935
- title: 'Generate Line Sketch',
936
- description: 'Generate line sketch material based on user prompt.',
937
- inputSchema: {
938
- prompt: zod_1.z.string().describe('The prompt to generate line sketch.'),
939
- saveToFileName: zod_1.z
940
- .string()
941
- .describe('The filename to save the generated line sketch. 应该是png文件'),
942
- },
943
- }, async ({ prompt, saveToFileName }) => {
944
- try {
945
- // 验证session状态
946
- await validateSession('generate-line-sketch');
947
- // 验证文件名
948
- validateFileName(saveToFileName);
949
- // 调用AI生成线稿
950
- const res = await session.ai.generateLineSketch({ prompt });
951
- if (res && res.url) {
952
- // 保存到本地
953
- await saveMaterial(session, res.url, saveToFileName);
954
- const result = {
955
- success: true,
956
- url: res.url,
957
- localPath: getMaterialUri(session, saveToFileName),
958
- timestamp: new Date().toISOString(),
959
- };
960
- return {
961
- content: [
962
- {
963
- type: 'text',
964
- text: JSON.stringify(result),
965
- },
966
- ],
967
- };
968
- }
969
- else {
970
- throw new Error('No URL returned from AI service');
971
- }
972
- }
973
- catch (error) {
974
- return createErrorResponse(error, 'generate-line-sketch');
975
- }
976
- });
977
871
  server.registerTool('upload-custom-material', {
978
872
  title: 'Upload Custom Material',
979
873
  description: 'Upload material files (images: jpeg/png, videos: mp4, audio: mp3) from the local filesystem to the materials directory. For video and audio files, duration information will be included in the response.',
@@ -1065,12 +959,18 @@ server.registerTool('generate-image', {
1065
959
  description: `生成图片`,
1066
960
  inputSchema: {
1067
961
  type: zod_1.z
1068
- .enum(['banana', 'banana-pro', 'seedream', 'seedream-pro'])
962
+ .enum([
963
+ 'banana',
964
+ 'banana-pro',
965
+ 'seedream',
966
+ 'seedream-pro',
967
+ 'line-sketch',
968
+ ])
1069
969
  .optional()
1070
970
  .default('seedream'),
1071
971
  prompt: zod_1.z
1072
972
  .string()
1073
- .describe('The prompt to generate. 一般要严格对应 storyboard 中当前场景的 start_frame 或 end_frame 中的字段描述'),
973
+ .describe('The prompt to generate. 一般要严格对应 storyboard 中当前场景的 start_frame 或 end_frame 中的字段描述,如果是生成线稿,则 type 使用 line-sketch'),
1074
974
  sceneIndex: zod_1.z
1075
975
  .number()
1076
976
  .min(1)
@@ -2464,7 +2364,7 @@ server.registerTool('generate-scene-tts', {
2464
2364
  .describe('The volume of the tts.'),
2465
2365
  voiceID: zod_1.z
2466
2366
  .string()
2467
- .describe(`适合作为视频配音的音色ID,除非用户指定,否则你必须已通过 search_voice 工具检查确定该音色确实是存在的。`),
2367
+ .describe(`适合作为视频配音的音色ID,除非用户指定,否则你必须确保已通过 pick-voice 工具挑选出真实存在的音色。`),
2468
2368
  context_texts: zod_1.z
2469
2369
  .array(zod_1.z.string())
2470
2370
  .default([])
@@ -2498,7 +2398,7 @@ server.registerTool('generate-scene-tts', {
2498
2398
  try {
2499
2399
  const voice = (await ai.listVoices()).find(v => v.id === voiceID);
2500
2400
  if (!voice) {
2501
- return createErrorResponse(`Voice ${voiceID} not found in voice-list. Use search-voices tool to find available voices. 若用户坚持要使用该音色,需跳过一致性检查。`, 'generate-scene-tts');
2401
+ return createErrorResponse(`Voice ${voiceID} not found in voice-list. Use pick-voice tool to pick an available voice. 若用户坚持要使用该音色,需跳过一致性检查。`, 'generate-scene-tts');
2502
2402
  }
2503
2403
  const storyBoardPath = (0, node_path_1.resolve)(process.env.ZEROCUT_PROJECT_CWD || process.cwd(), projectLocalDir, storyBoardFile);
2504
2404
  if ((0, node_fs_1.existsSync)(storyBoardPath)) {
@@ -2551,7 +2451,7 @@ server.registerTool('generate-scene-tts', {
2551
2451
  }
2552
2452
  console.log(`Generating TTS with voice: ${voiceID}, speed: ${finalSpeed}, text: ${text.substring(0, 100)}...`);
2553
2453
  if (voiceID.startsWith('BV0')) {
2554
- throw new Error(`BV0* 系列音色已弃用,你必须已通过 search_voice 工具检查确定该音色确实是存在的。`);
2454
+ throw new Error(`BV0* 系列音色已弃用,你必须通过 pick-voice 工具挑选一个真实存在的音色。`);
2555
2455
  }
2556
2456
  const type = voiceID.startsWith('zh_') ||
2557
2457
  voiceID.startsWith('en_') ||
@@ -2706,7 +2606,7 @@ ${context_texts.join('\n')}
2706
2606
  type: 'text',
2707
2607
  text: JSON.stringify({
2708
2608
  success: false,
2709
- error: 'No TTS URL returned from AI service. You should use search-voices tool to find available voices.',
2609
+ error: 'No TTS URL returned from AI service. You should use pick-voice tool to pick an available voice.',
2710
2610
  response: res,
2711
2611
  timestamp: new Date().toISOString(),
2712
2612
  }),
@@ -2939,67 +2839,71 @@ server.registerTool('get-schema', {
2939
2839
  return createErrorResponse(error, 'get-schema');
2940
2840
  }
2941
2841
  });
2942
- server.registerTool('search-voices', {
2943
- title: 'Search Voices',
2944
- description: 'Search voices from doubao_voices_full based on languages, and gender. 搜索并选择符合要求的语音,在合适的情况下,优先采用 volcano_tts_2 类型的语音',
2842
+ server.registerTool('pick-voice', {
2843
+ title: 'Pick Voice',
2844
+ description: '根据用户需求,选择尽可能符合要求的语音,在合适的情况下,优先采用 volcano_tts_2 类型的语音',
2945
2845
  inputSchema: {
2946
- languages: zod_1.z
2947
- .array(zod_1.z.enum([
2948
- 'zh',
2949
- 'en',
2950
- 'ja',
2951
- 'ko',
2952
- 'es',
2953
- 'pt',
2954
- 'nl',
2955
- 'vi',
2956
- 'ru',
2957
- 'id',
2958
- 'de',
2959
- 'fr',
2960
- 'it',
2961
- 'ar',
2962
- 'tr',
2963
- 'uk',
2964
- ]))
2846
+ prompt: zod_1.z
2847
+ .string()
2848
+ .describe('用户需求描述,例如:一个有亲和力的,适合给孩子讲故事的语音'),
2849
+ custom_design: zod_1.z
2850
+ .boolean()
2965
2851
  .optional()
2966
- .describe('Filter by languages (e.g., ["zh", "en"]). If not provided, no language filtering is applied.'),
2967
- gender: zod_1.z
2968
- .enum(['male', 'female'])
2852
+ .describe('是否自定义语音,由于要消耗较多积分,因此**只有用户明确要求自己设计语音**,才将该参数设为true'),
2853
+ custom_design_preview: zod_1.z
2854
+ .string()
2969
2855
  .optional()
2970
- .describe('Filter by gender (male or female). If not provided, no gender filtering is applied.'),
2856
+ .describe('用户自定义语音的预览文本,用于展示自定义语音的效果,只有 custom_design true 时才需要'),
2857
+ custom_design_save_to: zod_1.z
2858
+ .string()
2859
+ .optional()
2860
+ .describe('自定义语音的保存路径,例如:custom_voice.mp3 custom_voice_{id}.mp3'),
2971
2861
  },
2972
- }, async ({ languages, gender }) => {
2862
+ }, async ({ prompt, custom_design, custom_design_preview, custom_design_save_to, }) => {
2973
2863
  try {
2974
2864
  // 验证session状态
2975
- const currentSession = await validateSession('search-voices');
2865
+ const currentSession = await validateSession('pick-voice');
2976
2866
  const ai = currentSession.ai;
2977
- let filteredVoices = await ai.listVoices();
2978
- // Filter by languages
2979
- if (languages && languages.length > 0) {
2980
- filteredVoices = filteredVoices.filter(voice => voice.languages &&
2981
- voice.languages.some((lang) => languages.includes(lang)));
2982
- }
2983
- // Filter by gender
2984
- if (gender) {
2985
- filteredVoices = filteredVoices.filter(voice => {
2986
- return voice.gender === gender;
2867
+ if (custom_design) {
2868
+ if (!custom_design_preview) {
2869
+ throw new Error('custom_design_preview is required when custom_design is true');
2870
+ }
2871
+ const data = await currentSession.ai.voiceDesign({
2872
+ prompt,
2873
+ previewText: custom_design_preview,
2987
2874
  });
2875
+ if (data.voice_id) {
2876
+ const trial_audio = data.trial_audio;
2877
+ let uri = '';
2878
+ if (trial_audio) {
2879
+ uri = await saveMaterial(currentSession, trial_audio, custom_design_save_to || `custom_voice_${data.voice_id}.mp3`);
2880
+ }
2881
+ return {
2882
+ content: [
2883
+ {
2884
+ type: 'text',
2885
+ text: JSON.stringify({
2886
+ success: true,
2887
+ ...data,
2888
+ uri,
2889
+ timestamp: new Date().toISOString(),
2890
+ }),
2891
+ },
2892
+ ],
2893
+ };
2894
+ }
2895
+ else {
2896
+ throw new Error(`Voice design failed, ${JSON.stringify(data)}`);
2897
+ }
2988
2898
  }
2899
+ const data = await ai.pickVoice({ prompt });
2989
2900
  return {
2990
2901
  content: [
2991
2902
  {
2992
2903
  type: 'text',
2993
2904
  text: JSON.stringify({
2994
2905
  success: true,
2995
- data: {
2996
- totalCount: filteredVoices.length,
2997
- voices: filteredVoices,
2998
- filters: {
2999
- languages: languages || null,
3000
- gender: gender || null,
3001
- },
3002
- },
2906
+ ...data,
3003
2907
  timestamp: new Date().toISOString(),
3004
2908
  }),
3005
2909
  },
@@ -3007,52 +2911,7 @@ server.registerTool('search-voices', {
3007
2911
  };
3008
2912
  }
3009
2913
  catch (error) {
3010
- return createErrorResponse(error, 'search-voices');
3011
- }
3012
- });
3013
- server.registerTool('voice-design', {
3014
- title: 'Voice Design',
3015
- description: 'Design a voice based on a prompt. The voice will be designed based on the prompt and preview text.',
3016
- inputSchema: {
3017
- prompt: zod_1.z.string().describe('The prompt to design the voice.'),
3018
- previewText: zod_1.z.string().describe('The preview text to design the voice.'),
3019
- saveToFileName: zod_1.z
3020
- .string()
3021
- .describe('The file name to save the designed voice. 应该是mp3文件'),
3022
- },
3023
- }, async ({ prompt, previewText, saveToFileName }) => {
3024
- try {
3025
- const currentSession = await validateSession('voice-design');
3026
- const data = await currentSession.ai.voiceDesign({
3027
- prompt,
3028
- previewText,
3029
- });
3030
- if (data.voice_id) {
3031
- const trial_audio = data.trial_audio;
3032
- let uri = '';
3033
- if (trial_audio) {
3034
- uri = await saveMaterial(currentSession, trial_audio, saveToFileName);
3035
- }
3036
- return {
3037
- content: [
3038
- {
3039
- type: 'text',
3040
- text: JSON.stringify({
3041
- success: true,
3042
- ...data,
3043
- uri,
3044
- timestamp: new Date().toISOString(),
3045
- }),
3046
- },
3047
- ],
3048
- };
3049
- }
3050
- else {
3051
- throw new Error(`Voice design failed, ${JSON.stringify(data)}`);
3052
- }
3053
- }
3054
- catch (error) {
3055
- return createErrorResponse(error, 'voice-design');
2914
+ return createErrorResponse(error, 'pick-voice');
3056
2915
  }
3057
2916
  });
3058
2917
  server.registerTool('media-analyzer', {
@@ -3268,206 +3127,6 @@ server.registerTool('media-analyzer', {
3268
3127
  return createErrorResponse(error, 'media-analyzer');
3269
3128
  }
3270
3129
  });
3271
- // server.registerTool(
3272
- // 'image-aligner',
3273
- // {
3274
- // title: 'Image Aligner',
3275
- // description:
3276
- // 'Analyze image quality and alignment with prompt using AI Image Quality Inspector.',
3277
- // inputSchema: {
3278
- // imageFileName: z
3279
- // .string()
3280
- // .describe('The image file name in materials directory to analyze.'),
3281
- // sceneIndex: z.number().min(1).describe('场景索引,从1开始的下标'),
3282
- // storyBoardFile: z
3283
- // .string()
3284
- // .optional()
3285
- // .default('storyboard.json')
3286
- // .describe('故事板文件路径'),
3287
- // imagePrompt: z
3288
- // .string()
3289
- // .optional()
3290
- // .describe('可选的图片提示词,如果提供则覆盖storyboard中的提示词'),
3291
- // customPrompt: z
3292
- // .string()
3293
- // .optional()
3294
- // .describe('可选的额外用户要求,用于补充图片质量评估的特定需求'),
3295
- // },
3296
- // },
3297
- // async ({
3298
- // imageFileName,
3299
- // sceneIndex,
3300
- // storyBoardFile = 'storyboard.json',
3301
- // imagePrompt,
3302
- // customPrompt,
3303
- // }) => {
3304
- // try {
3305
- // const currentSession = await validateSession('image-aligner');
3306
- // // 验证图片文件
3307
- // validateImageFile(imageFileName);
3308
- // // 获取图片 URL
3309
- // const imageUrl = getMaterialUri(currentSession, imageFileName);
3310
- // // 确定要使用的提示词
3311
- // let finalPrompt = imagePrompt;
3312
- // // 如果没有提供imagePrompt,则从storyboard中获取
3313
- // if (!imagePrompt) {
3314
- // try {
3315
- // const storyBoardPath = resolve(
3316
- // process.env.ZEROCUT_PROJECT_CWD || process.cwd(),
3317
- // projectLocalDir,
3318
- // storyBoardFile
3319
- // );
3320
- // if (existsSync(storyBoardPath)) {
3321
- // const storyBoardContent = await readFile(storyBoardPath, 'utf8');
3322
- // const storyBoard = JSON.parse(storyBoardContent);
3323
- // if (storyBoard.scenes && Array.isArray(storyBoard.scenes)) {
3324
- // const scene = storyBoard.scenes[sceneIndex - 1]; // sceneIndex 从1开始,数组从0开始
3325
- // if (scene) {
3326
- // // 根据文件名判断优先级:若end_frame存在且imageFileName包含"_end"则优先取end_frame,否则取start_frame
3327
- // if (scene.end_frame && imageFileName.includes('_end')) {
3328
- // finalPrompt = scene.end_frame;
3329
- // } else {
3330
- // finalPrompt = scene.start_frame || scene.end_frame;
3331
- // }
3332
- // if (!finalPrompt) {
3333
- // return createErrorResponse(
3334
- // `场景 ${sceneIndex} 中未找到 start_frame 或 end_frame 提示词`,
3335
- // 'image-aligner'
3336
- // );
3337
- // }
3338
- // } else {
3339
- // return createErrorResponse(
3340
- // `在 ${storyBoardFile} 中未找到场景索引 ${sceneIndex}`,
3341
- // 'image-aligner'
3342
- // );
3343
- // }
3344
- // } else {
3345
- // return createErrorResponse(
3346
- // `${storyBoardFile} 文件格式不正确,缺少 scenes 数组`,
3347
- // 'image-aligner'
3348
- // );
3349
- // }
3350
- // } else {
3351
- // return createErrorResponse(
3352
- // `故事板文件不存在: ${storyBoardPath}`,
3353
- // 'image-aligner'
3354
- // );
3355
- // }
3356
- // } catch (error) {
3357
- // return createErrorResponse(
3358
- // `读取或解析故事板文件失败: ${error}`,
3359
- // 'image-aligner'
3360
- // );
3361
- // }
3362
- // }
3363
- // // 如果仍然没有提示词,返回错误
3364
- // if (!finalPrompt) {
3365
- // return createErrorResponse(
3366
- // '未提供 imagePrompt 且无法从故事板中获取提示词',
3367
- // 'image-aligner'
3368
- // );
3369
- // }
3370
- // // 读取图片质量检查指南
3371
- // const alignerGuidelinePath = resolve(
3372
- // __dirname,
3373
- // './prompts/reasonings/image_aligner.md'
3374
- // );
3375
- // let alignerGuideline = '';
3376
- // try {
3377
- // alignerGuideline = await readFile(alignerGuidelinePath, 'utf8');
3378
- // } catch (error) {
3379
- // console.warn('无法读取图片质量检查指南:', error);
3380
- // alignerGuideline =
3381
- // '请对图片质量进行评估,包括构图、色彩、清晰度等方面。';
3382
- // }
3383
- // // 构建系统提示
3384
- // const systemPrompt = `你是一个专业的AI图片质量检查员。请根据以下指南对图片进行评估:
3385
- // ${alignerGuideline}
3386
- // 请严格按照指南中的JSON格式返回评估结果。`;
3387
- // // 构建用户提示
3388
- // const userPrompt = `请对这张图片进行质量评估。
3389
- // 原始提示词:${finalPrompt}${
3390
- // customPrompt
3391
- // ? `
3392
- // 额外要求:${customPrompt}`
3393
- // : ''
3394
- // }
3395
- // 请按照指南要求,返回包含评分、问题列表和优化建议的JSON格式结果。`;
3396
- // // 调用AI模型进行图片质量评估
3397
- // const ai = currentSession.ai;
3398
- // const completion = await ai.getCompletions({
3399
- // model: 'Doubao-Seed-1.6',
3400
- // messages: [
3401
- // {
3402
- // role: 'system',
3403
- // content: systemPrompt,
3404
- // },
3405
- // {
3406
- // role: 'user',
3407
- // content: [
3408
- // {
3409
- // type: 'image_url',
3410
- // image_url: {
3411
- // url: imageUrl,
3412
- // },
3413
- // },
3414
- // {
3415
- // type: 'text',
3416
- // text: userPrompt,
3417
- // },
3418
- // ],
3419
- // },
3420
- // ],
3421
- // });
3422
- // const result = completion.choices[0]?.message?.content;
3423
- // if (!result) {
3424
- // throw new Error('No response from AI model');
3425
- // }
3426
- // // 解析AI响应
3427
- // let alignmentResult;
3428
- // try {
3429
- // // 尝试从响应中提取JSON
3430
- // const jsonMatch =
3431
- // result.match(/```json\s*([\s\S]*?)\s*```/) ||
3432
- // result.match(/\{[\s\S]*\}/);
3433
- // if (jsonMatch) {
3434
- // alignmentResult = JSON.parse(jsonMatch[1] || jsonMatch[0]);
3435
- // } else {
3436
- // // 如果没有找到JSON格式,尝试直接解析整个响应
3437
- // alignmentResult = JSON.parse(result);
3438
- // }
3439
- // } catch (error) {
3440
- // // 如果解析失败,返回原始响应
3441
- // alignmentResult = {
3442
- // error: 'JSON解析失败',
3443
- // raw_response: result,
3444
- // };
3445
- // }
3446
- // return {
3447
- // content: [
3448
- // {
3449
- // type: 'text',
3450
- // text: JSON.stringify({
3451
- // success: true,
3452
- // imageFileName,
3453
- // sceneIndex,
3454
- // storyBoardFile,
3455
- // imagePrompt: finalPrompt,
3456
- // customPrompt,
3457
- // promptSource: imagePrompt ? 'manual_override' : 'storyboard',
3458
- // analysis: alignmentResult,
3459
- // imageUrl,
3460
- // nextActionSuggest:
3461
- // '可根据分析结果调整提示词,修改storyboard后,重新生成图片。',
3462
- // }),
3463
- // },
3464
- // ],
3465
- // };
3466
- // } catch (error) {
3467
- // return createErrorResponse(error, 'image-aligner');
3468
- // }
3469
- // }
3470
- // );
3471
3130
  server.registerTool('audio-video-sync', {
3472
3131
  title: 'Audio Video Sync',
3473
3132
  description: 'Generate audio-video-synced video by matching video with audio. 还可以对口型。',
@@ -4399,6 +4058,69 @@ server.registerTool('search-context', {
4399
4058
  return createErrorResponse(error, 'search-context');
4400
4059
  }
4401
4060
  });
4061
+ // 列出项目下的所有文件
4062
+ server.registerTool('list-project-files', {
4063
+ title: 'List Project Files',
4064
+ description: 'List all files in the materials directory.',
4065
+ inputSchema: {},
4066
+ }, async () => {
4067
+ try {
4068
+ // 验证session状态
4069
+ const currentSession = await validateSession('list-project-files');
4070
+ console.log('Listing project files...');
4071
+ const terminal = currentSession.terminal;
4072
+ if (!terminal) {
4073
+ throw new Error('Terminal not available in current session');
4074
+ }
4075
+ let cwd;
4076
+ try {
4077
+ cwd = await terminal.getCwd();
4078
+ }
4079
+ catch (cwdError) {
4080
+ console.error('Failed to get current working directory:', cwdError);
4081
+ throw new Error('Failed to get current working directory');
4082
+ }
4083
+ console.log(`Current working directory: ${cwd}`);
4084
+ // 安全地列出各目录文件,失败时返回空数组
4085
+ const listFilesWithFallback = async (path, dirName) => {
4086
+ try {
4087
+ const files = await currentSession.files.listFiles(path);
4088
+ console.log(`Found ${files?.length || 0} files in ${dirName}`);
4089
+ return files || [];
4090
+ }
4091
+ catch (error) {
4092
+ console.warn(`Failed to list files in ${dirName} (${path}):`, error);
4093
+ return [];
4094
+ }
4095
+ };
4096
+ const [rootFiles, materialsFiles, outputFiles] = await Promise.all([
4097
+ listFilesWithFallback(cwd, 'root'),
4098
+ listFilesWithFallback(`${cwd}/materials`, 'materials'),
4099
+ listFilesWithFallback(`${cwd}/output`, 'output'),
4100
+ ]);
4101
+ const result = {
4102
+ success: true,
4103
+ cwd,
4104
+ root: rootFiles,
4105
+ materials: materialsFiles,
4106
+ output: outputFiles,
4107
+ totalFiles: rootFiles.length + materialsFiles.length + outputFiles.length,
4108
+ timestamp: new Date().toISOString(),
4109
+ };
4110
+ console.log(`Total files found: ${result.totalFiles}`);
4111
+ return {
4112
+ content: [
4113
+ {
4114
+ type: 'text',
4115
+ text: JSON.stringify(result),
4116
+ },
4117
+ ],
4118
+ };
4119
+ }
4120
+ catch (error) {
4121
+ return createErrorResponse(error, 'list-project-files');
4122
+ }
4123
+ });
4402
4124
  server.registerTool('build-capcat-draft', {
4403
4125
  title: 'Build CapCut Draft',
4404
4126
  description: 'Read draft_content.json file, parse JSON and generate URIs for all assets in timeline tracks, then output the processed JSON string.',