MoonshotAI / MoonshotAI/kimi-cli
[Windows] StrReplaceFile silently converts entire file from CRLF to LF, forcing Agent to abandon native tools for Python workarounds
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 11.4k
- Forks
- 1.3k
- Avg merge
- 9h 47m
- Merged PRs (30d)
- 2
Description
Related Issue: #1952 (CRLF issue with StrReplaceFile)
Related PR: #1953 (fix(file): preserve CRLF during file edits) -- still open/unmerged
Problem Description
On Windows, repository files use standard CRLF (\r\n) line endings (checked out via Git core.autocrlf=true). When the Agent attempts to use StrReplaceFile for localized edits, it hits a double failure:
- Using \n (LF) in the
oldstring: The match succeeds, butStrReplaceFilerewrites the entire file from CRLF to LF, producing a massive unrelated diff. - Using \r\n (CRLF) in the
oldstring: The match fails outright with"old string was not found".
This makes StrReplaceFile completely unsafe to use on Windows CRLF files. The Agent is forced to fall back to executing Python scripts through the Shell tool for every file modification.
Cascading Consequences (Real Session)
Once forced into Python-via-Shell on Windows PowerShell, a chain of secondary failures occurs:
| Failure | Symptom | Frequency |
|---|---|---|
SyntaxError: EOF while scanning triple-quoted string literal |
Multi-line Python passed via python -c "..." gets truncated |
Multiple |
SyntaxError: EOL while scanning string literal |
Backslash/ newline escaping across PowerShell + Python layers fails | Multiple |
SyntaxError: f-string expression part cannot include a backslash |
Windows path backslashes inside f-strings cause syntax errors | Multiple |
AttributeError: 'bytes' object has no attribute 'encode' |
Double .encode() on a bytes object in the script |
Once |
JSON parse error (Unterminated string) |
Unescaped quotes inside SetTodoList / tool-call JSON payloads |
Multiple |
| Tab vs. space mismatch | Some source files mix \t and space indentation; Python scripts searching with the wrong whitespace type fail to find targets | Multiple |
End result: Modifying ~7 source files consumed 110 tool calls across 4 conversation turns, and the files had to be redone from scratch after an accidental revert.
Reproduction
Repro 1 -- \n old string silently corrupts line endings
- Take any standard Windows CRLF source file (e.g., a C header with 300+ lines, all \r\n).
- Call
StrReplaceFilewith anoldstring that uses \n for newlines. - Replacement succeeds, but the file is now pure LF (\r\n count drops to 0; \n count increases).
git diffshows the whole file as changed due to line-ending churn.
Repro 2 -- \r\n old string fails to match
- Copy the same CRLF file to a test copy.
- Call
StrReplaceFilewith anoldstring that explicitly uses \r\n. - Returns:
"No replacements were made. The old string was not found in the file."
Environment
- OS: Windows (case-insensitive filesystem, Git
core.autocrlf=true) - Shell: PowerShell 5.x / 7.x
- Kimi CLI Version: 1.35.0+
- File format: UTF-8 (with or without BOM) + CRLF -- standard Windows C source files
- Project type: Large embedded project with Git submodules
Expected Behavior
StrReplaceFileshould preserve the original line-ending format of the file; a localized replacement must not rewrite every line ending in the entire file.- Alternatively, expose a parameter (e.g.,
preserve_line_endings: bool) to opt-in to preservation. - At minimum, when matching fails due to newline mismatch, return diagnostic detail (e.g.,
"Target text found but newline style mismatch: file uses CRLF, old string uses LF") instead of the generic"old string not found".
Impact Assessment
- Tool reliability: Agent can no longer trust
StrReplaceFileon Windows projects. - Efficiency: A single file edit balloons from 1-2 tool calls to 10+ calls (read -> probe -> script -> verify -> retry).
- Safety: Frequent Python syntax errors increase the risk of accidental file corruption; in our session a documentation file was accidentally overwritten by
WriteFilein overwrite mode because the Agent could not rely onStrReplaceFile. - UX: Extremely brittle workflow; user had to interrupt the Agent multiple times and manually restore files.
Current Workaround
The Agent has effectively abandoned StrReplaceFile and now uses:
- Small files (<300 lines):
WriteFilefull-file overwrite. - Large files (>=300 lines): Python script via
Shell, usingopen(..., newline='')to read/write verbatim.
This workaround is highly unstable on PowerShell (quoting hell, multi-layer escaping), so a native fix is urgently needed.
Suggested Fix Priority
- P0: Internally normalize \n for matching, but write back using the file's original newline sequence.
- P1: Add
preserve_line_endings: boolparameter toStrReplaceFile. - P2: Return structured diagnostics on mismatch (newline style, indentation character mismatch, BOM presence, etc.).
Full wire.jsonl logs and detailed analysis are retained internally; happy to provide sanitized excerpts if they help with debugging.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Review StrReplaceFile and the related PR #1953 first; the issue does not name implementation files or tests. Reproduce both newline cases on Windows with a CRLF file, then verify that localized replacements preserve the original line endings and that the reported mismatch behavior is covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, powershell, python
- Domain
- cli, operating-systems, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100