diff --git a/src/application/ClientConfigurationDocument.capacity.test.ts b/src/application/ClientConfigurationDocument.capacity.test.ts index e8670bdd09..190435a363 100644 --- a/src/application/ClientConfigurationDocument.capacity.test.ts +++ b/src/application/ClientConfigurationDocument.capacity.test.ts @@ -9,6 +9,50 @@ import { const registration = { command: "rea", args: ["mcp"] }; describe("TOML configuration source capacity", () => { + it.each(["\n", "\r\n"])( + "retains adjacent assignments and multiline values with %j breaks", + (newline) => { + const prefix = Array.from( + { length: 128 }, + (_, index) => + `[foreign.entry_${index}]\nvalue = ${index}\nnote = """first\n# [mcp_servers.rea]\nlast"""\nitems = [\n${index},\n]\n`, + ).join(""); + // Include a BOM, an empty value, and a final statement without a newline. + const original = + "\uFEFF" + + `${prefix}[mcp_servers.rea]\ncommand = "previous"\n[tail]\nempty = ""\nlast = 7`.replaceAll( + "\n", + newline, + ); + const parsed = parseClientConfiguration(original, "toml"); + const desired = withClientServers(parsed, { + ...parsed.servers, + rea: registration, + }); + const configured = serializeClientConfiguration( + desired, + "toml", + original, + ); + expect( + configured.startsWith("\uFEFF" + prefix.replaceAll("\n", newline)), + ).toBe(true); + expect(parseClientConfiguration(configured, "toml").document).toEqual( + desired, + ); + const removed = serializeClientConfiguration( + withClientServers(parsed, {}), + "toml", + configured, + ); + const expectedForeignDocument = { ...parsed.document }; + delete expectedForeignDocument.mcp_servers; + expect(parseClientConfiguration(removed, "toml").document).toEqual( + expectedForeignDocument, + ); + }, + ); + it("retains a large multiline foreign value inside an inline server table", () => { const note = `first\n${"x\n".repeat(500_000)}last`; const original = `mcp_servers = { other = {command="other",env={NOTE="""${note}"""}}}\n`; diff --git a/src/application/ClientConfigurationDocument.ts b/src/application/ClientConfigurationDocument.ts index 2fb2ee35f0..48724bf1c7 100644 --- a/src/application/ClientConfigurationDocument.ts +++ b/src/application/ClientConfigurationDocument.ts @@ -975,12 +975,6 @@ const upsertTomlServerSection = ( appendLines(pending); pending.length = 0; }; - const lineIndexAt = (offset: number): number => { - let line = 0; - for (let index = 0; index < lineStarts.length; index += 1) - if ((lineStarts[index] ?? 0) <= offset) line = index; - return line; - }; let lineIndex = 0; while (lineIndex < lines.length) { const physical = lines[lineIndex] ?? ""; @@ -1015,7 +1009,14 @@ const upsertTomlServerSection = ( let statementEnd = valueEnd; while (statementEnd < text.length && text[statementEnd] !== "\n") statementEnd += 1; - const endLine = lineIndexAt(Math.max(statementEnd - 1, lineStart)); + const lastOffset = Math.max(statementEnd - 1, lineStart); + let endLine = lineIndex; + // Statements advance through the source; only inspect their own lines. + while ( + endLine + 1 < lineStarts.length && + (lineStarts[endLine + 1] ?? 0) <= lastOffset + ) + endLine += 1; if (skipping) { discardPending(); lineIndex = endLine + 1;