jarvis-ai-assistant 0.1.121__py3-none-any.whl → 0.1.122__py3-none-any.whl
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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_code_agent/code_agent.py +36 -58
- jarvis/jarvis_code_agent/patch.py +145 -322
- jarvis/jarvis_code_agent/relevant_files.py +2 -4
- jarvis/jarvis_platform/kimi.py +0 -2
- jarvis/jarvis_tools/file_operation.py +0 -3
- jarvis/jarvis_tools/read_code.py +1 -2
- jarvis/jarvis_utils/__init__.py +3 -3
- {jarvis_ai_assistant-0.1.121.dist-info → jarvis_ai_assistant-0.1.122.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.1.121.dist-info → jarvis_ai_assistant-0.1.122.dist-info}/RECORD +14 -15
- {jarvis_ai_assistant-0.1.121.dist-info → jarvis_ai_assistant-0.1.122.dist-info}/entry_points.txt +0 -1
- jarvis/jarvis_dev/main.py +0 -878
- {jarvis_ai_assistant-0.1.121.dist-info → jarvis_ai_assistant-0.1.122.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.121.dist-info → jarvis_ai_assistant-0.1.122.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.121.dist-info → jarvis_ai_assistant-0.1.122.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
|
@@ -29,66 +29,44 @@ class CodeAgent:
|
|
|
29
29
|
"lsp_prepare_rename",
|
|
30
30
|
"lsp_validate_edit"])
|
|
31
31
|
code_system_prompt = """
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
## Core Principles
|
|
46
|
-
1. Deep Code Analysis
|
|
47
|
-
- Thoroughly analyze existing code using `read_code` and LSP tools
|
|
48
|
-
- Identify patterns, conventions, and dependencies
|
|
49
|
-
|
|
50
|
-
2. Change Implementation
|
|
51
|
-
- Produce minimal, focused changes
|
|
52
|
-
- Maintain backward compatibility
|
|
53
|
-
- Follow existing style and patterns exactly
|
|
54
|
-
- Complete implementations (NO TODOs/stubs)
|
|
32
|
+
# Role: Senior Code Engineer
|
|
33
|
+
Expert in precise code modifications with minimal impact.
|
|
34
|
+
|
|
35
|
+
## Key Responsibilities
|
|
36
|
+
1. Code Analysis
|
|
37
|
+
- Use `read_code` and LSP tools before changes
|
|
38
|
+
- Identify dependencies and patterns
|
|
39
|
+
|
|
40
|
+
2. Modification Rules
|
|
41
|
+
- Single atomic change per operation
|
|
42
|
+
- Strict style consistency
|
|
43
|
+
- Complete implementations (no stubs)
|
|
44
|
+
- Full error handling
|
|
55
45
|
|
|
56
46
|
3. Quality Assurance
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
## Tools
|
|
81
|
-
Primary:
|
|
82
|
-
- `read_code` (MUST use for code understanding)
|
|
83
|
-
- LSP tools (analysis/validation)
|
|
84
|
-
- `ask_user` for clarifications
|
|
85
|
-
|
|
86
|
-
## Quality Checklist
|
|
87
|
-
- Maintains all interfaces
|
|
88
|
-
- Matches existing style
|
|
89
|
-
- Complete error handling
|
|
90
|
-
- No overlapping modifications
|
|
91
|
-
- Proper documentation
|
|
47
|
+
- Validate with LSP tools
|
|
48
|
+
- Document complex logic
|
|
49
|
+
- Maintain API contracts
|
|
50
|
+
|
|
51
|
+
## Workflow
|
|
52
|
+
1. File Operations Order:
|
|
53
|
+
a) Move/Remove files
|
|
54
|
+
b) Create new files
|
|
55
|
+
c) Delete code blocks
|
|
56
|
+
d) Replace existing code
|
|
57
|
+
e) Insert new code
|
|
58
|
+
|
|
59
|
+
2. Large File Handling:
|
|
60
|
+
- Locate specific sections first
|
|
61
|
+
- Read targeted ranges
|
|
62
|
+
- Make focused changes
|
|
63
|
+
|
|
64
|
+
## Best Practices
|
|
65
|
+
- Prefer minimal changes over rewrites
|
|
66
|
+
- Preserve existing interfaces
|
|
67
|
+
- Verify line ranges carefully
|
|
68
|
+
- Test edge cases implicitly
|
|
69
|
+
- Document non-obvious logic
|
|
92
70
|
"""
|
|
93
71
|
self.agent = Agent(system_prompt=code_system_prompt,
|
|
94
72
|
name="CodeAgent",
|
|
@@ -21,276 +21,109 @@ class PatchOutputHandler(OutputHandler):
|
|
|
21
21
|
|
|
22
22
|
def prompt(self) -> str:
|
|
23
23
|
return """
|
|
24
|
-
#
|
|
25
|
-
<
|
|
26
|
-
File
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# 🗑️ DELETE: Remove existing code
|
|
41
|
-
<DELETE>
|
|
42
|
-
File: path/to/file
|
|
43
|
-
Lines: [start,end] or [start,end)
|
|
44
|
-
</DELETE>
|
|
45
|
-
|
|
46
|
-
# 🆕 NEW_FILE: Create new file
|
|
47
|
-
<NEW_FILE>
|
|
48
|
-
File: path/to/file
|
|
49
|
-
[new content]
|
|
50
|
-
...
|
|
51
|
-
</NEW_FILE>
|
|
52
|
-
|
|
53
|
-
# ➡️ MOVE_FILE: Relocate a file
|
|
54
|
-
<MOVE_FILE>
|
|
55
|
-
File: path/to/source/file
|
|
56
|
-
NewPath: path/to/destination/file
|
|
57
|
-
</MOVE_FILE>
|
|
58
|
-
|
|
59
|
-
# ❌ REMOVE_FILE: Delete entire file
|
|
60
|
-
<REMOVE_FILE>
|
|
61
|
-
File: path/to/file
|
|
62
|
-
</REMOVE_FILE>
|
|
63
|
-
|
|
64
|
-
# 📋 Formatting Rules
|
|
65
|
-
1. File Paths
|
|
66
|
-
- Use relative paths from project root
|
|
67
|
-
- Must be exact and case-sensitive
|
|
68
|
-
- Example: src/module/file.py
|
|
69
|
-
|
|
70
|
-
2. Line Numbers
|
|
71
|
-
- Format: [start,end] (inclusive) or [start,end) (right-exclusive)
|
|
72
|
-
- 1-based line numbers
|
|
73
|
-
- Single number for INSERT
|
|
74
|
-
- Omit for NEW_FILE/REMOVE_FILE
|
|
75
|
-
|
|
76
|
-
3. Content
|
|
77
|
-
- Maintain original indentation
|
|
78
|
-
- Follow existing code style
|
|
79
|
-
|
|
80
|
-
# 📌 Usage Examples
|
|
81
|
-
## REPLACE Example (Closed Interval)
|
|
82
|
-
<REPLACE>
|
|
83
|
-
File: src/utils.py
|
|
84
|
-
Lines: [9,13]
|
|
24
|
+
# 🛠️ Simplified Patch Format
|
|
25
|
+
<PATCH>
|
|
26
|
+
File path [Operation parameters]
|
|
27
|
+
Code content
|
|
28
|
+
</PATCH>
|
|
29
|
+
|
|
30
|
+
Operation types:
|
|
31
|
+
- Replace: [Start line,End line] Replace line range (e.g. [5,8] replaces lines 5-8)
|
|
32
|
+
- Delete: [Start line,End line] Delete line range (e.g. [10,10] deletes line 10)
|
|
33
|
+
- Insert: [Line number] Insert before specified line (e.g. [3] inserts before line 3)
|
|
34
|
+
- New file: [1] Create new file
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
# Replace operation
|
|
38
|
+
<PATCH>
|
|
39
|
+
src/app.py [5,8]
|
|
85
40
|
def updated_function():
|
|
86
|
-
|
|
87
|
-
return
|
|
88
|
-
</
|
|
41
|
+
print("Replaced lines 5-8")
|
|
42
|
+
return new_value * 2
|
|
43
|
+
</PATCH>
|
|
89
44
|
|
|
90
|
-
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def new_calculation():
|
|
95
|
-
# Replaces lines 5-7 (excludes line 8)
|
|
96
|
-
return 42
|
|
97
|
-
</REPLACE>
|
|
45
|
+
# Delete operation
|
|
46
|
+
<PATCH>
|
|
47
|
+
src/old.py [10,10]
|
|
48
|
+
</PATCH>
|
|
98
49
|
|
|
99
|
-
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
new_feature()
|
|
105
|
-
</INSERT>
|
|
50
|
+
# Insert operation
|
|
51
|
+
<PATCH>
|
|
52
|
+
utils/logger.py [3]
|
|
53
|
+
print("Inserted before original line 3")
|
|
54
|
+
</PATCH>
|
|
106
55
|
|
|
107
|
-
## NEW_FILE Example
|
|
108
|
-
<NEW_FILE>
|
|
109
|
-
File: src/new_module.py
|
|
110
56
|
# New file creation
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
File: src/utils.py
|
|
118
|
-
Lines: [9,13]
|
|
119
|
-
</DELETE>
|
|
120
|
-
|
|
121
|
-
## MOVE_FILE Example
|
|
122
|
-
<MOVE_FILE>
|
|
123
|
-
File: src/old_dir/file.py
|
|
124
|
-
NewPath: src/new_dir/file.py
|
|
125
|
-
</MOVE_FILE>
|
|
126
|
-
|
|
127
|
-
## REMOVE_FILE Example
|
|
128
|
-
<REMOVE_FILE>
|
|
129
|
-
File: src/obsolete.py
|
|
130
|
-
</REMOVE_FILE>
|
|
131
|
-
|
|
132
|
-
# 🚨 Critical Requirements
|
|
133
|
-
1. One change per block
|
|
134
|
-
2. Use correct operation type
|
|
135
|
-
3. Match existing code style
|
|
136
|
-
4. Preserve indentation levels
|
|
137
|
-
5. Exact file paths required
|
|
138
|
-
6. Handle edge cases properly
|
|
139
|
-
7. Include error handling
|
|
140
|
-
8. Maintain code consistency
|
|
141
|
-
|
|
142
|
-
# 🚫 Invalid Format Examples
|
|
143
|
-
## BAD EXAMPLE 1 - Do not use diff format
|
|
144
|
-
<REPLACE>
|
|
145
|
-
File: src/file.py
|
|
146
|
-
Lines: [5,8)
|
|
147
|
-
- old_line_1
|
|
148
|
-
+ new_line_1
|
|
149
|
-
</REPLACE>
|
|
150
|
-
|
|
151
|
-
## BAD EXAMPLE 2 - Do not include previous and new tags
|
|
152
|
-
<REPLACE>
|
|
153
|
-
File: src/file.py
|
|
154
|
-
Lines: [10,12]
|
|
155
|
-
<PREVIOUS>
|
|
156
|
-
old_code
|
|
157
|
-
</PREVIOUS>
|
|
158
|
-
<NEW>
|
|
159
|
-
new_code
|
|
160
|
-
</NEW>
|
|
161
|
-
</REPLACE>
|
|
162
|
-
|
|
163
|
-
## BAD EXAMPLE 3 - Do not use comment to explain
|
|
164
|
-
<REPLACE>
|
|
165
|
-
File: src/file.py
|
|
166
|
-
Lines: [15,18]
|
|
167
|
-
# Replace the following code
|
|
168
|
-
old_function()
|
|
169
|
-
# With the new implementation
|
|
170
|
-
new_function()
|
|
171
|
-
</REPLACE>
|
|
57
|
+
<PATCH>
|
|
58
|
+
config.yaml [1]
|
|
59
|
+
database:
|
|
60
|
+
host: localhost
|
|
61
|
+
port: 5432
|
|
62
|
+
</PATCH>
|
|
172
63
|
"""
|
|
173
64
|
|
|
174
65
|
|
|
175
66
|
def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
|
|
176
|
-
"""
|
|
67
|
+
"""解析补丁格式"""
|
|
177
68
|
result = {}
|
|
178
|
-
|
|
69
|
+
header_pattern = re.compile(
|
|
70
|
+
r'^\s*"?(.+?)"?\s*\[(\d+)(?:,(\d+))?\]\s*$' # Match file path and line number
|
|
71
|
+
)
|
|
72
|
+
patches = re.findall(r'<PATCH>\n?(.*?)\n?</PATCH>', patch_str, re.DOTALL)
|
|
179
73
|
|
|
180
|
-
for
|
|
181
|
-
|
|
182
|
-
|
|
74
|
+
for patch in patches:
|
|
75
|
+
# 分割首行和内容
|
|
76
|
+
parts = patch.split('\n', 1)
|
|
77
|
+
if len(parts) < 1:
|
|
183
78
|
continue
|
|
79
|
+
header_line = parts[0].strip()
|
|
80
|
+
content = parts[1] if len(parts) > 1 else ''
|
|
81
|
+
|
|
82
|
+
# 仅在内容非空时添加换行符
|
|
83
|
+
if content and not content.endswith('\n'):
|
|
84
|
+
content += '\n'
|
|
184
85
|
|
|
185
|
-
#
|
|
186
|
-
|
|
187
|
-
if not
|
|
86
|
+
# 解析文件路径和行号
|
|
87
|
+
header_match = header_pattern.match(header_line)
|
|
88
|
+
if not header_match:
|
|
188
89
|
continue
|
|
189
|
-
filepath = file_match.group(1).strip()
|
|
190
|
-
|
|
191
|
-
# Initialize line numbers
|
|
192
|
-
start_line = end_line = 0
|
|
193
|
-
|
|
194
|
-
# Parse line numbers based on operation type
|
|
195
|
-
if patch_type in ['REPLACE', 'DELETE']:
|
|
196
|
-
# 增强正则表达式兼容性
|
|
197
|
-
line_match = re.match(
|
|
198
|
-
r"^Lines:\s*\[\s*(\d+)\s*(?:,\s*(\d+)\s*)?([\]\)])\s*$", # 支持单数字格式
|
|
199
|
-
lines[1].strip(), # 去除前后空格
|
|
200
|
-
re.IGNORECASE
|
|
201
|
-
)
|
|
202
|
-
if line_match:
|
|
203
|
-
start_line = int(line_match.group(1))
|
|
204
|
-
end_value = int(line_match.group(2) or line_match.group(1)) # 第二个数字不存在时使用第一个
|
|
205
|
-
bracket_type = line_match.group(3).strip()
|
|
206
|
-
|
|
207
|
-
# 根据括号类型处理区间
|
|
208
|
-
if bracket_type == ')': # [m,n)
|
|
209
|
-
end_line = end_value - 1
|
|
210
|
-
else: # [m,n]
|
|
211
|
-
end_line = end_value
|
|
212
|
-
|
|
213
|
-
# 确保 end_line >= start_line
|
|
214
|
-
end_line = max(end_line, start_line)
|
|
215
|
-
else:
|
|
216
|
-
PrettyOutput.print(f"无法解析行号格式: {lines[1]}", OutputType.WARNING)
|
|
217
|
-
continue
|
|
218
|
-
elif patch_type == 'INSERT':
|
|
219
|
-
line_match = re.match(r"Line:\s*(\d+)", lines[1])
|
|
220
|
-
if line_match:
|
|
221
|
-
start_line = int(line_match.group(1)) # 1-based
|
|
222
|
-
end_line = start_line
|
|
223
|
-
elif patch_type == 'MOVE_FILE':
|
|
224
|
-
new_path_match = re.match(r"NewPath:\s*([^\s]+)", lines[1])
|
|
225
|
-
if new_path_match:
|
|
226
|
-
new_path = new_path_match.group(1).strip()
|
|
227
|
-
else:
|
|
228
|
-
continue
|
|
229
|
-
|
|
230
|
-
# Get content (after metadata)
|
|
231
|
-
if patch_type in ['REPLACE', 'DELETE']:
|
|
232
|
-
content_start = 2 # File + Lines
|
|
233
|
-
elif patch_type == 'INSERT':
|
|
234
|
-
content_start = 2 # File + Line
|
|
235
|
-
elif patch_type == 'NEW_FILE':
|
|
236
|
-
content_start = 1 # File
|
|
237
|
-
elif patch_type == 'MOVE_FILE':
|
|
238
|
-
content_start = 2 # File + NewPath
|
|
239
|
-
elif patch_type == 'REMOVE_FILE':
|
|
240
|
-
content_start = 1 # File
|
|
241
|
-
|
|
242
|
-
content_lines = lines[content_start:]
|
|
243
|
-
# 保留原始缩进和空行
|
|
244
|
-
content = '\n'.join(content_lines).rstrip('\n') + '\n' # 保留末尾换行
|
|
245
90
|
|
|
91
|
+
filepath = header_match.group(1)
|
|
92
|
+
start = int(header_match.group(2)) # 保持1-based行号
|
|
93
|
+
end = int(header_match.group(3)) + 1 if header_match.group(3) else start
|
|
94
|
+
|
|
95
|
+
# 存储参数
|
|
246
96
|
if filepath not in result:
|
|
247
97
|
result[filepath] = []
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
else:
|
|
257
|
-
result[filepath].append({
|
|
258
|
-
'type': patch_type,
|
|
259
|
-
'start_line': start_line,
|
|
260
|
-
'end_line': end_line,
|
|
261
|
-
'content': content
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
# Sort patches by start line in reverse order to apply from bottom to top
|
|
265
|
-
for filepath in result:
|
|
266
|
-
result[filepath].sort(key=lambda x: x.get('start_line', 0), reverse=True)
|
|
267
|
-
|
|
98
|
+
result[filepath].append({
|
|
99
|
+
'filepath': filepath,
|
|
100
|
+
'start': start,
|
|
101
|
+
'end': end,
|
|
102
|
+
'content': content # 保留原始内容(可能为空)
|
|
103
|
+
})
|
|
104
|
+
for filepath in result.keys():
|
|
105
|
+
result[filepath] = sorted(result[filepath], key=lambda x: x['start'], reverse=True)
|
|
268
106
|
return result
|
|
269
107
|
|
|
270
108
|
|
|
271
109
|
def apply_patch(output_str: str) -> str:
|
|
272
110
|
"""Apply patches to files"""
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
for patch in patch_info:
|
|
279
|
-
patch_type = patch['type']
|
|
280
|
-
|
|
281
|
-
if patch_type == 'MOVE_FILE':
|
|
282
|
-
handle_move_file(filepath, patch)
|
|
283
|
-
elif patch_type == 'NEW_FILE':
|
|
284
|
-
handle_new_file(filepath, patch)
|
|
285
|
-
elif patch_type == 'REMOVE_FILE':
|
|
286
|
-
handle_remove_file(filepath)
|
|
287
|
-
else:
|
|
288
|
-
handle_code_operation(filepath, patch)
|
|
289
|
-
|
|
290
|
-
except Exception as e:
|
|
291
|
-
PrettyOutput.print(f"应用 {patch_type} 操作到 {filepath} 失败: {str(e)}", OutputType.ERROR)
|
|
292
|
-
continue
|
|
111
|
+
try:
|
|
112
|
+
patches = _parse_patch(output_str)
|
|
113
|
+
except Exception as e:
|
|
114
|
+
PrettyOutput.print(f"解析补丁失败: {str(e)}", OutputType.ERROR)
|
|
115
|
+
return ""
|
|
293
116
|
|
|
117
|
+
ret = ""
|
|
118
|
+
|
|
119
|
+
for filepath, patch_list in patches.items():
|
|
120
|
+
for patch in patch_list:
|
|
121
|
+
try:
|
|
122
|
+
handle_code_operation(filepath, patch)
|
|
123
|
+
PrettyOutput.print(f"成功处理 操作", OutputType.SUCCESS)
|
|
124
|
+
except Exception as e:
|
|
125
|
+
PrettyOutput.print(f"操作失败: {str(e)}", OutputType.ERROR)
|
|
126
|
+
|
|
294
127
|
if has_uncommitted_changes():
|
|
295
128
|
diff = get_diff()
|
|
296
129
|
if handle_commit_workflow(diff):
|
|
@@ -308,15 +141,25 @@ def apply_patch(output_str: str) -> str:
|
|
|
308
141
|
if user_input:
|
|
309
142
|
ret += "\n" + user_input
|
|
310
143
|
else:
|
|
311
|
-
ret
|
|
144
|
+
ret = ""
|
|
312
145
|
|
|
313
146
|
return ret # Ensure a string is always returned
|
|
314
147
|
|
|
315
|
-
def get_diff()->str:
|
|
316
|
-
os.system
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
148
|
+
def get_diff() -> str:
|
|
149
|
+
"""使用更安全的subprocess代替os.system"""
|
|
150
|
+
import subprocess
|
|
151
|
+
try:
|
|
152
|
+
subprocess.run(['git', 'add', '.'], check=True)
|
|
153
|
+
result = subprocess.run(
|
|
154
|
+
['git', 'diff', 'HEAD'],
|
|
155
|
+
capture_output=True,
|
|
156
|
+
text=True,
|
|
157
|
+
check=True
|
|
158
|
+
)
|
|
159
|
+
return result.stdout
|
|
160
|
+
finally:
|
|
161
|
+
subprocess.run(['git', 'reset', 'HEAD'], check=True)
|
|
162
|
+
|
|
320
163
|
def handle_commit_workflow(diff:str)->bool:
|
|
321
164
|
"""Handle the git commit workflow and return the commit details.
|
|
322
165
|
|
|
@@ -365,82 +208,62 @@ def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
|
|
|
365
208
|
return result
|
|
366
209
|
# New handler functions below ▼▼▼
|
|
367
210
|
|
|
368
|
-
def handle_move_file(filepath: str, patch: Dict[str, Any]):
|
|
369
|
-
"""Handle file moving operation"""
|
|
370
|
-
new_path = patch['new_path']
|
|
371
|
-
os.makedirs(os.path.dirname(new_path), exist_ok=True)
|
|
372
|
-
if os.path.exists(filepath):
|
|
373
|
-
os.rename(filepath, new_path)
|
|
374
|
-
PrettyOutput.print(f"成功移动文件 {filepath} -> {new_path}", OutputType.SUCCESS)
|
|
375
|
-
else:
|
|
376
|
-
PrettyOutput.print(f"源文件不存在: {filepath}", OutputType.WARNING)
|
|
377
|
-
|
|
378
211
|
def handle_new_file(filepath: str, patch: Dict[str, Any]):
|
|
379
|
-
"""
|
|
380
|
-
new_content = patch.get('content', '').splitlines(keepends=True)
|
|
381
|
-
if new_content and new_content[-1] and new_content[-1][-1] != '\n':
|
|
382
|
-
new_content[-1] += '\n'
|
|
383
|
-
|
|
212
|
+
"""统一参数格式处理新文件"""
|
|
384
213
|
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
|
385
214
|
with open(filepath, 'w', encoding='utf-8') as f:
|
|
386
|
-
f.
|
|
387
|
-
PrettyOutput.print(f"成功创建新文件 {filepath}", OutputType.SUCCESS)
|
|
388
|
-
|
|
389
|
-
def handle_remove_file(filepath: str):
|
|
390
|
-
"""Handle file removal"""
|
|
391
|
-
if os.path.exists(filepath):
|
|
392
|
-
os.remove(filepath)
|
|
393
|
-
PrettyOutput.print(f"成功删除文件 {filepath}", OutputType.SUCCESS)
|
|
394
|
-
else:
|
|
395
|
-
PrettyOutput.print(f"文件不存在: {filepath}", OutputType.WARNING)
|
|
215
|
+
f.write(patch['content'])
|
|
396
216
|
|
|
397
217
|
def handle_code_operation(filepath: str, patch: Dict[str, Any]):
|
|
398
|
-
"""
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
218
|
+
"""处理紧凑格式补丁"""
|
|
219
|
+
try:
|
|
220
|
+
# 新建文件时强制覆盖
|
|
221
|
+
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
|
222
|
+
if not os.path.exists(filepath):
|
|
223
|
+
open(filepath, 'w', encoding='utf-8').close()
|
|
224
|
+
with open(filepath, 'r+', encoding='utf-8') as f:
|
|
225
|
+
lines = f.readlines()
|
|
226
|
+
|
|
227
|
+
new_lines = validate_and_apply_changes(
|
|
228
|
+
lines,
|
|
229
|
+
patch['start'],
|
|
230
|
+
patch['end'],
|
|
231
|
+
patch['content']
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
f.seek(0)
|
|
235
|
+
f.writelines(new_lines)
|
|
236
|
+
f.truncate()
|
|
415
237
|
|
|
416
|
-
|
|
417
|
-
lines = f.readlines()
|
|
418
|
-
validate_and_apply_changes(patch_type, lines, start_line, end_line, new_content)
|
|
419
|
-
f.seek(0)
|
|
420
|
-
f.writelines(lines)
|
|
421
|
-
f.truncate()
|
|
238
|
+
PrettyOutput.print(f"成功更新 {filepath}", OutputType.SUCCESS)
|
|
422
239
|
|
|
423
|
-
|
|
240
|
+
except Exception as e:
|
|
241
|
+
PrettyOutput.print(f"操作失败: {str(e)}", OutputType.ERROR)
|
|
424
242
|
|
|
425
243
|
def validate_and_apply_changes(
|
|
426
|
-
patch_type: str,
|
|
427
244
|
lines: List[str],
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
):
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
245
|
+
start: int,
|
|
246
|
+
end: int,
|
|
247
|
+
content: str
|
|
248
|
+
) -> List[str]:
|
|
249
|
+
|
|
250
|
+
new_content = content.splitlines(keepends=True)
|
|
251
|
+
|
|
252
|
+
# 插入操作处理
|
|
253
|
+
if start == end:
|
|
254
|
+
if start < 1 or start > len(lines)+1:
|
|
255
|
+
raise ValueError(f"无效插入位置: {start}")
|
|
256
|
+
# 在指定位置前插入
|
|
257
|
+
return lines[:start-1] + new_content + lines[start-1:]
|
|
258
|
+
|
|
259
|
+
# 范围替换/删除操作
|
|
260
|
+
if start > end:
|
|
261
|
+
raise ValueError(f"起始行{start}不能大于结束行{end}")
|
|
262
|
+
|
|
263
|
+
max_line = len(lines)
|
|
264
|
+
# 自动修正行号范围
|
|
265
|
+
start = max(1, min(start, max_line+1))
|
|
266
|
+
end = max(start, min(end, max_line+1))
|
|
267
|
+
|
|
268
|
+
# 执行替换
|
|
269
|
+
return lines[:start-1] + new_content + lines[end-1:]
|
|
@@ -60,14 +60,12 @@ Identify customization options:
|
|
|
60
60
|
- "Should we create a new class?"
|
|
61
61
|
|
|
62
62
|
# 🎨 Question Template
|
|
63
|
-
|
|
63
|
+
3-5 specific questions about existing implementations:
|
|
64
64
|
<QUESTION>
|
|
65
|
-
[3-5 specific questions about existing implementations:
|
|
66
65
|
1. System architecture question
|
|
67
66
|
2. Implementation details question
|
|
68
|
-
3. Integration or extension question
|
|
67
|
+
3. Integration or extension question
|
|
69
68
|
</QUESTION>
|
|
70
|
-
```
|
|
71
69
|
|
|
72
70
|
# 🔎 Investigation Focus
|
|
73
71
|
1. Current System
|
jarvis/jarvis_platform/kimi.py
CHANGED
|
@@ -57,9 +57,6 @@ class FileOperationTool:
|
|
|
57
57
|
content = open(abs_path, 'r', encoding='utf-8').read()
|
|
58
58
|
output = f"File: {abs_path}\n{content}"
|
|
59
59
|
|
|
60
|
-
# Print file content
|
|
61
|
-
PrettyOutput.print(f"读取文件: {abs_path}\n{content}", OutputType.INFO)
|
|
62
|
-
|
|
63
60
|
return {
|
|
64
61
|
"success": True,
|
|
65
62
|
"stdout": output,
|