Skip to content

Opencode v2: Tool Patch messes up line endings in Windows #54605

Closed as duplicate

Description

@Mac-Moneysac

Description

Editing files via tool patch messes up line endings in CRLF formatted files in windows.

Per default line endings in Windows are CRLF. However, opencode introduces LF line endings when using the builtin tool patch. In git repositories without line ending normalization or when editing files in windows that are not versioned this poses an annoying problem.

Besides that I want to thank you for the amazing project!

Potential duplicates

#37090 has been closed since it has been originally tested with opencode v1. Therefore it has been re-opened since it is still present for v2.
#50740 is about tool write afaik

Plugins

No response

OpenCode version

2.0.26

Steps to reproduce

  1. Use an existing code file with CRLF line endings.
  2. Use an OpenAI model which triggers the patch tool
  3. Use a suitable prompt such that a code line will be added.
  4. This new line will have LF endings instead of CRLF.

Screenshot and/or share link

No response

Operating System

Windows 11

Terminal

Windows Terminal

Activity

  1. opencode-agent commented on Oct 11, 2026

    @opencode-agent
    Contributor

    Thanks for re-filing this for v2, and for the kind words!

    I think this is a duplicate of #45926. It reports the same apply_patch behaviour on v2: lines the patch touches in a CRLF file get LF endings, so the file ends up with mixed line endings. The cause it identifies is still in the current code, and that issue is still open.

    Possible duplicates and related issues, most likely first:

    Anyone else hitting this can use your plugin, https://github.com/Mac-Moneysac/opencode-fix-line-endings, as a workaround for now.

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different. Feel free to add your details to #45926 in the meantime.

  2. Mac-Moneysac commented on Oct 11, 2026

    @Mac-Moneysac
    Author

    Issue #45926 has been opened vor v1. The corresponding pull request #45931 was implemented for v1 and has therefore been closed. For this reason, I have specifically opened this ticket for v2.

  3. opencode-agent commented on Oct 11, 2026

    @opencode-agent
    Contributor

    Thanks for the details. I've reproduced this on 2.0.26, and it still happens on the latest dev (727fd603).

    Steps, using a simulated model:

    1. Start with a file app.ts with four CRLF lines.
    2. The model calls the built-in patch tool to change one line and add a new one.
    3. Check the file with cat -A: CRLF lines end in ^M$, LF lines end in $.

    After the patch, every line inside the hunk is LF, including the unchanged context lines, while the untouched line at the end is still CRLF. The file ends up with mixed line endings. The screenshot and recording below show it, and the script below reproduces it.

    The v2 patch code splits and rejoins the file on \n alone, so the model's LF lines replace the CRLF lines they cover. It's ready for a maintainer to look at. In the meantime, your plugin (https://github.com/Mac-Moneysac/opencode-fix-line-endings) is a workaround.

    recording.mp4

    Screenshot

    Reproduction script (drive.ts)
    // Repro for anomalyco/opencode#54605: the patch tool writes LF line endings into CRLF files.
    // The project starts with a CRLF file. The simulated model calls `patch` to change one line
    // and add a new one, then runs `cat -A` (CRLF lines end in "^M$", LF lines end in "$").
    import { Effect } from "effect"
    import { Llm, OpenCodeDriver } from "opencode-drive"
    
    const patchText = [
      "*** Begin Patch",
      "*** Update File: app.ts",
      "@@",
      " const a = 1",
      "-const b = 2",
      "+const b = 20",
      "+const added = 99",
      " const c = 3",
      "*** End Patch",
    ].join("\n")
    
    export default OpenCodeDriver.use(
      {
        ...(process.env.OC_DEV ? { opencode: { dev: process.env.OC_DEV } } : {}),
        project: {
          git: true,
          files: { "app.ts": "const a = 1\r\nconst b = 2\r\nconst c = 3\r\nconst d = 4\r\n" },
        },
        tui: { recording: true },
      },
      ({ ui, llm }) =>
        Effect.gen(function* () {
          yield* llm.queue(
              Llm.toolCall({ index: 0, id: "call_before", name: "shell", input: { command: "cat -A app.ts", description: "Show line endings before" } }),
              Llm.finish("tool-calls"),
          )
          yield* llm.queue(
              Llm.toolCall({ index: 0, id: "call_patch", name: "patch", input: { patchText } }),
              Llm.finish("tool-calls"),
          )
          yield* llm.queue(
              Llm.toolCall({ index: 0, id: "call_after", name: "shell", input: { command: "echo AFTER; cat -A app.ts", description: "Show line endings after" } }),
              Llm.finish("tool-calls"),
          )
          yield* llm.queue(Llm.text("Done. Lines ending in ^M$ are CRLF, lines ending in $ only are LF."))
          yield* ui.submit("Change b to 20 and add a line after it in app.ts")
          yield* ui.waitFor("Done. Lines ending", { timeout: 60000 })
          yield* Effect.sleep(1500)
          yield* ui.screenshot("after-patch")
        }),
    )

    Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.

  4. neriousy commented on Oct 20, 2026

    @neriousy
    Member

    Thanks for reporting this on V2 and sharing your workaround. This is the same problem as #45926: patching a CRLF file introduces LF endings, and we're tracking it there. Please subscribe or add a 👍 to that issue; your Windows 11 details and workaround are worth adding there too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions