@shareai-lab/kode 1.1.14 → 1.1.16-dev.2

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.
Files changed (289) hide show
  1. package/cli.js +77 -82
  2. package/dist/entrypoints/cli.js +59 -38
  3. package/dist/entrypoints/cli.js.map +3 -3
  4. package/dist/index.js +5 -26
  5. package/dist/package.json +4 -1
  6. package/package.json +11 -104
  7. package/dist/test/testAdapters.js +0 -88
  8. package/dist/test/testAdapters.js.map +0 -1
  9. package/src/ProjectOnboarding.tsx +0 -198
  10. package/src/Tool.ts +0 -83
  11. package/src/commands/agents.tsx +0 -3416
  12. package/src/commands/approvedTools.ts +0 -53
  13. package/src/commands/bug.tsx +0 -20
  14. package/src/commands/clear.ts +0 -43
  15. package/src/commands/compact.ts +0 -120
  16. package/src/commands/config.tsx +0 -19
  17. package/src/commands/cost.ts +0 -18
  18. package/src/commands/ctx_viz.ts +0 -209
  19. package/src/commands/doctor.ts +0 -24
  20. package/src/commands/help.tsx +0 -19
  21. package/src/commands/init.ts +0 -37
  22. package/src/commands/listen.ts +0 -42
  23. package/src/commands/login.tsx +0 -51
  24. package/src/commands/logout.tsx +0 -40
  25. package/src/commands/mcp.ts +0 -41
  26. package/src/commands/model.tsx +0 -40
  27. package/src/commands/modelstatus.tsx +0 -20
  28. package/src/commands/onboarding.tsx +0 -34
  29. package/src/commands/pr_comments.ts +0 -59
  30. package/src/commands/refreshCommands.ts +0 -54
  31. package/src/commands/release-notes.ts +0 -34
  32. package/src/commands/resume.tsx +0 -31
  33. package/src/commands/review.ts +0 -49
  34. package/src/commands/terminalSetup.ts +0 -221
  35. package/src/commands.ts +0 -139
  36. package/src/components/ApproveApiKey.tsx +0 -93
  37. package/src/components/AsciiLogo.tsx +0 -13
  38. package/src/components/AutoUpdater.tsx +0 -148
  39. package/src/components/Bug.tsx +0 -367
  40. package/src/components/Config.tsx +0 -293
  41. package/src/components/ConsoleOAuthFlow.tsx +0 -327
  42. package/src/components/Cost.tsx +0 -23
  43. package/src/components/CostThresholdDialog.tsx +0 -46
  44. package/src/components/CustomSelect/option-map.ts +0 -42
  45. package/src/components/CustomSelect/select-option.tsx +0 -78
  46. package/src/components/CustomSelect/select.tsx +0 -152
  47. package/src/components/CustomSelect/theme.ts +0 -45
  48. package/src/components/CustomSelect/use-select-state.ts +0 -414
  49. package/src/components/CustomSelect/use-select.ts +0 -35
  50. package/src/components/FallbackToolUseRejectedMessage.tsx +0 -15
  51. package/src/components/FileEditToolUpdatedMessage.tsx +0 -66
  52. package/src/components/Help.tsx +0 -215
  53. package/src/components/HighlightedCode.tsx +0 -33
  54. package/src/components/InvalidConfigDialog.tsx +0 -113
  55. package/src/components/Link.tsx +0 -32
  56. package/src/components/LogSelector.tsx +0 -86
  57. package/src/components/Logo.tsx +0 -170
  58. package/src/components/MCPServerApprovalDialog.tsx +0 -100
  59. package/src/components/MCPServerDialogCopy.tsx +0 -25
  60. package/src/components/MCPServerMultiselectDialog.tsx +0 -109
  61. package/src/components/Message.tsx +0 -221
  62. package/src/components/MessageResponse.tsx +0 -15
  63. package/src/components/MessageSelector.tsx +0 -211
  64. package/src/components/ModeIndicator.tsx +0 -88
  65. package/src/components/ModelConfig.tsx +0 -301
  66. package/src/components/ModelListManager.tsx +0 -227
  67. package/src/components/ModelSelector.tsx +0 -3387
  68. package/src/components/ModelStatusDisplay.tsx +0 -230
  69. package/src/components/Onboarding.tsx +0 -274
  70. package/src/components/PressEnterToContinue.tsx +0 -11
  71. package/src/components/PromptInput.tsx +0 -760
  72. package/src/components/SentryErrorBoundary.ts +0 -39
  73. package/src/components/Spinner.tsx +0 -129
  74. package/src/components/StickerRequestForm.tsx +0 -16
  75. package/src/components/StructuredDiff.tsx +0 -191
  76. package/src/components/TextInput.tsx +0 -259
  77. package/src/components/TodoItem.tsx +0 -47
  78. package/src/components/TokenWarning.tsx +0 -31
  79. package/src/components/ToolUseLoader.tsx +0 -40
  80. package/src/components/TrustDialog.tsx +0 -106
  81. package/src/components/binary-feedback/BinaryFeedback.tsx +0 -63
  82. package/src/components/binary-feedback/BinaryFeedbackOption.tsx +0 -111
  83. package/src/components/binary-feedback/BinaryFeedbackView.tsx +0 -172
  84. package/src/components/binary-feedback/utils.ts +0 -220
  85. package/src/components/messages/AssistantBashOutputMessage.tsx +0 -22
  86. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +0 -49
  87. package/src/components/messages/AssistantRedactedThinkingMessage.tsx +0 -19
  88. package/src/components/messages/AssistantTextMessage.tsx +0 -144
  89. package/src/components/messages/AssistantThinkingMessage.tsx +0 -40
  90. package/src/components/messages/AssistantToolUseMessage.tsx +0 -132
  91. package/src/components/messages/TaskProgressMessage.tsx +0 -32
  92. package/src/components/messages/TaskToolMessage.tsx +0 -58
  93. package/src/components/messages/UserBashInputMessage.tsx +0 -28
  94. package/src/components/messages/UserCommandMessage.tsx +0 -30
  95. package/src/components/messages/UserKodingInputMessage.tsx +0 -28
  96. package/src/components/messages/UserPromptMessage.tsx +0 -35
  97. package/src/components/messages/UserTextMessage.tsx +0 -39
  98. package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +0 -12
  99. package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +0 -36
  100. package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +0 -31
  101. package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +0 -57
  102. package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +0 -35
  103. package/src/components/messages/UserToolResultMessage/utils.tsx +0 -56
  104. package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +0 -121
  105. package/src/components/permissions/FallbackPermissionRequest.tsx +0 -153
  106. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +0 -182
  107. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +0 -77
  108. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +0 -164
  109. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +0 -83
  110. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +0 -240
  111. package/src/components/permissions/PermissionRequest.tsx +0 -101
  112. package/src/components/permissions/PermissionRequestTitle.tsx +0 -69
  113. package/src/components/permissions/hooks.ts +0 -44
  114. package/src/components/permissions/toolUseOptions.ts +0 -59
  115. package/src/components/permissions/utils.ts +0 -23
  116. package/src/constants/betas.ts +0 -5
  117. package/src/constants/claude-asterisk-ascii-art.tsx +0 -238
  118. package/src/constants/figures.ts +0 -4
  119. package/src/constants/keys.ts +0 -3
  120. package/src/constants/macros.ts +0 -11
  121. package/src/constants/modelCapabilities.ts +0 -179
  122. package/src/constants/models.ts +0 -1025
  123. package/src/constants/oauth.ts +0 -18
  124. package/src/constants/product.ts +0 -17
  125. package/src/constants/prompts.ts +0 -168
  126. package/src/constants/releaseNotes.ts +0 -7
  127. package/src/context/PermissionContext.tsx +0 -149
  128. package/src/context.ts +0 -278
  129. package/src/cost-tracker.ts +0 -84
  130. package/src/entrypoints/cli.tsx +0 -1561
  131. package/src/entrypoints/mcp.ts +0 -175
  132. package/src/history.ts +0 -25
  133. package/src/hooks/useApiKeyVerification.ts +0 -59
  134. package/src/hooks/useArrowKeyHistory.ts +0 -55
  135. package/src/hooks/useCanUseTool.ts +0 -138
  136. package/src/hooks/useCancelRequest.ts +0 -39
  137. package/src/hooks/useDoublePress.ts +0 -41
  138. package/src/hooks/useExitOnCtrlCD.ts +0 -31
  139. package/src/hooks/useInterval.ts +0 -25
  140. package/src/hooks/useLogMessages.ts +0 -16
  141. package/src/hooks/useLogStartupTime.ts +0 -12
  142. package/src/hooks/useNotifyAfterTimeout.ts +0 -65
  143. package/src/hooks/usePermissionRequestLogging.ts +0 -44
  144. package/src/hooks/useTerminalSize.ts +0 -49
  145. package/src/hooks/useTextInput.ts +0 -317
  146. package/src/hooks/useUnifiedCompletion.ts +0 -1405
  147. package/src/index.ts +0 -34
  148. package/src/messages.ts +0 -38
  149. package/src/permissions.ts +0 -268
  150. package/src/query.ts +0 -720
  151. package/src/screens/ConfigureNpmPrefix.tsx +0 -197
  152. package/src/screens/Doctor.tsx +0 -219
  153. package/src/screens/LogList.tsx +0 -68
  154. package/src/screens/REPL.tsx +0 -813
  155. package/src/screens/ResumeConversation.tsx +0 -68
  156. package/src/services/adapters/base.ts +0 -38
  157. package/src/services/adapters/chatCompletions.ts +0 -90
  158. package/src/services/adapters/responsesAPI.ts +0 -170
  159. package/src/services/browserMocks.ts +0 -66
  160. package/src/services/claude.ts +0 -2197
  161. package/src/services/customCommands.ts +0 -704
  162. package/src/services/fileFreshness.ts +0 -377
  163. package/src/services/gpt5ConnectionTest.ts +0 -340
  164. package/src/services/mcpClient.ts +0 -564
  165. package/src/services/mcpServerApproval.tsx +0 -50
  166. package/src/services/mentionProcessor.ts +0 -273
  167. package/src/services/modelAdapterFactory.ts +0 -69
  168. package/src/services/notifier.ts +0 -40
  169. package/src/services/oauth.ts +0 -357
  170. package/src/services/openai.ts +0 -1359
  171. package/src/services/responseStateManager.ts +0 -90
  172. package/src/services/sentry.ts +0 -3
  173. package/src/services/statsig.ts +0 -172
  174. package/src/services/statsigStorage.ts +0 -86
  175. package/src/services/systemReminder.ts +0 -507
  176. package/src/services/vcr.ts +0 -161
  177. package/src/test/testAdapters.ts +0 -96
  178. package/src/tools/ArchitectTool/ArchitectTool.tsx +0 -135
  179. package/src/tools/ArchitectTool/prompt.ts +0 -15
  180. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +0 -576
  181. package/src/tools/BashTool/BashTool.tsx +0 -243
  182. package/src/tools/BashTool/BashToolResultMessage.tsx +0 -38
  183. package/src/tools/BashTool/OutputLine.tsx +0 -49
  184. package/src/tools/BashTool/prompt.ts +0 -174
  185. package/src/tools/BashTool/utils.ts +0 -56
  186. package/src/tools/FileEditTool/FileEditTool.tsx +0 -319
  187. package/src/tools/FileEditTool/prompt.ts +0 -51
  188. package/src/tools/FileEditTool/utils.ts +0 -58
  189. package/src/tools/FileReadTool/FileReadTool.tsx +0 -404
  190. package/src/tools/FileReadTool/prompt.ts +0 -7
  191. package/src/tools/FileWriteTool/FileWriteTool.tsx +0 -301
  192. package/src/tools/FileWriteTool/prompt.ts +0 -10
  193. package/src/tools/GlobTool/GlobTool.tsx +0 -119
  194. package/src/tools/GlobTool/prompt.ts +0 -8
  195. package/src/tools/GrepTool/GrepTool.tsx +0 -147
  196. package/src/tools/GrepTool/prompt.ts +0 -11
  197. package/src/tools/MCPTool/MCPTool.tsx +0 -107
  198. package/src/tools/MCPTool/prompt.ts +0 -3
  199. package/src/tools/MemoryReadTool/MemoryReadTool.tsx +0 -127
  200. package/src/tools/MemoryReadTool/prompt.ts +0 -3
  201. package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +0 -89
  202. package/src/tools/MemoryWriteTool/prompt.ts +0 -3
  203. package/src/tools/MultiEditTool/MultiEditTool.tsx +0 -388
  204. package/src/tools/MultiEditTool/prompt.ts +0 -45
  205. package/src/tools/NotebookEditTool/NotebookEditTool.tsx +0 -298
  206. package/src/tools/NotebookEditTool/prompt.ts +0 -3
  207. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +0 -258
  208. package/src/tools/NotebookReadTool/prompt.ts +0 -3
  209. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +0 -107
  210. package/src/tools/StickerRequestTool/prompt.ts +0 -19
  211. package/src/tools/TaskTool/TaskTool.tsx +0 -438
  212. package/src/tools/TaskTool/constants.ts +0 -1
  213. package/src/tools/TaskTool/prompt.ts +0 -92
  214. package/src/tools/ThinkTool/ThinkTool.tsx +0 -54
  215. package/src/tools/ThinkTool/prompt.ts +0 -12
  216. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +0 -313
  217. package/src/tools/TodoWriteTool/prompt.ts +0 -63
  218. package/src/tools/URLFetcherTool/URLFetcherTool.tsx +0 -178
  219. package/src/tools/URLFetcherTool/cache.ts +0 -55
  220. package/src/tools/URLFetcherTool/htmlToMarkdown.ts +0 -55
  221. package/src/tools/URLFetcherTool/prompt.ts +0 -17
  222. package/src/tools/WebSearchTool/WebSearchTool.tsx +0 -103
  223. package/src/tools/WebSearchTool/prompt.ts +0 -13
  224. package/src/tools/WebSearchTool/searchProviders.ts +0 -66
  225. package/src/tools/lsTool/lsTool.tsx +0 -272
  226. package/src/tools/lsTool/prompt.ts +0 -2
  227. package/src/tools.ts +0 -67
  228. package/src/types/PermissionMode.ts +0 -120
  229. package/src/types/RequestContext.ts +0 -72
  230. package/src/types/common.d.ts +0 -2
  231. package/src/types/conversation.ts +0 -51
  232. package/src/types/logs.ts +0 -58
  233. package/src/types/modelCapabilities.ts +0 -64
  234. package/src/types/notebook.ts +0 -87
  235. package/src/utils/Cursor.ts +0 -436
  236. package/src/utils/PersistentShell.ts +0 -552
  237. package/src/utils/advancedFuzzyMatcher.ts +0 -290
  238. package/src/utils/agentLoader.ts +0 -278
  239. package/src/utils/agentStorage.ts +0 -97
  240. package/src/utils/array.ts +0 -3
  241. package/src/utils/ask.tsx +0 -99
  242. package/src/utils/auth.ts +0 -13
  243. package/src/utils/autoCompactCore.ts +0 -223
  244. package/src/utils/autoUpdater.ts +0 -458
  245. package/src/utils/betas.ts +0 -20
  246. package/src/utils/browser.ts +0 -14
  247. package/src/utils/cleanup.ts +0 -72
  248. package/src/utils/commands.ts +0 -261
  249. package/src/utils/commonUnixCommands.ts +0 -161
  250. package/src/utils/config.ts +0 -945
  251. package/src/utils/conversationRecovery.ts +0 -55
  252. package/src/utils/debugLogger.ts +0 -1235
  253. package/src/utils/diff.ts +0 -42
  254. package/src/utils/env.ts +0 -57
  255. package/src/utils/errors.ts +0 -21
  256. package/src/utils/exampleCommands.ts +0 -109
  257. package/src/utils/execFileNoThrow.ts +0 -51
  258. package/src/utils/expertChatStorage.ts +0 -136
  259. package/src/utils/file.ts +0 -405
  260. package/src/utils/fileRecoveryCore.ts +0 -71
  261. package/src/utils/format.tsx +0 -44
  262. package/src/utils/fuzzyMatcher.ts +0 -328
  263. package/src/utils/generators.ts +0 -62
  264. package/src/utils/git.ts +0 -92
  265. package/src/utils/globalLogger.ts +0 -77
  266. package/src/utils/http.ts +0 -10
  267. package/src/utils/imagePaste.ts +0 -38
  268. package/src/utils/json.ts +0 -13
  269. package/src/utils/log.ts +0 -382
  270. package/src/utils/markdown.ts +0 -213
  271. package/src/utils/messageContextManager.ts +0 -294
  272. package/src/utils/messages.tsx +0 -945
  273. package/src/utils/model.ts +0 -914
  274. package/src/utils/permissions/filesystem.ts +0 -127
  275. package/src/utils/responseState.ts +0 -23
  276. package/src/utils/ripgrep.ts +0 -167
  277. package/src/utils/secureFile.ts +0 -564
  278. package/src/utils/sessionState.ts +0 -49
  279. package/src/utils/state.ts +0 -25
  280. package/src/utils/style.ts +0 -29
  281. package/src/utils/terminal.ts +0 -50
  282. package/src/utils/theme.ts +0 -127
  283. package/src/utils/thinking.ts +0 -144
  284. package/src/utils/todoStorage.ts +0 -431
  285. package/src/utils/tokens.ts +0 -43
  286. package/src/utils/toolExecutionController.ts +0 -163
  287. package/src/utils/unaryLogging.ts +0 -26
  288. package/src/utils/user.ts +0 -37
  289. package/src/utils/validate.ts +0 -165
@@ -1,388 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, statSync } from 'fs'
2
- import { Box, Text } from 'ink'
3
- import { dirname, isAbsolute, relative, resolve, sep } from 'path'
4
- import * as React from 'react'
5
- import { z } from 'zod'
6
- import { FileEditToolUpdatedMessage } from '../../components/FileEditToolUpdatedMessage'
7
- import { StructuredDiff } from '../../components/StructuredDiff'
8
- import { logEvent } from '../../services/statsig'
9
- import { Tool, ValidationResult } from '../../Tool'
10
- import { intersperse } from '../../utils/array'
11
- import {
12
- addLineNumbers,
13
- detectFileEncoding,
14
- detectLineEndings,
15
- findSimilarFile,
16
- writeTextContent,
17
- } from '../../utils/file.js'
18
- import { logError } from '../../utils/log'
19
- import { getCwd } from '../../utils/state'
20
- import { getTheme } from '../../utils/theme'
21
- import { NotebookEditTool } from '../NotebookEditTool/NotebookEditTool'
22
- // Local content-based edit function for MultiEditTool
23
- function applyContentEdit(
24
- content: string,
25
- oldString: string,
26
- newString: string,
27
- replaceAll: boolean = false
28
- ): { newContent: string; occurrences: number } {
29
- if (replaceAll) {
30
- const regex = new RegExp(oldString.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g')
31
- const matches = content.match(regex)
32
- const occurrences = matches ? matches.length : 0
33
- const newContent = content.replace(regex, newString)
34
- return { newContent, occurrences }
35
- } else {
36
- if (content.includes(oldString)) {
37
- const newContent = content.replace(oldString, newString)
38
- return { newContent, occurrences: 1 }
39
- } else {
40
- throw new Error(`String not found: ${oldString.substring(0, 50)}...`)
41
- }
42
- }
43
- }
44
- import { hasWritePermission } from '../../utils/permissions/filesystem'
45
- import { PROJECT_FILE } from '../../constants/product'
46
- import { DESCRIPTION, PROMPT } from './prompt'
47
- import { emitReminderEvent } from '../../services/systemReminder'
48
- import { recordFileEdit } from '../../services/fileFreshness'
49
-
50
- const EditSchema = z.object({
51
- old_string: z.string().describe('The text to replace'),
52
- new_string: z.string().describe('The text to replace it with'),
53
- replace_all: z
54
- .boolean()
55
- .optional()
56
- .default(false)
57
- .describe('Replace all occurences of old_string (default false)'),
58
- })
59
-
60
- const inputSchema = z.strictObject({
61
- file_path: z.string().describe('The absolute path to the file to modify'),
62
- edits: z
63
- .array(EditSchema)
64
- .min(1)
65
- .describe('Array of edit operations to perform sequentially on the file'),
66
- })
67
-
68
- export type In = typeof inputSchema
69
-
70
- // Number of lines of context to include before/after the change in our result message
71
- const N_LINES_SNIPPET = 4
72
-
73
- export const MultiEditTool = {
74
- name: 'MultiEdit',
75
- async description() {
76
- return 'A tool for making multiple edits to a single file atomically'
77
- },
78
- async prompt() {
79
- return PROMPT
80
- },
81
- inputSchema,
82
- userFacingName() {
83
- return 'Multi-Edit'
84
- },
85
- async isEnabled() {
86
- return true
87
- },
88
- isReadOnly() {
89
- return false
90
- },
91
- isConcurrencySafe() {
92
- return false // MultiEdit modifies files, not safe for concurrent execution
93
- },
94
- needsPermissions(input?: z.infer<typeof inputSchema>) {
95
- if (!input) return true
96
- return !hasWritePermission(input.file_path)
97
- },
98
- renderResultForAssistant(content) {
99
- return content
100
- },
101
- renderToolUseMessage(input, { verbose }) {
102
- const { file_path, edits } = input
103
- const workingDir = getCwd()
104
- const relativePath = isAbsolute(file_path)
105
- ? relative(workingDir, file_path)
106
- : file_path
107
-
108
- if (verbose) {
109
- const editSummary = edits
110
- .map(
111
- (edit, index) =>
112
- `${index + 1}. Replace "${edit.old_string.substring(0, 50)}${edit.old_string.length > 50 ? '...' : ''}" with "${edit.new_string.substring(0, 50)}${edit.new_string.length > 50 ? '...' : ''}"`,
113
- )
114
- .join('\n')
115
- return `Multiple edits to ${relativePath}:\n${editSummary}`
116
- }
117
-
118
- return `Making ${edits.length} edits to ${relativePath}`
119
- },
120
- renderToolUseRejectedMessage() {
121
- return (
122
- <Box>
123
- <Text color={getTheme().error}>⚠ Edit request rejected</Text>
124
- </Box>
125
- )
126
- },
127
- renderToolResultMessage(output) {
128
- if (typeof output === 'string') {
129
- const isError = output.includes('Error:')
130
- return (
131
- <Box flexDirection="column">
132
- <Text color={isError ? getTheme().error : getTheme().success}>
133
- {output}
134
- </Text>
135
- </Box>
136
- )
137
- }
138
-
139
- return <FileEditToolUpdatedMessage {...output} />
140
- },
141
- async validateInput(
142
- { file_path, edits }: z.infer<typeof inputSchema>,
143
- context?: { readFileTimestamps?: Record<string, number> },
144
- ): Promise<ValidationResult> {
145
- const workingDir = getCwd()
146
- const normalizedPath = isAbsolute(file_path)
147
- ? resolve(file_path)
148
- : resolve(workingDir, file_path)
149
-
150
- // Check if it's a notebook file
151
- if (normalizedPath.endsWith('.ipynb')) {
152
- return {
153
- result: false,
154
- errorCode: 1,
155
- message: `For Jupyter notebooks (.ipynb files), use the ${NotebookEditTool.name} tool instead.`,
156
- }
157
- }
158
-
159
- // For new files, check parent directory exists
160
- if (!existsSync(normalizedPath)) {
161
- const parentDir = dirname(normalizedPath)
162
- if (!existsSync(parentDir)) {
163
- return {
164
- result: false,
165
- errorCode: 2,
166
- message: `Parent directory does not exist: ${parentDir}`,
167
- }
168
- }
169
-
170
- // For new files, ensure first edit creates the file (empty old_string)
171
- if (edits.length === 0 || edits[0].old_string !== '') {
172
- return {
173
- result: false,
174
- errorCode: 6,
175
- message:
176
- 'For new files, the first edit must have an empty old_string to create the file content.',
177
- }
178
- }
179
- } else {
180
- // For existing files, apply file protection mechanisms
181
- const readFileTimestamps = context?.readFileTimestamps || {}
182
- const readTimestamp = readFileTimestamps[normalizedPath]
183
-
184
- if (!readTimestamp) {
185
- return {
186
- result: false,
187
- errorCode: 7,
188
- message:
189
- 'File has not been read yet. Read it first before editing it.',
190
- meta: {
191
- filePath: normalizedPath,
192
- isFilePathAbsolute: String(isAbsolute(file_path)),
193
- },
194
- }
195
- }
196
-
197
- // Check if file has been modified since last read
198
- const stats = statSync(normalizedPath)
199
- const lastWriteTime = stats.mtimeMs
200
- if (lastWriteTime > readTimestamp) {
201
- return {
202
- result: false,
203
- errorCode: 8,
204
- message:
205
- 'File has been modified since read, either by the user or by a linter. Read it again before attempting to edit it.',
206
- meta: {
207
- filePath: normalizedPath,
208
- lastWriteTime,
209
- readTimestamp,
210
- },
211
- }
212
- }
213
-
214
- // Pre-validate that all old_strings exist in the file
215
- const encoding = detectFileEncoding(normalizedPath)
216
- if (encoding === 'binary') {
217
- return {
218
- result: false,
219
- errorCode: 9,
220
- message: 'Cannot edit binary files.',
221
- }
222
- }
223
-
224
- const currentContent = readFileSync(normalizedPath, 'utf-8')
225
- for (let i = 0; i < edits.length; i++) {
226
- const edit = edits[i]
227
- if (
228
- edit.old_string !== '' &&
229
- !currentContent.includes(edit.old_string)
230
- ) {
231
- return {
232
- result: false,
233
- errorCode: 10,
234
- message: `Edit ${i + 1}: String to replace not found in file: "${edit.old_string.substring(0, 100)}${edit.old_string.length > 100 ? '...' : ''}"`,
235
- meta: {
236
- editIndex: i + 1,
237
- oldString: edit.old_string.substring(0, 200),
238
- },
239
- }
240
- }
241
- }
242
- }
243
-
244
- // Validate each edit
245
- for (let i = 0; i < edits.length; i++) {
246
- const edit = edits[i]
247
- if (edit.old_string === edit.new_string) {
248
- return {
249
- result: false,
250
- errorCode: 3,
251
- message: `Edit ${i + 1}: old_string and new_string cannot be the same`,
252
- }
253
- }
254
- }
255
-
256
- return { result: true }
257
- },
258
- async *call({ file_path, edits }, { readFileTimestamps }) {
259
- const startTime = Date.now()
260
- const workingDir = getCwd()
261
- const filePath = isAbsolute(file_path)
262
- ? resolve(file_path)
263
- : resolve(workingDir, file_path)
264
-
265
- try {
266
- // Read current file content (or empty for new files)
267
- let currentContent = ''
268
- let fileExists = existsSync(filePath)
269
-
270
- if (fileExists) {
271
- const encoding = detectFileEncoding(filePath)
272
- if (encoding === 'binary') {
273
- yield {
274
- type: 'result',
275
- data: 'Error: Cannot edit binary files',
276
- resultForAssistant: 'Error: Cannot edit binary files',
277
- }
278
- return
279
- }
280
- currentContent = readFileSync(filePath, 'utf-8')
281
- } else {
282
- // For new files, ensure parent directory exists
283
- const parentDir = dirname(filePath)
284
- if (!existsSync(parentDir)) {
285
- mkdirSync(parentDir, { recursive: true })
286
- }
287
- }
288
-
289
- // Apply all edits sequentially
290
- let modifiedContent = currentContent
291
- const appliedEdits = []
292
-
293
- for (let i = 0; i < edits.length; i++) {
294
- const edit = edits[i]
295
- const { old_string, new_string, replace_all } = edit
296
-
297
- try {
298
- const result = applyContentEdit(
299
- modifiedContent,
300
- old_string,
301
- new_string,
302
- replace_all,
303
- )
304
- modifiedContent = result.newContent
305
- appliedEdits.push({
306
- editIndex: i + 1,
307
- success: true,
308
- old_string: old_string.substring(0, 100),
309
- new_string: new_string.substring(0, 100),
310
- occurrences: result.occurrences,
311
- })
312
- } catch (error) {
313
- // If any edit fails, abort the entire operation
314
- const errorMessage =
315
- error instanceof Error ? error.message : 'Unknown error'
316
- yield {
317
- type: 'result',
318
- data: `Error in edit ${i + 1}: ${errorMessage}`,
319
- resultForAssistant: `Error in edit ${i + 1}: ${errorMessage}`,
320
- }
321
- return
322
- }
323
- }
324
-
325
- // Write the modified content
326
- const lineEndings = fileExists ? detectLineEndings(currentContent) : 'LF'
327
- const encoding = fileExists ? detectFileEncoding(filePath) : 'utf8'
328
- writeTextContent(filePath, modifiedContent, encoding, lineEndings)
329
-
330
- // Record Agent edit operation for file freshness tracking
331
- recordFileEdit(filePath, modifiedContent)
332
-
333
- // Update readFileTimestamps to prevent stale file warnings
334
- readFileTimestamps[filePath] = Date.now()
335
-
336
- // Emit file edited event for system reminders
337
- emitReminderEvent('file:edited', {
338
- filePath,
339
- edits: edits.map(e => ({
340
- oldString: e.old_string,
341
- newString: e.new_string,
342
- })),
343
- originalContent: currentContent,
344
- newContent: modifiedContent,
345
- timestamp: Date.now(),
346
- operation: fileExists ? 'update' : 'create',
347
- })
348
-
349
- // Generate result data
350
- const relativePath = relative(workingDir, filePath)
351
- const summary = `Successfully applied ${edits.length} edits to ${relativePath}`
352
-
353
- const resultData = {
354
- filePath: relativePath,
355
- wasNewFile: !fileExists,
356
- editsApplied: appliedEdits,
357
- totalEdits: edits.length,
358
- summary,
359
- }
360
-
361
- // Log the operation
362
- logEvent('multi_edit_tool_used', {
363
- file_path: relativePath,
364
- edits_count: String(edits.length),
365
- was_new_file: String(!fileExists),
366
- duration_ms: String(Date.now() - startTime),
367
- })
368
-
369
- yield {
370
- type: 'result',
371
- data: resultData,
372
- resultForAssistant: summary,
373
- }
374
- } catch (error) {
375
- const errorMessage =
376
- error instanceof Error ? error.message : 'Unknown error occurred'
377
- const errorResult = `Error applying multi-edit: ${errorMessage}`
378
-
379
- logError(error)
380
-
381
- yield {
382
- type: 'result',
383
- data: errorResult,
384
- resultForAssistant: errorResult,
385
- }
386
- }
387
- },
388
- } satisfies Tool<typeof inputSchema, any>
@@ -1,45 +0,0 @@
1
- import { NotebookEditTool } from '../NotebookEditTool/NotebookEditTool'
2
-
3
- export const DESCRIPTION = `This is a tool for making multiple edits to a single file in one operation. It is built on top of the Edit tool and allows you to perform multiple find-and-replace operations efficiently. Prefer this tool over the Edit tool when you need to make multiple edits to the same file.
4
-
5
- Before using this tool:
6
-
7
- 1. Use the Read tool to understand the file's contents and context
8
- 2. Verify the directory path is correct
9
-
10
- To make multiple file edits, provide the following:
11
- 1. file_path: The absolute path to the file to modify (must be absolute, not relative)
12
- 2. edits: An array of edit operations to perform, where each edit contains:
13
- - old_string: The text to replace (must match the file contents exactly, including all whitespace and indentation)
14
- - new_string: The edited text to replace the old_string
15
- - replace_all: Replace all occurences of old_string. This parameter is optional and defaults to false.
16
-
17
- IMPORTANT:
18
- - All edits are applied in sequence, in the order they are provided
19
- - Each edit operates on the result of the previous edit
20
- - All edits must be valid for the operation to succeed - if any edit fails, none will be applied
21
- - This tool is ideal when you need to make several changes to different parts of the same file
22
- - For Jupyter notebooks (.ipynb files), use the ${NotebookEditTool.name} instead
23
-
24
- CRITICAL REQUIREMENTS:
25
- 1. All edits follow the same requirements as the single Edit tool
26
- 2. The edits are atomic - either all succeed or none are applied
27
- 3. Plan your edits carefully to avoid conflicts between sequential operations
28
-
29
- WARNING:
30
- - The tool will fail if edits.old_string doesn't match the file contents exactly (including whitespace)
31
- - The tool will fail if edits.old_string and edits.new_string are the same
32
- - Since edits are applied in sequence, ensure that earlier edits don't affect the text that later edits are trying to find
33
-
34
- When making edits:
35
- - Ensure all edits result in idiomatic, correct code
36
- - Do not leave the code in a broken state
37
- - Always use absolute file paths (starting with /)
38
- - Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.
39
-
40
- If you want to create a new file, use:
41
- - A new file path, including dir name if needed
42
- - First edit: empty old_string and the new file's contents as new_string
43
- - Subsequent edits: normal edit operations on the created content`
44
-
45
- export const PROMPT = DESCRIPTION