diff --git a/src/server/services/agent/__tests__/fileChanges.test.ts b/src/server/services/agent/__tests__/fileChanges.test.ts new file mode 100644 index 0000000..194ba93 --- /dev/null +++ b/src/server/services/agent/__tests__/fileChanges.test.ts @@ -0,0 +1,66 @@ +/** + * Copyright 2026 GoodRx, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { buildProposedFileChanges } from '../fileChanges'; + +describe('buildProposedFileChanges', () => { + it('keeps workspace edit approvals as before-and-after previews instead of fake diffs', () => { + const [change] = buildProposedFileChanges({ + toolCallId: 'tool-1', + sourceTool: 'workspace.edit_file', + input: { + path: '/workspace/sample-service/app.js', + oldText: 'before', + newText: 'after', + }, + }); + + expect(change).toMatchObject({ + id: 'tool-1:sample-service/app.js', + toolCallId: 'tool-1', + sourceTool: 'workspace.edit_file', + path: '/workspace/sample-service/app.js', + displayPath: 'sample-service/app.js', + stage: 'awaiting-approval', + unifiedDiff: null, + beforeTextPreview: 'before', + afterTextPreview: 'after', + }); + }); + + it('keeps workspace writes as preview-only changes', () => { + const [change] = buildProposedFileChanges({ + toolCallId: 'tool-2', + sourceTool: 'workspace.write_file', + input: { + path: '/workspace/sample-service/README.md', + content: '# Sample service', + }, + }); + + expect(change).toMatchObject({ + id: 'tool-2:sample-service/README.md', + toolCallId: 'tool-2', + sourceTool: 'workspace.write_file', + path: '/workspace/sample-service/README.md', + displayPath: 'sample-service/README.md', + stage: 'awaiting-approval', + unifiedDiff: null, + beforeTextPreview: null, + afterTextPreview: '# Sample service', + }); + }); +}); diff --git a/src/server/services/agent/fileChanges.ts b/src/server/services/agent/fileChanges.ts index 8ed7064..f84ec41 100644 --- a/src/server/services/agent/fileChanges.ts +++ b/src/server/services/agent/fileChanges.ts @@ -92,25 +92,6 @@ function countChangedLines(value: string): number { return value.split('\n').length; } -function buildUnifiedDiff(path: string, before: string, after: string): string | null { - if (before === after) { - return null; - } - - const displayPath = trimWorkspacePrefix(path); - const beforeLines = before.split('\n'); - const afterLines = after.split('\n'); - - return [ - `diff --git a/${displayPath} b/${displayPath}`, - `--- a/${displayPath}`, - `+++ b/${displayPath}`, - `@@ -1,${beforeLines.length} +1,${afterLines.length} @@`, - ...beforeLines.map((line) => `-${line}`), - ...afterLines.map((line) => `+${line}`), - ].join('\n'); -} - function unwrapToolPayload(value: unknown): unknown { if (!isRecord(value) || !Array.isArray(value.content)) { return value; @@ -270,7 +251,7 @@ export function buildProposedFileChanges({ additions: countChangedLines(args.newText), deletions: countChangedLines(args.oldText), truncated: false, - unifiedDiff: buildUnifiedDiff(args.path, args.oldText, args.newText), + unifiedDiff: null, beforeTextPreview: args.oldText, afterTextPreview: args.newText, summary: `Proposed update to ${trimWorkspacePrefix(args.path)}`,