@opensumi/ide-ai-native 3.8.1-next-1741080291.0 → 3.8.1-next-1741091353.0
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/lib/browser/ai-core.contribution.d.ts +0 -3
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +1 -45
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-agent.service.d.ts +8 -0
- package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-agent.service.js +32 -5
- package/lib/browser/chat/chat-agent.service.js.map +1 -1
- package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-manager.service.js +4 -0
- package/lib/browser/chat/chat-manager.service.js.map +1 -1
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +3 -2
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +5 -9
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/chat/chat.module.less +1 -2
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +13 -39
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatContext/index.js +2 -2
- package/lib/browser/components/ChatContext/index.js.map +1 -1
- package/lib/browser/components/ChatInput.d.ts.map +1 -1
- package/lib/browser/components/ChatInput.js +25 -1
- package/lib/browser/components/ChatInput.js.map +1 -1
- package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
- package/lib/browser/components/ChatToolRender.js +2 -3
- package/lib/browser/components/ChatToolRender.js.map +1 -1
- package/lib/browser/components/chat-history.module.less +2 -1
- package/lib/browser/components/components.module.less +20 -0
- package/lib/browser/context/llm-context.service.d.ts +18 -5
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +80 -47
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/layout/layout.module.less +4 -4
- package/lib/browser/mcp/base-apply.service.d.ts +18 -7
- package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
- package/lib/browser/mcp/base-apply.service.js +185 -65
- package/lib/browser/mcp/base-apply.service.js.map +1 -1
- package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
- package/lib/browser/mcp/tools/components/EditFile.js +15 -9
- package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
- package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts +13 -0
- package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts.map +1 -0
- package/lib/browser/mcp/tools/components/{SearchResult.js → ExpandableFileList.js} +29 -19
- package/lib/browser/mcp/tools/components/ExpandableFileList.js.map +1 -0
- package/lib/browser/mcp/tools/components/index.module.less +4 -0
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
- package/lib/browser/mcp/tools/createNewFileWithText.js +19 -11
- package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
- package/lib/browser/mcp/tools/fileSearch.d.ts +1 -0
- package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/fileSearch.js +14 -5
- package/lib/browser/mcp/tools/fileSearch.js.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js +1 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.js +6 -3
- package/lib/browser/mcp/tools/grepSearch.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/EditFile.js +1 -1
- package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts +1 -0
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/ListDir.js +3 -0
- package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
- package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
- package/lib/browser/mcp/tools/listDir.d.ts +1 -0
- package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
- package/lib/browser/mcp/tools/listDir.js +35 -4
- package/lib/browser/mcp/tools/listDir.js.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
- package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
- package/lib/browser/model/msg-history-manager.d.ts +1 -0
- package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
- package/lib/browser/model/msg-history-manager.js +3 -0
- package/lib/browser/model/msg-history-manager.js.map +1 -1
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +1 -7
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-manager.js +68 -8
- package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +10 -4
- package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-previewer.js +14 -3
- package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +25 -4
- package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +3 -3
- package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff.controller.js +10 -5
- package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +46 -17
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +110 -53
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +4 -0
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +26 -1
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
- package/lib/common/index.d.ts +0 -1
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +0 -2
- package/lib/common/index.js.map +1 -1
- package/lib/common/llm-context.d.ts +13 -9
- package/lib/common/llm-context.d.ts.map +1 -1
- package/lib/common/llm-context.js.map +1 -1
- package/lib/common/prompts/context-prompt-provider.d.ts +4 -3
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +33 -22
- package/lib/common/prompts/context-prompt-provider.js.map +1 -1
- package/lib/common/types.d.ts +1 -0
- package/lib/common/types.d.ts.map +1 -1
- package/lib/node/anthropic/anthropic-language-model.d.ts +1 -3
- package/lib/node/anthropic/anthropic-language-model.d.ts.map +1 -1
- package/lib/node/anthropic/anthropic-language-model.js +2 -6
- package/lib/node/anthropic/anthropic-language-model.js.map +1 -1
- package/lib/node/base-language-model.d.ts +1 -4
- package/lib/node/base-language-model.d.ts.map +1 -1
- package/lib/node/base-language-model.js +6 -7
- package/lib/node/base-language-model.js.map +1 -1
- package/lib/node/deepseek/deepseek-language-model.d.ts +1 -3
- package/lib/node/deepseek/deepseek-language-model.d.ts.map +1 -1
- package/lib/node/deepseek/deepseek-language-model.js +2 -6
- package/lib/node/deepseek/deepseek-language-model.js.map +1 -1
- package/lib/node/openai/openai-language-model.d.ts +4 -5
- package/lib/node/openai/openai-language-model.d.ts.map +1 -1
- package/lib/node/openai/openai-language-model.js +7 -8
- package/lib/node/openai/openai-language-model.js.map +1 -1
- package/package.json +23 -24
- package/src/browser/ai-core.contribution.ts +1 -56
- package/src/browser/chat/chat-agent.service.ts +38 -7
- package/src/browser/chat/chat-manager.service.ts +6 -0
- package/src/browser/chat/chat-model.ts +11 -6
- package/src/browser/chat/chat-proxy.service.ts +6 -9
- package/src/browser/chat/chat.module.less +1 -2
- package/src/browser/chat/chat.view.tsx +14 -72
- package/src/browser/components/ChatContext/index.tsx +2 -2
- package/src/browser/components/ChatInput.tsx +67 -3
- package/src/browser/components/ChatToolRender.tsx +1 -2
- package/src/browser/components/chat-history.module.less +2 -1
- package/src/browser/components/components.module.less +20 -0
- package/src/browser/context/llm-context.service.ts +93 -54
- package/src/browser/layout/layout.module.less +4 -4
- package/src/browser/mcp/base-apply.service.ts +222 -67
- package/src/browser/mcp/tools/components/EditFile.tsx +16 -9
- package/src/browser/mcp/tools/components/ExpandableFileList.tsx +133 -0
- package/src/browser/mcp/tools/components/index.module.less +4 -0
- package/src/browser/mcp/tools/createNewFileWithText.ts +21 -12
- package/src/browser/mcp/tools/fileSearch.ts +14 -4
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -0
- package/src/browser/mcp/tools/grepSearch.ts +6 -3
- package/src/browser/mcp/tools/handlers/EditFile.ts +1 -1
- package/src/browser/mcp/tools/handlers/ListDir.ts +4 -0
- package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
- package/src/browser/mcp/tools/listDir.ts +36 -5
- package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
- package/src/browser/model/msg-history-manager.ts +4 -0
- package/src/browser/preferences/schema.ts +1 -7
- package/src/browser/widget/inline-diff/inline-diff-manager.tsx +143 -21
- package/src/browser/widget/inline-diff/inline-diff-previewer.ts +25 -7
- package/src/browser/widget/inline-diff/inline-diff-widget.module.less +25 -4
- package/src/browser/widget/inline-diff/inline-diff.controller.ts +16 -8
- package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +139 -68
- package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +30 -1
- package/src/common/index.ts +0 -2
- package/src/common/llm-context.ts +10 -4
- package/src/common/prompts/context-prompt-provider.ts +38 -29
- package/src/common/types.ts +1 -0
- package/src/node/anthropic/anthropic-language-model.ts +2 -7
- package/src/node/base-language-model.ts +12 -10
- package/src/node/deepseek/deepseek-language-model.ts +2 -7
- package/src/node/openai/openai-language-model.ts +9 -10
- package/lib/browser/mcp/tools/components/SearchResult.d.ts +0 -11
- package/lib/browser/mcp/tools/components/SearchResult.d.ts.map +0 -1
- package/lib/browser/mcp/tools/components/SearchResult.js.map +0 -1
- package/lib/common/model.d.ts +0 -12
- package/lib/common/model.d.ts.map +0 -1
- package/lib/common/model.js +0 -83
- package/lib/common/model.js.map +0 -1
- package/lib/node/openai-compatible/openai-compatible-language-model.d.ts +0 -10
- package/lib/node/openai-compatible/openai-compatible-language-model.d.ts.map +0 -1
- package/lib/node/openai-compatible/openai-compatible-language-model.js +0 -32
- package/lib/node/openai-compatible/openai-compatible-language-model.js.map +0 -1
- package/src/browser/mcp/tools/components/SearchResult.tsx +0 -92
- package/src/common/model.ts +0 -90
- package/src/node/openai-compatible/openai-compatible-language-model.ts +0 -30
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { CommandService, LabelService, URI, path, useInjectable } from '@opensumi/ide-core-browser';
|
|
4
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
5
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
6
|
+
|
|
7
|
+
import { IChatInternalService } from '../../../../common';
|
|
8
|
+
import { ChatInternalService } from '../../../chat/chat.internal.service';
|
|
9
|
+
|
|
10
|
+
import styles from './index.module.less';
|
|
11
|
+
|
|
12
|
+
interface FileInfo {
|
|
13
|
+
uri: string;
|
|
14
|
+
isDirectory: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ExpandableFileListProps {
|
|
18
|
+
args: any;
|
|
19
|
+
toolCallId: string;
|
|
20
|
+
messageId: string;
|
|
21
|
+
toolName: string;
|
|
22
|
+
headerText?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const FileSearchToolComponent: React.FC<ExpandableFileListProps> = ({ args, toolCallId, messageId }) => (
|
|
26
|
+
<ExpandableFileList
|
|
27
|
+
args={args}
|
|
28
|
+
toolCallId={toolCallId}
|
|
29
|
+
messageId={messageId}
|
|
30
|
+
toolName='fileSearch'
|
|
31
|
+
headerText={`Searched files "${args.query}"`}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export const GrepSearchToolComponent: React.FC<ExpandableFileListProps> = ({ args, toolCallId, messageId }) => (
|
|
36
|
+
<ExpandableFileList
|
|
37
|
+
args={args}
|
|
38
|
+
toolCallId={toolCallId}
|
|
39
|
+
messageId={messageId}
|
|
40
|
+
toolName='grepSearch'
|
|
41
|
+
headerText={`Grepped codebase "${args.query}"`}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export const ListDirToolComponent: React.FC<ExpandableFileListProps> = ({ args, toolCallId, messageId }) => (
|
|
46
|
+
<ExpandableFileList
|
|
47
|
+
args={args}
|
|
48
|
+
toolCallId={toolCallId}
|
|
49
|
+
messageId={messageId}
|
|
50
|
+
toolName='listDir'
|
|
51
|
+
headerText={`Listed directory "${args.relative_workspace_path}"`}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const ExpandableFileList: React.FC<ExpandableFileListProps> = ({
|
|
56
|
+
args,
|
|
57
|
+
toolCallId,
|
|
58
|
+
toolName,
|
|
59
|
+
messageId,
|
|
60
|
+
headerText,
|
|
61
|
+
}) => {
|
|
62
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
63
|
+
const labelService = useInjectable<LabelService>(LabelService);
|
|
64
|
+
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
65
|
+
const workspaceService = useInjectable<IWorkspaceService>(IWorkspaceService);
|
|
66
|
+
const commandService = useInjectable<CommandService>(CommandService);
|
|
67
|
+
const workspaceRoot = useMemo(() => URI.parse(workspaceService.tryGetRoots()?.[0]?.uri), []);
|
|
68
|
+
|
|
69
|
+
const chatService = useInjectable<ChatInternalService>(IChatInternalService);
|
|
70
|
+
const [fileList, setFileList] = useState<FileInfo[]>([]);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const toDispose = chatService.sessionModel.history.onMessageAdditionalChange((additional) => {
|
|
74
|
+
setFileList(additional[toolCallId]?.files || []);
|
|
75
|
+
});
|
|
76
|
+
return () => {
|
|
77
|
+
toDispose.dispose();
|
|
78
|
+
};
|
|
79
|
+
}, []);
|
|
80
|
+
|
|
81
|
+
const handleFileClick = async (fileInfo: FileInfo) => {
|
|
82
|
+
// 处理文件点击跳转
|
|
83
|
+
if (!fileInfo.isDirectory) {
|
|
84
|
+
editorService.open(URI.parse(fileInfo.uri));
|
|
85
|
+
} else {
|
|
86
|
+
// 如果是目录,聚焦到文件树并展开该目录
|
|
87
|
+
const uri = URI.parse(fileInfo.uri);
|
|
88
|
+
commandService.executeCommand('filetree.location', uri);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const parsedFiles = useMemo(
|
|
93
|
+
() =>
|
|
94
|
+
fileList.map((file) => {
|
|
95
|
+
const uri = URI.parse(file.uri);
|
|
96
|
+
const iconClass = labelService.getIcon(uri, { isDirectory: file.isDirectory });
|
|
97
|
+
return {
|
|
98
|
+
iconClass,
|
|
99
|
+
name: uri.path.base,
|
|
100
|
+
path: path.relative(workspaceRoot.codeUri.fsPath, uri.path.dir.toString()),
|
|
101
|
+
uri: file.uri,
|
|
102
|
+
isDirectory: file.isDirectory,
|
|
103
|
+
};
|
|
104
|
+
}),
|
|
105
|
+
[fileList],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div className={styles.container}>
|
|
110
|
+
<div className={styles.header} onClick={() => setIsExpanded(!isExpanded)}>
|
|
111
|
+
<span style={{ transform: `rotate(${isExpanded ? '90deg' : '0deg'})` }}>▶</span>
|
|
112
|
+
<span>
|
|
113
|
+
{headerText} · {fileList.length} files
|
|
114
|
+
</span>
|
|
115
|
+
</div>
|
|
116
|
+
{isExpanded && (
|
|
117
|
+
<ul className={styles.fileList}>
|
|
118
|
+
{parsedFiles.map((file, index) => (
|
|
119
|
+
<li
|
|
120
|
+
key={index}
|
|
121
|
+
className={styles.fileItem}
|
|
122
|
+
onClick={() => handleFileClick({ uri: file.uri, isDirectory: file.isDirectory })}
|
|
123
|
+
>
|
|
124
|
+
<span className={file.iconClass}></span>
|
|
125
|
+
<span style={{ flex: 1 }}>{file.name}</span>
|
|
126
|
+
<span className={styles.filePath}>{file.path}</span>
|
|
127
|
+
</li>
|
|
128
|
+
))}
|
|
129
|
+
</ul>
|
|
130
|
+
)}
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
align-items: center;
|
|
18
18
|
justify-content: center;
|
|
19
19
|
}
|
|
20
|
+
.left {
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
}
|
|
20
23
|
.left,
|
|
21
24
|
.right {
|
|
22
25
|
display: flex;
|
|
@@ -154,6 +157,7 @@
|
|
|
154
157
|
background-color: var(--design-chatInput-background);
|
|
155
158
|
padding: 10px;
|
|
156
159
|
border-radius: 4px;
|
|
160
|
+
margin: 10px 0px;
|
|
157
161
|
|
|
158
162
|
.command_title {
|
|
159
163
|
display: flex;
|
|
@@ -6,10 +6,13 @@ import { IFileServiceClient } from '@opensumi/ide-file-service';
|
|
|
6
6
|
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
7
7
|
|
|
8
8
|
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
9
|
+
import { BaseApplyService } from '../base-apply.service';
|
|
10
|
+
|
|
11
|
+
import { EditFileToolComponent } from './components/EditFile';
|
|
9
12
|
|
|
10
13
|
const inputSchema = z.object({
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
target_file: z.string().describe('The relative path where the file should be created'),
|
|
15
|
+
code_edit: z.string().describe('The content to write into the new file'),
|
|
13
16
|
});
|
|
14
17
|
|
|
15
18
|
@Domain(MCPServerContribution)
|
|
@@ -20,29 +23,31 @@ export class CreateNewFileWithTextTool implements MCPServerContribution {
|
|
|
20
23
|
@Autowired(IFileServiceClient)
|
|
21
24
|
private readonly fileService: IFileServiceClient;
|
|
22
25
|
|
|
26
|
+
@Autowired(BaseApplyService)
|
|
27
|
+
private applyService: BaseApplyService;
|
|
28
|
+
|
|
23
29
|
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
24
30
|
registry.registerMCPTool(this.getToolDefinition());
|
|
31
|
+
registry.registerToolComponent('create_new_file_with_text', EditFileToolComponent);
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
getToolDefinition(): MCPToolDefinition {
|
|
28
35
|
return {
|
|
29
36
|
name: 'create_new_file_with_text',
|
|
37
|
+
label: 'Create File',
|
|
30
38
|
description:
|
|
31
39
|
'Creates a new file at the specified path within the project directory and populates it with the provided text. ' +
|
|
32
40
|
'Use this tool to generate new files in your project structure. ' +
|
|
33
|
-
'Requires two parameters: ' +
|
|
34
|
-
'- pathInProject: The relative path where the file should be created ' +
|
|
35
|
-
'- text: The content to write into the new file ' +
|
|
36
41
|
'Returns one of two possible responses: ' +
|
|
37
42
|
'"ok" if the file was successfully created and populated, ' +
|
|
38
43
|
'"can\'t find project dir" if the project directory cannot be determined. ' +
|
|
39
|
-
'Note:
|
|
44
|
+
'Note: This tool creates any necessary parent directories automatically.',
|
|
40
45
|
inputSchema,
|
|
41
46
|
handler: this.handler.bind(this),
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
private async handler(args: z.infer<typeof inputSchema
|
|
50
|
+
private async handler(args: z.infer<typeof inputSchema> & { toolCallId: string }, logger: MCPLogger) {
|
|
46
51
|
try {
|
|
47
52
|
// 获取工作区根目录
|
|
48
53
|
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
@@ -56,7 +61,7 @@ export class CreateNewFileWithTextTool implements MCPServerContribution {
|
|
|
56
61
|
|
|
57
62
|
// 构建完整的文件路径
|
|
58
63
|
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
59
|
-
const fullPath = path.join(rootUri.codeUri.fsPath, args.
|
|
64
|
+
const fullPath = path.join(rootUri.codeUri.fsPath, args.target_file);
|
|
60
65
|
const fileUri = URI.file(fullPath);
|
|
61
66
|
|
|
62
67
|
// 创建父目录
|
|
@@ -64,17 +69,21 @@ export class CreateNewFileWithTextTool implements MCPServerContribution {
|
|
|
64
69
|
const parentUri = URI.file(parentDir);
|
|
65
70
|
await this.fileService.createFolder(parentUri.toString());
|
|
66
71
|
|
|
67
|
-
//
|
|
68
|
-
await this.fileService.createFile(fileUri.toString()
|
|
72
|
+
// 创建文件
|
|
73
|
+
await this.fileService.createFile(fileUri.toString());
|
|
74
|
+
|
|
75
|
+
// 使用 applyService 写入文件内容
|
|
76
|
+
const codeBlock = await this.applyService.registerCodeBlock(args.target_file, args.code_edit, args.toolCallId);
|
|
77
|
+
await this.applyService.apply(codeBlock);
|
|
69
78
|
|
|
70
|
-
logger.appendLine(`Successfully created file at: ${args.
|
|
79
|
+
logger.appendLine(`Successfully created file at: ${args.target_file}`);
|
|
71
80
|
return {
|
|
72
81
|
content: [{ type: 'text', text: 'ok' }],
|
|
73
82
|
};
|
|
74
83
|
} catch (error) {
|
|
75
84
|
logger.appendLine(`Error during file creation: ${error}`);
|
|
76
85
|
return {
|
|
77
|
-
content: [{ type: 'text', text:
|
|
86
|
+
content: [{ type: 'text', text: error.message }],
|
|
78
87
|
isError: true,
|
|
79
88
|
};
|
|
80
89
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
import { Autowired } from '@opensumi/di';
|
|
4
|
+
import { getValidateInput } from '@opensumi/ide-addons/lib/browser/file-search.contribution';
|
|
4
5
|
import { Domain, URI } from '@opensumi/ide-core-common';
|
|
5
6
|
import { FileSearchServicePath, IFileSearchService } from '@opensumi/ide-file-search/lib/common';
|
|
6
7
|
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
@@ -9,7 +10,7 @@ import { IChatInternalService } from '../../../common';
|
|
|
9
10
|
import { ChatInternalService } from '../../chat/chat.internal.service';
|
|
10
11
|
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
11
12
|
|
|
12
|
-
import { FileSearchToolComponent } from './components/
|
|
13
|
+
import { FileSearchToolComponent } from './components/ExpandableFileList';
|
|
13
14
|
|
|
14
15
|
const inputSchema = z.object({
|
|
15
16
|
query: z.string().describe('Fuzzy filename to search for'),
|
|
@@ -58,7 +59,7 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
// 使用 OpenSumi 的文件搜索 API
|
|
61
|
-
const searchPattern = args.query;
|
|
62
|
+
const searchPattern = this.normalizeQuery(args.query);
|
|
62
63
|
const searchResults = await this.fileSearchService.find(searchPattern, {
|
|
63
64
|
rootUris: [new URI(workspaceRoots[0].uri).codeUri.fsPath],
|
|
64
65
|
// TODO: 忽略配置
|
|
@@ -71,7 +72,10 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
71
72
|
|
|
72
73
|
const files = searchResults.slice(0, MAX_RESULTS).map((file) => {
|
|
73
74
|
const uri = URI.parse(file);
|
|
74
|
-
return
|
|
75
|
+
return {
|
|
76
|
+
uri: uri.codeUri.fsPath,
|
|
77
|
+
isDirectory: false, // 文件搜索结果都是文件
|
|
78
|
+
};
|
|
75
79
|
});
|
|
76
80
|
|
|
77
81
|
const messages = this.chatInternalService.sessionModel.history.getMessages();
|
|
@@ -87,7 +91,7 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
87
91
|
content: [
|
|
88
92
|
{
|
|
89
93
|
type: 'text',
|
|
90
|
-
text: `${files.join('\n')}\n${
|
|
94
|
+
text: `${files.map((f) => f.uri).join('\n')}\n${
|
|
91
95
|
searchResults.length > MAX_RESULTS
|
|
92
96
|
? `\nFound ${searchResults.length} files matching "${args.query}", only return the first ${MAX_RESULTS} results`
|
|
93
97
|
: ''
|
|
@@ -96,4 +100,10 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
96
100
|
],
|
|
97
101
|
};
|
|
98
102
|
}
|
|
103
|
+
|
|
104
|
+
private normalizeQuery(query: string): string {
|
|
105
|
+
const nonBlank = query.trim().replace(/\s/g, '');
|
|
106
|
+
const validated = getValidateInput(nonBlank);
|
|
107
|
+
return validated;
|
|
108
|
+
}
|
|
99
109
|
}
|
|
@@ -29,6 +29,7 @@ export class GetDiagnosticsByPathTool implements MCPServerContribution {
|
|
|
29
29
|
getToolDefinition(): MCPToolDefinition {
|
|
30
30
|
return {
|
|
31
31
|
name: 'get_diagnostics_by_path',
|
|
32
|
+
label: 'Get Diagnostics',
|
|
32
33
|
description:
|
|
33
34
|
'Retrieves diagnostic information (errors, warnings, etc.) from a specific file in the project. ' +
|
|
34
35
|
'Use this tool to get information about problems in any project file. ' +
|
|
@@ -10,7 +10,7 @@ import { IChatInternalService } from '../../../common';
|
|
|
10
10
|
import { ChatInternalService } from '../../chat/chat.internal.service';
|
|
11
11
|
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
12
12
|
|
|
13
|
-
import { GrepSearchToolComponent } from './components/
|
|
13
|
+
import { GrepSearchToolComponent } from './components/ExpandableFileList';
|
|
14
14
|
|
|
15
15
|
const inputSchema = z.object({
|
|
16
16
|
query: z.string().describe('The regex pattern to search for'),
|
|
@@ -90,7 +90,7 @@ export class GrepSearchTool implements MCPServerContribution {
|
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
const results: string[] = [];
|
|
93
|
-
const files: string
|
|
93
|
+
const files: Array<{ uri: string; isDirectory: boolean }> = [];
|
|
94
94
|
for (const [fileUri, result] of this.searchService.searchResults.entries()) {
|
|
95
95
|
results.push(
|
|
96
96
|
`File: ${fileUri}\n${result
|
|
@@ -103,7 +103,10 @@ export class GrepSearchTool implements MCPServerContribution {
|
|
|
103
103
|
.map((r) => `Line: ${r.line}\nContent: ${r.lineText || r.renderLineText}`)
|
|
104
104
|
.join('\n')}`,
|
|
105
105
|
);
|
|
106
|
-
files.push(
|
|
106
|
+
files.push({
|
|
107
|
+
uri: fileUri,
|
|
108
|
+
isDirectory: false, // grep 搜索结果都是文件
|
|
109
|
+
});
|
|
107
110
|
}
|
|
108
111
|
deferred.resolve(results.join('\n\n'));
|
|
109
112
|
const messages = this.chatInternalService.sessionModel.history.getMessages();
|
|
@@ -14,7 +14,7 @@ export class EditFileHandler {
|
|
|
14
14
|
|
|
15
15
|
async handler(params: { targetFile: string; codeEdit: string; instructions?: string }, toolCallId: string) {
|
|
16
16
|
const { targetFile, codeEdit } = params;
|
|
17
|
-
const block = this.applyService.registerCodeBlock(targetFile, codeEdit, toolCallId);
|
|
17
|
+
const block = await this.applyService.registerCodeBlock(targetFile, codeEdit, toolCallId);
|
|
18
18
|
const blockData = await this.applyService.apply(block);
|
|
19
19
|
return blockData;
|
|
20
20
|
}
|
|
@@ -56,6 +56,10 @@ export class ListDirHandler {
|
|
|
56
56
|
@Autowired(IFileServiceClient)
|
|
57
57
|
private readonly fileSystemService: IFileServiceClient;
|
|
58
58
|
|
|
59
|
+
getWorkspaceDir(): string {
|
|
60
|
+
return this.appConfig.workspaceDir;
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
async handler(args: { relativeWorkspacePath: string }) {
|
|
60
64
|
const { relativeWorkspacePath } = args;
|
|
61
65
|
if (!relativeWorkspacePath) {
|
|
@@ -49,6 +49,7 @@ export class RunCommandHandler {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async handler(args: z.infer<typeof inputSchema> & { toolCallId: string }, logger: MCPLogger) {
|
|
52
|
+
logger.appendLine(`Executing command: ${args.command}`);
|
|
52
53
|
if (args.require_user_approval) {
|
|
53
54
|
const def = new Deferred<boolean>();
|
|
54
55
|
this.approvalDeferredMap.set(args.toolCallId, def);
|
|
@@ -89,6 +90,7 @@ export class RunCommandHandler {
|
|
|
89
90
|
content: result,
|
|
90
91
|
});
|
|
91
92
|
|
|
93
|
+
logger.appendLine(`Command ${args.command} finished with exit code: ${e.code}`);
|
|
92
94
|
terminalClient.term.writeln(
|
|
93
95
|
`\n${color.italic}> Command ${args.command} executed successfully. Terminal will close in ${
|
|
94
96
|
3000 / 1000
|
|
@@ -3,8 +3,11 @@ import { z } from 'zod';
|
|
|
3
3
|
import { Autowired } from '@opensumi/di';
|
|
4
4
|
import { Domain } from '@opensumi/ide-core-common';
|
|
5
5
|
|
|
6
|
+
import { IChatInternalService } from '../../../common';
|
|
7
|
+
import { ChatInternalService } from '../../chat/chat.internal.service';
|
|
6
8
|
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
7
9
|
|
|
10
|
+
import { ListDirToolComponent } from './components/ExpandableFileList';
|
|
8
11
|
import { ListDirHandler } from './handlers/ListDir';
|
|
9
12
|
|
|
10
13
|
const inputSchema = z
|
|
@@ -26,8 +29,12 @@ export class ListDirTool implements MCPServerContribution {
|
|
|
26
29
|
@Autowired(ListDirHandler)
|
|
27
30
|
private readonly listDirHandler: ListDirHandler;
|
|
28
31
|
|
|
32
|
+
@Autowired(IChatInternalService)
|
|
33
|
+
private readonly chatInternalService: ChatInternalService;
|
|
34
|
+
|
|
29
35
|
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
30
36
|
registry.registerMCPTool(this.getToolDefinition());
|
|
37
|
+
registry.registerToolComponent('list_dir', ListDirToolComponent);
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
getToolDefinition(): MCPToolDefinition {
|
|
@@ -41,16 +48,40 @@ export class ListDirTool implements MCPServerContribution {
|
|
|
41
48
|
};
|
|
42
49
|
}
|
|
43
50
|
|
|
44
|
-
private async handler(args: z.infer<typeof inputSchema
|
|
51
|
+
private async handler(args: z.infer<typeof inputSchema> & { toolCallId: string }, logger: MCPLogger) {
|
|
45
52
|
const result = await this.listDirHandler.handler(args);
|
|
53
|
+
|
|
54
|
+
// 构建文件 URI 列表,用于前端渲染
|
|
55
|
+
const fileUris = result.files.map((file) => {
|
|
56
|
+
const filePath = `${this.listDirHandler.getWorkspaceDir()}/${result.directoryRelativeWorkspacePath}/${file.name}`;
|
|
57
|
+
return {
|
|
58
|
+
uri: filePath,
|
|
59
|
+
isDirectory: file.isDirectory,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// 设置消息的附加数据
|
|
64
|
+
const messages = this.chatInternalService.sessionModel.history.getMessages();
|
|
65
|
+
this.chatInternalService.sessionModel.history.setMessageAdditional(messages[messages.length - 1].id, {
|
|
66
|
+
[args.toolCallId]: {
|
|
67
|
+
files: fileUris,
|
|
68
|
+
title: `Listed directory "${args.relativeWorkspacePath}"`,
|
|
69
|
+
details: result.files.map((file) => ({
|
|
70
|
+
type: file.isDirectory ? 'dir' : 'file',
|
|
71
|
+
name: file.name,
|
|
72
|
+
info: file.isDirectory ? `${file.numChildren ?? '?'} items` : `${file.size}KB, ${file.numLines} lines`,
|
|
73
|
+
lastModified: file.lastModified,
|
|
74
|
+
})),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
logger.appendLine(`Listed ${fileUris.length} files in directory "${args.relativeWorkspacePath}"`);
|
|
79
|
+
|
|
46
80
|
return {
|
|
47
81
|
content: [
|
|
48
82
|
{
|
|
49
83
|
type: 'text',
|
|
50
|
-
text: `Contents of directory
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
${result.files
|
|
84
|
+
text: `Contents of directory "${args.relativeWorkspacePath}":\n${result.files
|
|
54
85
|
.map(
|
|
55
86
|
(file) =>
|
|
56
87
|
`[${file.isDirectory ? 'dir' : 'file'}] ${file.name} ${
|
|
@@ -32,6 +32,7 @@ export class RunTerminalCommandTool implements MCPServerContribution {
|
|
|
32
32
|
getToolDefinition(): MCPToolDefinition {
|
|
33
33
|
return {
|
|
34
34
|
name: 'run_terminal_cmd',
|
|
35
|
+
label: 'Run Command',
|
|
35
36
|
description:
|
|
36
37
|
"PROPOSE a command to run on behalf of the user.\nIf you have this tool, note that you DO have the ability to run commands directly on the USER's system.\n\nAdhere to these rules:\n1. Based on the contents of the conversation, you will be told if you are in the same shell as a previous step or a new shell.\n2. If in a new shell, you should `cd` to the right directory and do necessary setup in addition to running the command.\n3. If in the same shell, the state will persist, no need to do things like `cd` to the same directory.\n4. For ANY commands that would use a pager, you should append ` | cat` to the command (or whatever is appropriate). You MUST do this for: git, less, head, tail, more, etc.\n5. For commands that are long running/expected to run indefinitely until interruption, please run them in the background. To run jobs in the background, set `is_background` to true rather than changing the details of the command.\n6. Dont include any newlines in the command.",
|
|
37
38
|
inputSchema,
|
|
@@ -128,6 +128,10 @@ export class MsgHistoryManager extends Disposable {
|
|
|
128
128
|
return this.messageAdditionalMap.get(id) || {};
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
public get sessionAdditionals() {
|
|
132
|
+
return this.messageAdditionalMap;
|
|
133
|
+
}
|
|
134
|
+
|
|
131
135
|
toJSON() {
|
|
132
136
|
return {
|
|
133
137
|
messages: this.getMessages(),
|
|
@@ -69,14 +69,9 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
|
|
|
69
69
|
[AINativeSettingSectionsId.LLMModelSelection]: {
|
|
70
70
|
type: 'string',
|
|
71
71
|
default: 'deepseek',
|
|
72
|
-
enum: ['deepseek', 'anthropic', 'openai'
|
|
72
|
+
enum: ['deepseek', 'anthropic', 'openai'],
|
|
73
73
|
description: localize('preference.ai.native.llm.model.selection.description'),
|
|
74
74
|
},
|
|
75
|
-
[AINativeSettingSectionsId.ModelID]: {
|
|
76
|
-
type: 'string',
|
|
77
|
-
default: 'deepseek-chat',
|
|
78
|
-
description: localize('preference.ai.native.llm.model.id'),
|
|
79
|
-
},
|
|
80
75
|
[AINativeSettingSectionsId.DeepseekApiKey]: {
|
|
81
76
|
type: 'string',
|
|
82
77
|
default: '',
|
|
@@ -153,7 +148,6 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
|
|
|
153
148
|
},
|
|
154
149
|
[AINativeSettingSectionsId.SystemPrompt]: {
|
|
155
150
|
type: 'string',
|
|
156
|
-
default: '',
|
|
157
151
|
description: localize('preference.ai.native.chat.system.prompt.description'),
|
|
158
152
|
},
|
|
159
153
|
},
|
|
@@ -1,38 +1,160 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { localize, useInjectable } from '@opensumi/ide-core-browser';
|
|
5
|
-
import { IResource } from '@opensumi/ide-editor';
|
|
3
|
+
import { Icon, Popover } from '@opensumi/ide-components';
|
|
4
|
+
import { AppConfig, IDisposable, URI, localize, path, useInjectable } from '@opensumi/ide-core-browser';
|
|
5
|
+
import { IResource, WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
6
|
+
import { Path } from '@opensumi/ide-utils/lib/path';
|
|
6
7
|
|
|
7
8
|
import { BaseApplyService } from '../../mcp/base-apply.service';
|
|
8
9
|
|
|
9
10
|
import styles from './inline-diff-widget.module.less';
|
|
10
11
|
|
|
12
|
+
const IconWithPopover = (props: {
|
|
13
|
+
icon: string;
|
|
14
|
+
content: string;
|
|
15
|
+
id: string;
|
|
16
|
+
onClick?: () => void;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
}) => (
|
|
19
|
+
<Popover content={props.content} id={props.id} onClick={props.onClick}>
|
|
20
|
+
<Icon iconClass={props.icon} className={props.disabled ? styles.disabled : ''} />
|
|
21
|
+
</Popover>
|
|
22
|
+
);
|
|
23
|
+
|
|
11
24
|
export const InlineDiffManager: React.FC<{ resource: IResource }> = (props) => {
|
|
25
|
+
const { resource } = props;
|
|
12
26
|
const applyService = useInjectable<BaseApplyService>(BaseApplyService);
|
|
27
|
+
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
28
|
+
const appConfig = useInjectable<AppConfig>(AppConfig);
|
|
13
29
|
const [show, setShow] = useState(true);
|
|
30
|
+
const [changesCount, setChangesCount] = useState(0);
|
|
31
|
+
const [currentChangeIndex, setCurrentChangeIndex] = useState(0);
|
|
32
|
+
const [filePaths, setFilePaths] = useState<string[]>([]);
|
|
33
|
+
|
|
34
|
+
const currentFilePath = useMemo(
|
|
35
|
+
() => path.relative(appConfig.workspaceDir, resource.uri.path.toString()),
|
|
36
|
+
[resource],
|
|
37
|
+
);
|
|
38
|
+
|
|
14
39
|
useEffect(() => {
|
|
15
|
-
applyService.onCodeBlockUpdate((codeBlock) => {
|
|
16
|
-
|
|
40
|
+
const toDispose = applyService.onCodeBlockUpdate((codeBlock) => {
|
|
41
|
+
if (path.relative(appConfig.workspaceDir, props.resource.uri.path.toString()) === codeBlock.relativePath) {
|
|
42
|
+
setShow(codeBlock.status === 'pending');
|
|
43
|
+
}
|
|
44
|
+
const pendingPaths = applyService.getPendingPaths();
|
|
45
|
+
setFilePaths(pendingPaths);
|
|
17
46
|
});
|
|
47
|
+
return () => {
|
|
48
|
+
toDispose.dispose();
|
|
49
|
+
};
|
|
18
50
|
}, []);
|
|
51
|
+
|
|
52
|
+
// 不同编辑器是不同实例,所以不需要监听
|
|
53
|
+
const decorationModelService = applyService.currentPreviewer?.getNode()?.livePreviewDiffDecorationModel;
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
let toDispose: IDisposable | undefined;
|
|
57
|
+
if (decorationModelService) {
|
|
58
|
+
setChangesCount(decorationModelService.partialEditWidgetCount);
|
|
59
|
+
toDispose = decorationModelService.onPartialEditWidgetListChange((e) => {
|
|
60
|
+
setChangesCount(e.filter((item) => item.status === 'pending').length);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return () => {
|
|
64
|
+
toDispose?.dispose();
|
|
65
|
+
};
|
|
66
|
+
}, [decorationModelService]);
|
|
67
|
+
|
|
68
|
+
const handleSiblingChange = useCallback(
|
|
69
|
+
(direction: 'up' | 'down') => {
|
|
70
|
+
const index = decorationModelService?.revealSiblingChange(direction);
|
|
71
|
+
if (index !== undefined) {
|
|
72
|
+
setCurrentChangeIndex(index);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
[decorationModelService],
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const handleSiblingFile = useCallback(
|
|
79
|
+
(direction: 'up' | 'down') => {
|
|
80
|
+
const index = filePaths.indexOf(currentFilePath!);
|
|
81
|
+
if (index === -1) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const uri = URI.file(path.join(appConfig.workspaceDir, filePaths[index + (direction === 'up' ? -1 : 1)]));
|
|
85
|
+
editorService.open(uri);
|
|
86
|
+
},
|
|
87
|
+
[currentFilePath, filePaths],
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const changeTip = useMemo(() => {
|
|
91
|
+
if (changesCount === 0) {
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
return ` ${currentChangeIndex + 1} of ${changesCount}`;
|
|
95
|
+
}, [changesCount, currentChangeIndex]);
|
|
96
|
+
|
|
97
|
+
const fileTip = useMemo(() => {
|
|
98
|
+
if (!currentFilePath) {
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
return ` ${filePaths.indexOf(currentFilePath) + 1} of ${filePaths.length}`;
|
|
102
|
+
}, [currentFilePath, filePaths]);
|
|
103
|
+
|
|
19
104
|
return (
|
|
20
105
|
<div className={styles.inlineDiffManager} style={{ display: show ? 'flex' : 'none' }}>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
106
|
+
{/* <div className={styles.left}>
|
|
107
|
+
<IconWithPopover
|
|
108
|
+
icon='codicon codicon-issues'
|
|
109
|
+
content={localize('aiNative.inlineDiff.reveal')}
|
|
110
|
+
id='inline-diff-manager-reveal'
|
|
111
|
+
onClick={handleReveal}
|
|
112
|
+
/>
|
|
113
|
+
</div> */}
|
|
114
|
+
<div className={styles.mid}>
|
|
115
|
+
<IconWithPopover
|
|
116
|
+
icon='codicon codicon-check'
|
|
117
|
+
onClick={() => applyService.processAll(props.resource.uri, 'accept')}
|
|
118
|
+
content={localize('aiNative.inlineDiff.acceptAll')}
|
|
119
|
+
id='inline-diff-manager-accept-all'
|
|
120
|
+
/>
|
|
121
|
+
<IconWithPopover
|
|
122
|
+
icon='codicon codicon-close'
|
|
123
|
+
onClick={() => applyService.processAll(props.resource.uri, 'reject')}
|
|
124
|
+
content={localize('aiNative.inlineDiff.rejectAll')}
|
|
125
|
+
id='inline-diff-manager-reject-all'
|
|
126
|
+
/>
|
|
127
|
+
<IconWithPopover
|
|
128
|
+
icon='codicon codicon-arrow-up'
|
|
129
|
+
content={localize('aiNative.inlineDiff.up') + changeTip}
|
|
130
|
+
id='inline-diff-manager-up'
|
|
131
|
+
disabled={currentChangeIndex === 0}
|
|
132
|
+
onClick={() => handleSiblingChange('up')}
|
|
133
|
+
/>
|
|
134
|
+
<IconWithPopover
|
|
135
|
+
icon='codicon codicon-arrow-down'
|
|
136
|
+
content={localize('aiNative.inlineDiff.down') + changeTip}
|
|
137
|
+
id='inline-diff-manager-down'
|
|
138
|
+
disabled={currentChangeIndex === changesCount - 1}
|
|
139
|
+
onClick={() => handleSiblingChange('down')}
|
|
140
|
+
/>
|
|
141
|
+
</div>
|
|
142
|
+
<div className={styles.right}>
|
|
143
|
+
<IconWithPopover
|
|
144
|
+
icon='codicon codicon-arrow-left'
|
|
145
|
+
onClick={() => handleSiblingFile('up')}
|
|
146
|
+
disabled={filePaths.length === 0 || filePaths[0] === currentFilePath}
|
|
147
|
+
content={localize('aiNative.inlineDiff.left') + fileTip}
|
|
148
|
+
id='inline-diff-manager-left'
|
|
149
|
+
/>
|
|
150
|
+
<IconWithPopover
|
|
151
|
+
icon='codicon codicon-arrow-right'
|
|
152
|
+
onClick={() => handleSiblingFile('down')}
|
|
153
|
+
disabled={filePaths.length === 0 || filePaths[filePaths.length - 1] === currentFilePath}
|
|
154
|
+
content={localize('aiNative.inlineDiff.right') + fileTip}
|
|
155
|
+
id='inline-diff-manager-right'
|
|
156
|
+
/>
|
|
157
|
+
</div>
|
|
36
158
|
</div>
|
|
37
159
|
);
|
|
38
160
|
};
|