MoonshotAI / MoonshotAI/kimi-cli

[Windows] StrReplaceFile silently converts entire file from CRLF to LF, forcing Agent to abandon native tools for Python workarounds

Open
#2,191 0 comments 0 reactions 0 assignees View on GitHub

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:

  1. Using \n (LF) in the old string: The match succeeds, but StrReplaceFile rewrites the entire file from CRLF to LF, producing a massive unrelated diff.
  2. Using \r\n (CRLF) in the old string: 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

  1. Take any standard Windows CRLF source file (e.g., a C header with 300+ lines, all \r\n).
  2. Call StrReplaceFile with an old string that uses \n for newlines.
  3. Replacement succeeds, but the file is now pure LF (\r\n count drops to 0; \n count increases).
  4. git diff shows the whole file as changed due to line-ending churn.

Repro 2 -- \r\n old string fails to match

  1. Copy the same CRLF file to a test copy.
  2. Call StrReplaceFile with an old string that explicitly uses \r\n.
  3. 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
  1. StrReplaceFile should preserve the original line-ending format of the file; a localized replacement must not rewrite every line ending in the entire file.
  2. Alternatively, expose a parameter (e.g., preserve_line_endings: bool) to opt-in to preservation.
  3. 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 StrReplaceFile on 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 WriteFile in overwrite mode because the Agent could not rely on StrReplaceFile.
  • 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): WriteFile full-file overwrite.
  • Large files (>=300 lines): Python script via Shell, using open(..., 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
  1. P0: Internally normalize \n for matching, but write back using the file's original newline sequence.
  2. P1: Add preserve_line_endings: bool parameter to StrReplaceFile.
  3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.