@shareai-lab/kode 1.1.23-dev.1 → 1.1.23-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.
|
@@ -12,16 +12,17 @@ function FileEditToolUpdatedMessage({
|
|
|
12
12
|
verbose
|
|
13
13
|
}) {
|
|
14
14
|
const { columns } = useTerminalSize();
|
|
15
|
-
const
|
|
15
|
+
const patches = Array.isArray(structuredPatch) ? structuredPatch : [];
|
|
16
|
+
const numAdditions = patches.reduce(
|
|
16
17
|
(count, hunk) => count + hunk.lines.filter((_) => _.startsWith("+")).length,
|
|
17
18
|
0
|
|
18
19
|
);
|
|
19
|
-
const numRemovals =
|
|
20
|
+
const numRemovals = patches.reduce(
|
|
20
21
|
(count, hunk) => count + hunk.lines.filter((_) => _.startsWith("-")).length,
|
|
21
22
|
0
|
|
22
23
|
);
|
|
23
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, " ", "\u23BF Updated", " ", /* @__PURE__ */ React.createElement(Text, { bold: true }, verbose ? filePath : relative(getCwd(), filePath)), numAdditions > 0 || numRemovals > 0 ? " with " : "", numAdditions > 0 ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, numAdditions), " ", numAdditions > 1 ? "additions" : "addition") : null, numAdditions > 0 && numRemovals > 0 ? " and " : null, numRemovals > 0 ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, numRemovals), " ", numRemovals > 1 ? "removals" : "removal") : null), intersperse(
|
|
24
|
-
|
|
24
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, " ", "\u23BF Updated", " ", /* @__PURE__ */ React.createElement(Text, { bold: true }, verbose ? filePath : relative(getCwd(), filePath)), numAdditions > 0 || numRemovals > 0 ? " with " : "", numAdditions > 0 ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, numAdditions), " ", numAdditions > 1 ? "additions" : "addition") : null, numAdditions > 0 && numRemovals > 0 ? " and " : null, numRemovals > 0 ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, numRemovals), " ", numRemovals > 1 ? "removals" : "removal") : null), patches.length > 0 && intersperse(
|
|
25
|
+
patches.map((_) => /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingLeft: 5, key: _.newStart }, /* @__PURE__ */ React.createElement(StructuredDiff, { patch: _, dim: false, width: columns - 12 }))),
|
|
25
26
|
(i) => /* @__PURE__ */ React.createElement(Box, { paddingLeft: 5, key: `ellipsis-${i}` }, /* @__PURE__ */ React.createElement(Text, { color: getTheme().secondaryText }, "..."))
|
|
26
27
|
));
|
|
27
28
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/FileEditToolUpdatedMessage.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Hunk } from 'diff'\nimport { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { intersperse } from '../utils/array'\nimport { StructuredDiff } from './StructuredDiff'\nimport { getTheme } from '../utils/theme'\nimport { getCwd } from '../utils/state'\nimport { relative } from 'path'\nimport { useTerminalSize } from '../hooks/useTerminalSize'\n\ntype Props = {\n filePath: string\n structuredPatch
|
|
5
|
-
"mappings": "AACA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAQzB,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,EAAE,QAAQ,IAAI,gBAAgB;AACpC,QAAM,eAAe,
|
|
4
|
+
"sourcesContent": ["import { Hunk } from 'diff'\nimport { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { intersperse } from '../utils/array'\nimport { StructuredDiff } from './StructuredDiff'\nimport { getTheme } from '../utils/theme'\nimport { getCwd } from '../utils/state'\nimport { relative } from 'path'\nimport { useTerminalSize } from '../hooks/useTerminalSize'\n\ntype Props = {\n filePath: string\n structuredPatch?: Hunk[]\n verbose: boolean\n}\n\nexport function FileEditToolUpdatedMessage({\n filePath,\n structuredPatch,\n verbose,\n}: Props): React.ReactNode {\n const { columns } = useTerminalSize()\n const patches = Array.isArray(structuredPatch) ? structuredPatch : []\n const numAdditions = patches.reduce(\n (count, hunk) => count + hunk.lines.filter(_ => _.startsWith('+')).length,\n 0,\n )\n const numRemovals = patches.reduce(\n (count, hunk) => count + hunk.lines.filter(_ => _.startsWith('-')).length,\n 0,\n )\n\n return (\n <Box flexDirection=\"column\">\n <Text>\n {' '}\u23BF Updated{' '}\n <Text bold>{verbose ? filePath : relative(getCwd(), filePath)}</Text>\n {numAdditions > 0 || numRemovals > 0 ? ' with ' : ''}\n {numAdditions > 0 ? (\n <>\n <Text bold>{numAdditions}</Text>{' '}\n {numAdditions > 1 ? 'additions' : 'addition'}\n </>\n ) : null}\n {numAdditions > 0 && numRemovals > 0 ? ' and ' : null}\n {numRemovals > 0 ? (\n <>\n <Text bold>{numRemovals}</Text>{' '}\n {numRemovals > 1 ? 'removals' : 'removal'}\n </>\n ) : null}\n </Text>\n {patches.length > 0 &&\n intersperse(\n patches.map(_ => (\n <Box flexDirection=\"column\" paddingLeft={5} key={_.newStart}>\n <StructuredDiff patch={_} dim={false} width={columns - 12} />\n </Box>\n )),\n i => (\n <Box paddingLeft={5} key={`ellipsis-${i}`}>\n <Text color={getTheme().secondaryText}>...</Text>\n </Box>\n ),\n )}\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAQzB,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,EAAE,QAAQ,IAAI,gBAAgB;AACpC,QAAM,UAAU,MAAM,QAAQ,eAAe,IAAI,kBAAkB,CAAC;AACpE,QAAM,eAAe,QAAQ;AAAA,IAC3B,CAAC,OAAO,SAAS,QAAQ,KAAK,MAAM,OAAO,OAAK,EAAE,WAAW,GAAG,CAAC,EAAE;AAAA,IACnE;AAAA,EACF;AACA,QAAM,cAAc,QAAQ;AAAA,IAC1B,CAAC,OAAO,SAAS,QAAQ,KAAK,MAAM,OAAO,OAAK,EAAE,WAAW,GAAG,CAAC,EAAE;AAAA,IACnE;AAAA,EACF;AAEA,SACE,oCAAC,OAAI,eAAc,YACjB,oCAAC,YACE,MAAK,kBAAU,KAChB,oCAAC,QAAK,MAAI,QAAE,UAAU,WAAW,SAAS,OAAO,GAAG,QAAQ,CAAE,GAC7D,eAAe,KAAK,cAAc,IAAI,WAAW,IACjD,eAAe,IACd,0DACE,oCAAC,QAAK,MAAI,QAAE,YAAa,GAAQ,KAChC,eAAe,IAAI,cAAc,UACpC,IACE,MACH,eAAe,KAAK,cAAc,IAAI,UAAU,MAChD,cAAc,IACb,0DACE,oCAAC,QAAK,MAAI,QAAE,WAAY,GAAQ,KAC/B,cAAc,IAAI,aAAa,SAClC,IACE,IACN,GACC,QAAQ,SAAS,KAChB;AAAA,IACE,QAAQ,IAAI,OACV,oCAAC,OAAI,eAAc,UAAS,aAAa,GAAG,KAAK,EAAE,YACjD,oCAAC,kBAAe,OAAO,GAAG,KAAK,OAAO,OAAO,UAAU,IAAI,CAC7D,CACD;AAAA,IACD,OACE,oCAAC,OAAI,aAAa,GAAG,KAAK,YAAY,CAAC,MACrC,oCAAC,QAAK,OAAO,SAAS,EAAE,iBAAe,KAAG,CAC5C;AAAA,EAEJ,CACJ;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -34,6 +34,7 @@ import { hasWritePermission } from "../../utils/permissions/filesystem.js";
|
|
|
34
34
|
import { PROMPT } from "./prompt.js";
|
|
35
35
|
import { emitReminderEvent } from "../../services/systemReminder.js";
|
|
36
36
|
import { recordFileEdit } from "../../services/fileFreshness.js";
|
|
37
|
+
import { getPatch } from "../../utils/diff.js";
|
|
37
38
|
const EditSchema = z.object({
|
|
38
39
|
old_string: z.string().describe("The text to replace"),
|
|
39
40
|
new_string: z.string().describe("The text to replace it with"),
|
|
@@ -93,7 +94,14 @@ ${editSummary}`;
|
|
|
93
94
|
const isError = output.includes("Error:");
|
|
94
95
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: isError ? getTheme().error : getTheme().success }, output));
|
|
95
96
|
}
|
|
96
|
-
return /* @__PURE__ */ React.createElement(
|
|
97
|
+
return /* @__PURE__ */ React.createElement(
|
|
98
|
+
FileEditToolUpdatedMessage,
|
|
99
|
+
{
|
|
100
|
+
filePath: output.filePath,
|
|
101
|
+
structuredPatch: output.structuredPatch,
|
|
102
|
+
verbose: false
|
|
103
|
+
}
|
|
104
|
+
);
|
|
97
105
|
},
|
|
98
106
|
async validateInput({ file_path, edits }, context) {
|
|
99
107
|
const workingDir = getCwd();
|
|
@@ -257,12 +265,19 @@ ${editSummary}`;
|
|
|
257
265
|
});
|
|
258
266
|
const relativePath = relative(workingDir, filePath);
|
|
259
267
|
const summary = `Successfully applied ${edits.length} edits to ${relativePath}`;
|
|
268
|
+
const structuredPatch = getPatch({
|
|
269
|
+
filePath: file_path,
|
|
270
|
+
fileContents: currentContent,
|
|
271
|
+
oldStr: currentContent,
|
|
272
|
+
newStr: modifiedContent
|
|
273
|
+
});
|
|
260
274
|
const resultData = {
|
|
261
|
-
filePath:
|
|
275
|
+
filePath: file_path,
|
|
262
276
|
wasNewFile: !fileExists,
|
|
263
277
|
editsApplied: appliedEdits,
|
|
264
278
|
totalEdits: edits.length,
|
|
265
|
-
summary
|
|
279
|
+
summary,
|
|
280
|
+
structuredPatch
|
|
266
281
|
};
|
|
267
282
|
logEvent("multi_edit_tool_used", {
|
|
268
283
|
file_path: relativePath,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/MultiEditTool/MultiEditTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, mkdirSync, readFileSync, statSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { dirname, isAbsolute, relative, resolve, sep } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FileEditToolUpdatedMessage } from '../../components/FileEditToolUpdatedMessage'\nimport { StructuredDiff } from '../../components/StructuredDiff'\nimport { logEvent } from '../../services/statsig'\nimport { Tool, ValidationResult } from '../../Tool'\nimport { intersperse } from '../../utils/array'\nimport {\n addLineNumbers,\n detectFileEncoding,\n detectLineEndings,\n findSimilarFile,\n writeTextContent,\n} from '../../utils/file.js'\nimport { logError } from '../../utils/log'\nimport { getCwd } from '../../utils/state'\nimport { getTheme } from '../../utils/theme'\nimport { NotebookEditTool } from '../NotebookEditTool/NotebookEditTool'\n// Local content-based edit function for MultiEditTool\nfunction applyContentEdit(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n): { newContent: string; occurrences: number } {\n if (replaceAll) {\n const regex = new RegExp(oldString.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g')\n const matches = content.match(regex)\n const occurrences = matches ? matches.length : 0\n const newContent = content.replace(regex, newString)\n return { newContent, occurrences }\n } else {\n if (content.includes(oldString)) {\n const newContent = content.replace(oldString, newString)\n return { newContent, occurrences: 1 }\n } else {\n throw new Error(`String not found: ${oldString.substring(0, 50)}...`)\n }\n }\n}\nimport { hasWritePermission } from '../../utils/permissions/filesystem'\nimport { PROJECT_FILE } from '../../constants/product'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { emitReminderEvent } from '../../services/systemReminder'\nimport { recordFileEdit } from '../../services/fileFreshness'\n\nconst EditSchema = z.object({\n old_string: z.string().describe('The text to replace'),\n new_string: z.string().describe('The text to replace it with'),\n replace_all: z\n .boolean()\n .optional()\n .default(false)\n .describe('Replace all occurences of old_string (default false)'),\n})\n\nconst inputSchema = z.strictObject({\n file_path: z.string().describe('The absolute path to the file to modify'),\n edits: z\n .array(EditSchema)\n .min(1)\n .describe('Array of edit operations to perform sequentially on the file'),\n})\n\nexport type In = typeof inputSchema\n\n// Number of lines of context to include before/after the change in our result message\nconst N_LINES_SNIPPET = 4\n\nexport const MultiEditTool = {\n name: 'MultiEdit',\n async description() {\n return 'A tool for making multiple edits to a single file atomically'\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Multi-Edit'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // MultiEdit modifies files, not safe for concurrent execution\n },\n needsPermissions(input?: z.infer<typeof inputSchema>) {\n if (!input) return true\n return !hasWritePermission(input.file_path)\n },\n renderResultForAssistant(content) {\n return content\n },\n renderToolUseMessage(input, { verbose }) {\n const { file_path, edits } = input\n const workingDir = getCwd()\n const relativePath = isAbsolute(file_path)\n ? relative(workingDir, file_path)\n : file_path\n\n if (verbose) {\n const editSummary = edits\n .map(\n (edit, index) =>\n `${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 ? '...' : ''}\"`,\n )\n .join('\\n')\n return `Multiple edits to ${relativePath}:\\n${editSummary}`\n }\n\n return `Making ${edits.length} edits to ${relativePath}`\n },\n renderToolUseRejectedMessage() {\n return (\n <Box>\n <Text color={getTheme().error}>\u26A0 Edit request rejected</Text>\n </Box>\n )\n },\n renderToolResultMessage(output) {\n if (typeof output === 'string') {\n const isError = output.includes('Error:')\n return (\n <Box flexDirection=\"column\">\n <Text color={isError ? getTheme().error : getTheme().success}>\n {output}\n </Text>\n </Box>\n )\n }\n\n return <FileEditToolUpdatedMessage {...output} />\n },\n async validateInput(\n { file_path, edits }: z.infer<typeof inputSchema>,\n context?: { readFileTimestamps?: Record<string, number> },\n ): Promise<ValidationResult> {\n const workingDir = getCwd()\n const normalizedPath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n // Check if it's a notebook file\n if (normalizedPath.endsWith('.ipynb')) {\n return {\n result: false,\n errorCode: 1,\n message: `For Jupyter notebooks (.ipynb files), use the ${NotebookEditTool.name} tool instead.`,\n }\n }\n\n // For new files, check parent directory exists\n if (!existsSync(normalizedPath)) {\n const parentDir = dirname(normalizedPath)\n if (!existsSync(parentDir)) {\n return {\n result: false,\n errorCode: 2,\n message: `Parent directory does not exist: ${parentDir}`,\n }\n }\n\n // For new files, ensure first edit creates the file (empty old_string)\n if (edits.length === 0 || edits[0].old_string !== '') {\n return {\n result: false,\n errorCode: 6,\n message:\n 'For new files, the first edit must have an empty old_string to create the file content.',\n }\n }\n } else {\n // For existing files, apply file protection mechanisms\n const readFileTimestamps = context?.readFileTimestamps || {}\n const readTimestamp = readFileTimestamps[normalizedPath]\n\n if (!readTimestamp) {\n return {\n result: false,\n errorCode: 7,\n message:\n 'File has not been read yet. Read it first before editing it.',\n meta: {\n filePath: normalizedPath,\n isFilePathAbsolute: String(isAbsolute(file_path)),\n },\n }\n }\n\n // Check if file has been modified since last read\n const stats = statSync(normalizedPath)\n const lastWriteTime = stats.mtimeMs\n if (lastWriteTime > readTimestamp) {\n return {\n result: false,\n errorCode: 8,\n message:\n 'File has been modified since read, either by the user or by a linter. Read it again before attempting to edit it.',\n meta: {\n filePath: normalizedPath,\n lastWriteTime,\n readTimestamp,\n },\n }\n }\n\n // Pre-validate that all old_strings exist in the file\n const encoding = detectFileEncoding(normalizedPath)\n if (encoding === 'binary') {\n return {\n result: false,\n errorCode: 9,\n message: 'Cannot edit binary files.',\n }\n }\n\n const currentContent = readFileSync(normalizedPath, 'utf-8')\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (\n edit.old_string !== '' &&\n !currentContent.includes(edit.old_string)\n ) {\n return {\n result: false,\n errorCode: 10,\n message: `Edit ${i + 1}: String to replace not found in file: \"${edit.old_string.substring(0, 100)}${edit.old_string.length > 100 ? '...' : ''}\"`,\n meta: {\n editIndex: i + 1,\n oldString: edit.old_string.substring(0, 200),\n },\n }\n }\n }\n }\n\n // Validate each edit\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (edit.old_string === edit.new_string) {\n return {\n result: false,\n errorCode: 3,\n message: `Edit ${i + 1}: old_string and new_string cannot be the same`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ file_path, edits }, { readFileTimestamps }) {\n const startTime = Date.now()\n const workingDir = getCwd()\n const filePath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n try {\n // Read current file content (or empty for new files)\n let currentContent = ''\n let fileExists = existsSync(filePath)\n\n if (fileExists) {\n const encoding = detectFileEncoding(filePath)\n if (encoding === 'binary') {\n yield {\n type: 'result',\n data: 'Error: Cannot edit binary files',\n resultForAssistant: 'Error: Cannot edit binary files',\n }\n return\n }\n currentContent = readFileSync(filePath, 'utf-8')\n } else {\n // For new files, ensure parent directory exists\n const parentDir = dirname(filePath)\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true })\n }\n }\n\n // Apply all edits sequentially\n let modifiedContent = currentContent\n const appliedEdits = []\n\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n const { old_string, new_string, replace_all } = edit\n\n try {\n const result = applyContentEdit(\n modifiedContent,\n old_string,\n new_string,\n replace_all,\n )\n modifiedContent = result.newContent\n appliedEdits.push({\n editIndex: i + 1,\n success: true,\n old_string: old_string.substring(0, 100),\n new_string: new_string.substring(0, 100),\n occurrences: result.occurrences,\n })\n } catch (error) {\n // If any edit fails, abort the entire operation\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error'\n yield {\n type: 'result',\n data: `Error in edit ${i + 1}: ${errorMessage}`,\n resultForAssistant: `Error in edit ${i + 1}: ${errorMessage}`,\n }\n return\n }\n }\n\n // Write the modified content\n const lineEndings = fileExists ? detectLineEndings(currentContent) : 'LF'\n const encoding = fileExists ? detectFileEncoding(filePath) : 'utf8'\n writeTextContent(filePath, modifiedContent, encoding, lineEndings)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(filePath, modifiedContent)\n\n // Update readFileTimestamps to prevent stale file warnings\n readFileTimestamps[filePath] = Date.now()\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath,\n edits: edits.map(e => ({\n oldString: e.old_string,\n newString: e.new_string,\n })),\n originalContent: currentContent,\n newContent: modifiedContent,\n timestamp: Date.now(),\n operation: fileExists ? 'update' : 'create',\n })\n\n // Generate result data\n const relativePath = relative(workingDir, filePath)\n const summary = `Successfully applied ${edits.length} edits to ${relativePath}`\n\n const resultData = {\n filePath: relativePath,\n wasNewFile: !fileExists,\n editsApplied: appliedEdits,\n totalEdits: edits.length,\n summary,\n }\n\n // Log the operation\n logEvent('multi_edit_tool_used', {\n file_path: relativePath,\n edits_count: String(edits.length),\n was_new_file: String(!fileExists),\n duration_ms: String(Date.now() - startTime),\n })\n\n yield {\n type: 'result',\n data: resultData,\n resultForAssistant: summary,\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n const errorResult = `Error applying multi-edit: ${errorMessage}`\n\n logError(error)\n\n yield {\n type: 'result',\n data: errorResult,\n resultForAssistant: errorResult,\n }\n }\n },\n} satisfies Tool<typeof inputSchema, any>\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY,WAAW,cAAc,gBAAgB;AAC9D,SAAS,KAAK,YAAY;AAC1B,SAAS,SAAS,YAAY,UAAU,eAAoB;AAC5D,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,kCAAkC;AAE3C,SAAS,gBAAgB;AAGzB;AAAA,EAEE;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AAEjC,SAAS,iBACP,SACA,WACA,WACA,aAAsB,OACuB;AAC7C,MAAI,YAAY;AACd,UAAM,QAAQ,IAAI,OAAO,UAAU,QAAQ,uBAAuB,MAAM,GAAG,GAAG;AAC9E,UAAM,UAAU,QAAQ,MAAM,KAAK;AACnC,UAAM,cAAc,UAAU,QAAQ,SAAS;AAC/C,UAAM,aAAa,QAAQ,QAAQ,OAAO,SAAS;AACnD,WAAO,EAAE,YAAY,YAAY;AAAA,EACnC,OAAO;AACL,QAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,YAAM,aAAa,QAAQ,QAAQ,WAAW,SAAS;AACvD,aAAO,EAAE,YAAY,aAAa,EAAE;AAAA,IACtC,OAAO;AACL,YAAM,IAAI,MAAM,qBAAqB,UAAU,UAAU,GAAG,EAAE,CAAC,KAAK;AAAA,IACtE;AAAA,EACF;AACF;AACA,SAAS,0BAA0B;AAEnC,SAAsB,cAAc;AACpC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;
|
|
4
|
+
"sourcesContent": ["import { existsSync, mkdirSync, readFileSync, statSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { dirname, isAbsolute, relative, resolve, sep } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FileEditToolUpdatedMessage } from '../../components/FileEditToolUpdatedMessage'\nimport { StructuredDiff } from '../../components/StructuredDiff'\nimport { logEvent } from '../../services/statsig'\nimport { Tool, ValidationResult } from '../../Tool'\nimport { intersperse } from '../../utils/array'\nimport {\n addLineNumbers,\n detectFileEncoding,\n detectLineEndings,\n findSimilarFile,\n writeTextContent,\n} from '../../utils/file.js'\nimport { logError } from '../../utils/log'\nimport { getCwd } from '../../utils/state'\nimport { getTheme } from '../../utils/theme'\nimport { NotebookEditTool } from '../NotebookEditTool/NotebookEditTool'\n// Local content-based edit function for MultiEditTool\nfunction applyContentEdit(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n): { newContent: string; occurrences: number } {\n if (replaceAll) {\n const regex = new RegExp(oldString.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g')\n const matches = content.match(regex)\n const occurrences = matches ? matches.length : 0\n const newContent = content.replace(regex, newString)\n return { newContent, occurrences }\n } else {\n if (content.includes(oldString)) {\n const newContent = content.replace(oldString, newString)\n return { newContent, occurrences: 1 }\n } else {\n throw new Error(`String not found: ${oldString.substring(0, 50)}...`)\n }\n }\n}\nimport { hasWritePermission } from '../../utils/permissions/filesystem'\nimport { PROJECT_FILE } from '../../constants/product'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { emitReminderEvent } from '../../services/systemReminder'\nimport { recordFileEdit } from '../../services/fileFreshness'\nimport { getPatch } from '../../utils/diff'\n\nconst EditSchema = z.object({\n old_string: z.string().describe('The text to replace'),\n new_string: z.string().describe('The text to replace it with'),\n replace_all: z\n .boolean()\n .optional()\n .default(false)\n .describe('Replace all occurences of old_string (default false)'),\n})\n\nconst inputSchema = z.strictObject({\n file_path: z.string().describe('The absolute path to the file to modify'),\n edits: z\n .array(EditSchema)\n .min(1)\n .describe('Array of edit operations to perform sequentially on the file'),\n})\n\nexport type In = typeof inputSchema\n\n// Number of lines of context to include before/after the change in our result message\nconst N_LINES_SNIPPET = 4\n\nexport const MultiEditTool = {\n name: 'MultiEdit',\n async description() {\n return 'A tool for making multiple edits to a single file atomically'\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Multi-Edit'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // MultiEdit modifies files, not safe for concurrent execution\n },\n needsPermissions(input?: z.infer<typeof inputSchema>) {\n if (!input) return true\n return !hasWritePermission(input.file_path)\n },\n renderResultForAssistant(content) {\n return content\n },\n renderToolUseMessage(input, { verbose }) {\n const { file_path, edits } = input\n const workingDir = getCwd()\n const relativePath = isAbsolute(file_path)\n ? relative(workingDir, file_path)\n : file_path\n\n if (verbose) {\n const editSummary = edits\n .map(\n (edit, index) =>\n `${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 ? '...' : ''}\"`,\n )\n .join('\\n')\n return `Multiple edits to ${relativePath}:\\n${editSummary}`\n }\n\n return `Making ${edits.length} edits to ${relativePath}`\n },\n renderToolUseRejectedMessage() {\n return (\n <Box>\n <Text color={getTheme().error}>\u26A0 Edit request rejected</Text>\n </Box>\n )\n },\n renderToolResultMessage(output) {\n if (typeof output === 'string') {\n const isError = output.includes('Error:')\n return (\n <Box flexDirection=\"column\">\n <Text color={isError ? getTheme().error : getTheme().success}>\n {output}\n </Text>\n </Box>\n )\n }\n\n return (\n <FileEditToolUpdatedMessage\n filePath={output.filePath}\n structuredPatch={output.structuredPatch}\n verbose={false}\n />\n )\n },\n async validateInput(\n { file_path, edits }: z.infer<typeof inputSchema>,\n context?: { readFileTimestamps?: Record<string, number> },\n ): Promise<ValidationResult> {\n const workingDir = getCwd()\n const normalizedPath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n // Check if it's a notebook file\n if (normalizedPath.endsWith('.ipynb')) {\n return {\n result: false,\n errorCode: 1,\n message: `For Jupyter notebooks (.ipynb files), use the ${NotebookEditTool.name} tool instead.`,\n }\n }\n\n // For new files, check parent directory exists\n if (!existsSync(normalizedPath)) {\n const parentDir = dirname(normalizedPath)\n if (!existsSync(parentDir)) {\n return {\n result: false,\n errorCode: 2,\n message: `Parent directory does not exist: ${parentDir}`,\n }\n }\n\n // For new files, ensure first edit creates the file (empty old_string)\n if (edits.length === 0 || edits[0].old_string !== '') {\n return {\n result: false,\n errorCode: 6,\n message:\n 'For new files, the first edit must have an empty old_string to create the file content.',\n }\n }\n } else {\n // For existing files, apply file protection mechanisms\n const readFileTimestamps = context?.readFileTimestamps || {}\n const readTimestamp = readFileTimestamps[normalizedPath]\n\n if (!readTimestamp) {\n return {\n result: false,\n errorCode: 7,\n message:\n 'File has not been read yet. Read it first before editing it.',\n meta: {\n filePath: normalizedPath,\n isFilePathAbsolute: String(isAbsolute(file_path)),\n },\n }\n }\n\n // Check if file has been modified since last read\n const stats = statSync(normalizedPath)\n const lastWriteTime = stats.mtimeMs\n if (lastWriteTime > readTimestamp) {\n return {\n result: false,\n errorCode: 8,\n message:\n 'File has been modified since read, either by the user or by a linter. Read it again before attempting to edit it.',\n meta: {\n filePath: normalizedPath,\n lastWriteTime,\n readTimestamp,\n },\n }\n }\n\n // Pre-validate that all old_strings exist in the file\n const encoding = detectFileEncoding(normalizedPath)\n if (encoding === 'binary') {\n return {\n result: false,\n errorCode: 9,\n message: 'Cannot edit binary files.',\n }\n }\n\n const currentContent = readFileSync(normalizedPath, 'utf-8')\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (\n edit.old_string !== '' &&\n !currentContent.includes(edit.old_string)\n ) {\n return {\n result: false,\n errorCode: 10,\n message: `Edit ${i + 1}: String to replace not found in file: \"${edit.old_string.substring(0, 100)}${edit.old_string.length > 100 ? '...' : ''}\"`,\n meta: {\n editIndex: i + 1,\n oldString: edit.old_string.substring(0, 200),\n },\n }\n }\n }\n }\n\n // Validate each edit\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (edit.old_string === edit.new_string) {\n return {\n result: false,\n errorCode: 3,\n message: `Edit ${i + 1}: old_string and new_string cannot be the same`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ file_path, edits }, { readFileTimestamps }) {\n const startTime = Date.now()\n const workingDir = getCwd()\n const filePath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n try {\n // Read current file content (or empty for new files)\n let currentContent = ''\n let fileExists = existsSync(filePath)\n\n if (fileExists) {\n const encoding = detectFileEncoding(filePath)\n if (encoding === 'binary') {\n yield {\n type: 'result',\n data: 'Error: Cannot edit binary files',\n resultForAssistant: 'Error: Cannot edit binary files',\n }\n return\n }\n currentContent = readFileSync(filePath, 'utf-8')\n } else {\n // For new files, ensure parent directory exists\n const parentDir = dirname(filePath)\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true })\n }\n }\n\n // Apply all edits sequentially\n let modifiedContent = currentContent\n const appliedEdits = []\n\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n const { old_string, new_string, replace_all } = edit\n\n try {\n const result = applyContentEdit(\n modifiedContent,\n old_string,\n new_string,\n replace_all,\n )\n modifiedContent = result.newContent\n appliedEdits.push({\n editIndex: i + 1,\n success: true,\n old_string: old_string.substring(0, 100),\n new_string: new_string.substring(0, 100),\n occurrences: result.occurrences,\n })\n } catch (error) {\n // If any edit fails, abort the entire operation\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error'\n yield {\n type: 'result',\n data: `Error in edit ${i + 1}: ${errorMessage}`,\n resultForAssistant: `Error in edit ${i + 1}: ${errorMessage}`,\n }\n return\n }\n }\n\n // Write the modified content\n const lineEndings = fileExists ? detectLineEndings(currentContent) : 'LF'\n const encoding = fileExists ? detectFileEncoding(filePath) : 'utf8'\n writeTextContent(filePath, modifiedContent, encoding, lineEndings)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(filePath, modifiedContent)\n\n // Update readFileTimestamps to prevent stale file warnings\n readFileTimestamps[filePath] = Date.now()\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath,\n edits: edits.map(e => ({\n oldString: e.old_string,\n newString: e.new_string,\n })),\n originalContent: currentContent,\n newContent: modifiedContent,\n timestamp: Date.now(),\n operation: fileExists ? 'update' : 'create',\n })\n\n // Generate result data\n const relativePath = relative(workingDir, filePath)\n const summary = `Successfully applied ${edits.length} edits to ${relativePath}`\n\n const structuredPatch = getPatch({\n filePath: file_path,\n fileContents: currentContent,\n oldStr: currentContent,\n newStr: modifiedContent,\n })\n\n const resultData = {\n filePath: file_path,\n wasNewFile: !fileExists,\n editsApplied: appliedEdits,\n totalEdits: edits.length,\n summary,\n structuredPatch,\n }\n\n // Log the operation\n logEvent('multi_edit_tool_used', {\n file_path: relativePath,\n edits_count: String(edits.length),\n was_new_file: String(!fileExists),\n duration_ms: String(Date.now() - startTime),\n })\n\n yield {\n type: 'result',\n data: resultData,\n resultForAssistant: summary,\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n const errorResult = `Error applying multi-edit: ${errorMessage}`\n\n logError(error)\n\n yield {\n type: 'result',\n data: errorResult,\n resultForAssistant: errorResult,\n }\n }\n },\n} satisfies Tool<typeof inputSchema, any>\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["encoding"]
|
|
7
7
|
}
|