跳到主要内容
    ↑↓ 选择↵ 打开esc 关闭
    中文English
    timxx

    Preserve Format

    v2026.5.10代码智能
    opencode-preserve-format

    OpenCode plugin that preserves original BOM and line endings when editing files

    GitHub 星标

    1

    月装机量

    20

    近 7 天 3

    综合评分SCORE

    25.3

    生态多维模型

    最近提交

    3 个月前

    2026-05-10

    快速安装与配置

    opencode.json

    写入当前项目的 opencode.json,只对这个仓库生效。

    opencode.json

    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["opencode-preserve-format@2026.5.10"]
    }

    opencode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。

    opencode-preserve-format

    npm

    An OpenCode plugin that preserves a file's original BOM and line endings whenever OpenCode modifies it. Every file keeps exactly what it had before — no configuration needed.

    Installation

    Add to your opencode.json:

    {
      "plugin": ["opencode-preserve-format"]
    }
    

    OpenCode installs the package automatically at startup.

    How detection works

    Line endings: The plugin counts \r\n (CRLF) and lone \n (LF) occurrences in the file. Whichever is more frequent is used as the target. Equal counts → CRLF. No newlines → LF.

    BOM: The first bytes of the file are inspected for:

    Bytes Encoding
    EF BB BF UTF-8 BOM
    FF FE UTF-16 LE
    FE FF UTF-16 BE

    If found, the BOM is re-prepended after every edit.

    New files: When the write tool creates a file that doesn't exist yet, the target line ending is detected from the AI-generated content using the same majority algorithm. No BOM is added to new files.

    Mixed endings: Dominant wins. A file with 70 CRLF and 30 LF is treated as a CRLF file.

    How it works

    The plugin hooks into OpenCode's tool execution pipeline at two points:

    • Before tool execution (tool.execute.before): Reads the original file, detects its format, and converts content/oldString/newString in the tool args before they reach disk. Normalizing oldString ensures the edit tool's string-matching succeeds even when the LLM generates it with incorrect line endings.

    • After file edits (file.edited event): Re-reads the file as raw bytes, applies the full format pipeline (strip BOM → decode → normalize endings → encode → prepend BOM), and writes back only if something changed. This is the safety net for partial edits that produce mixed line endings.

    Installing as a local file

    Copy index.ts into your .opencode/plugins/ directory. No additional dependencies are needed (only Node.js built-ins are used).

    Project-level:

    cp index.ts <project>/.opencode/plugins/preserve-format.ts
    

    Global:

    cp index.ts ~/.config/opencode/plugins/preserve-format.ts
    

    Debugging

    The plugin logs through ctx.client.app.log() with the service name preserve-format.

    For the fastest debug loop:

    1. Install the plugin as a local file from index.ts.
    2. Start OpenCode with the plugin enabled for the project.
    3. Edit a file with known line endings or BOM.
    4. Check the OpenCode logs for entries from service=preserve-format.

    Useful log messages include:

    • plugin loaded
    • tool: write / tool: edit / tool: multiedit / tool: apply_patch
    • write -> crlf or write -> lf
    • normalized file
    • could not read format
    • could not normalize file

    To exercise the full pipeline manually, test with an existing CRLF or BOM-marked file, make an edit through OpenCode, then confirm the file still has the same BOM and dominant line ending after the write completes.

    Running tests

    Install dependencies, then run:

    npm test
    

    Other useful checks:

    npm run typecheck
    npm run build
    

    Manual test matrix

    Scenario Expected behaviour
    UTF-8, CRLF, no BOM All line endings remain CRLF
    UTF-8, LF, no BOM All line endings remain LF
    UTF-8, CRLF, with BOM BOM preserved, all CRLF
    UTF-8, LF, with BOM BOM preserved, all LF
    UTF-16 LE with BOM BOM preserved, correct encoding, endings preserved
    UTF-16 BE with BOM BOM preserved, correct encoding, endings preserved
    New file (write) Ending detected from AI content; no BOM added
    Binary file (.png, .zip, etc.) No-op
    Mixed endings (70 CRLF / 30 LF) Normalized to CRLF
    Unreadable file Warning logged; file passes through unmodified