(args: EditInput, safePath: string)
| 93 | } |
| 94 | |
| 95 | private async execution(args: EditInput, safePath: string): Promise<ExecutableToolResult> { |
| 96 | if (args.old_string === args.new_string) { |
| 97 | return { |
| 98 | isError: true, |
| 99 | output: 'No changes to make: old_string and new_string are exactly the same.', |
| 100 | }; |
| 101 | } |
| 102 | |
| 103 | try { |
| 104 | const raw = await this.kaos.readText(safePath); |
| 105 | const modelView = toModelTextView(raw); |
| 106 | const content = modelView.text; |
| 107 | const replaceAll = args.replace_all ?? false; |
| 108 | |
| 109 | if (!replaceAll) { |
| 110 | let count = 0; |
| 111 | let pos = 0; |
| 112 | while (pos < content.length) { |
| 113 | const idx = content.indexOf(args.old_string, pos); |
| 114 | if (idx === -1) break; |
| 115 | count++; |
| 116 | pos = idx + args.old_string.length; |
| 117 | } |
| 118 | |
| 119 | if (count === 0) { |
| 120 | return { isError: true, output: `old_string not found in ${args.path}, the file contents may be out of date. Please use the Read Tool to reload the content. |
| 121 | ` }; |
| 122 | } |
| 123 | if (count > 1) { |
| 124 | return { |
| 125 | isError: true, |
| 126 | output: |
| 127 | `old_string is not unique in ${args.path} (found ${String(count)} occurrences). ` + |
| 128 | 'To replace every occurrence, set replace_all=true. To replace only one occurrence, include more surrounding context in old_string.', |
| 129 | }; |
| 130 | } |
| 131 | |
| 132 | const newContent = replaceOnceLiteral(content, args.old_string, args.new_string); |
| 133 | await this.kaos.writeText( |
| 134 | safePath, |
| 135 | materializeModelText(newContent, modelView.lineEndingStyle), |
| 136 | ); |
| 137 | return { output: `Replaced 1 occurrence in ${args.path}` }; |
| 138 | } |
| 139 | |
| 140 | const parts = content.split(args.old_string); |
| 141 | const replacementCount = parts.length - 1; |
| 142 | if (replacementCount === 0) { |
| 143 | return { isError: true, output: `old_string not found in ${args.path}, the file contents may be out of date. Please use the Read Tool to reload the content. |
| 144 | ` }; |
| 145 | } |
| 146 | |
| 147 | const newContent = parts.join(args.new_string); |
| 148 | await this.kaos.writeText( |
| 149 | safePath, |
| 150 | materializeModelText(newContent, modelView.lineEndingStyle), |
| 151 | ); |
| 152 | return { output: `Replaced ${String(replacementCount)} occurrences in ${args.path}` }; |
no test coverage detected