import cls from 'classnames'; import React, { useEffect, useMemo, useState } from 'react'; import { Icon, Popover } from '@opensumi/ide-components'; import { AppConfig, LabelService, MarkerSeverity, URI, Uri, detectModeId, path, useInjectable, } from '@opensumi/ide-core-browser'; import { WorkbenchEditorService } from '@opensumi/ide-editor'; import { ILanguageService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/languages/language'; import { IModelService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/services/model'; import { StandaloneServices } from '@opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices'; import { CodeBlockData } from '../../../../common/types'; import { ApplyStatus } from '../../../components/ApplyStatus'; import { ChatMarkdown } from '../../../components/ChatMarkdown'; import { IMCPServerToolComponentProps } from '../../../types'; import { BaseApplyService } from '../../base-apply.service'; import styles from './index.module.less'; export const EditFileToolComponent = (props: IMCPServerToolComponentProps) => { const { args, messageId, toolCallId } = props; const [mode, setMode] = useState<'code' | 'diff'>('code'); const labelService = useInjectable(LabelService); const appConfig = useInjectable(AppConfig); const applyService = useInjectable(BaseApplyService); const editorService = useInjectable(WorkbenchEditorService); const { target_file = '', code_edit, instructions } = args || {}; const absolutePath = path.join(appConfig.workspaceDir, target_file); const [codeBlockData, setCodeBlockData] = useState( applyService.getCodeBlock(toolCallId, messageId), ); const icon = useMemo(() => { if (!target_file) { return; } const icon = `file-icon ${labelService.getIcon(URI.file(absolutePath))}`; return icon; }, [target_file, absolutePath]); const languageId = useMemo(() => { if (!target_file) { return; } const modelService = StandaloneServices.get(IModelService); const languageService = StandaloneServices.get(ILanguageService); const detectedModeId = detectModeId(modelService, languageService, Uri.file(absolutePath)); return detectedModeId; }, [target_file, absolutePath]); const errorContent = useMemo(() => { if (codeBlockData?.status === 'failed') { try { const result = JSON.parse(props.result || '{}'); return result.content?.[0]?.text; } catch { return ''; } } }, [props.result, codeBlockData]); useEffect(() => { const disposable = applyService.onCodeBlockUpdate((codeBlockData) => { if (codeBlockData.toolCallId === toolCallId) { setCodeBlockData({ ...codeBlockData }); } }); return () => { disposable.dispose(); }; }, []); const handleToggleMode = (e: React.MouseEvent) => { e.stopPropagation(); setMode(mode === 'code' ? 'diff' : 'code'); }; if (!args || !codeBlockData) { return null; } return [ instructions &&

{instructions}

,
{ if (codeBlockData.status === 'pending') { editorService.open(URI.file(absolutePath)); } else if (codeBlockData.status === 'success') { applyService.revealApplyPosition(codeBlockData); } }} >
{icon && } {target_file} {codeBlockData.iterationCount > 1 && ( {codeBlockData.iterationCount}/3 )}
{codeBlockData.applyResult?.diff && ( )}
, codeBlockData.applyResult && codeBlockData.applyResult.diagnosticInfos.length > 0 && (
Found Lints:
{codeBlockData.applyResult?.diagnosticInfos.map((info) => (
{info.message.split('\n')[0]}
))}
), ]; };