Files
kandev/apps/web/lib/state/slices/comments/format.ts
T
João Salavisa f74de1c642 fix: improve plan comment formatting to match code review style (#600)
* fix: improve plan comment formatting to match code review style

- Update formatPlanCommentsAsMarkdown to use code blocks and blockquotes
- Remove duplicate header in chat-input-area.tsx
- Update buildDocumentContext to use consistent formatting
- Fixes duplicate '### Plan Comments' headers and extra separators

* fix: add tests and fix multiline blockquote handling

- Add format.test.ts for formatPlanCommentsAsMarkdown and related functions
- Fix multiline comment text to properly prefix each line with >
- Addresses review feedback about missing tests and broken blockquotes

* fix: export and reuse toBlockquote helper to avoid duplication

* fix: update E2E test to match new plan comment format

The test was expecting 'Comment 1:' which was the old bullet-style format.
Now looks for 'Plan Comments' header instead.
2026-04-16 02:57:41 +01:00

108 lines
3.0 KiB
TypeScript

import type { Comment, DiffComment, PlanComment, PRFeedbackComment } from "./types";
import { isDiffComment, isPlanComment, isPRFeedbackComment } from "./types";
/**
* Format diff review comments as human-readable markdown for sending to agent.
*/
export function formatReviewCommentsAsMarkdown(comments: DiffComment[]): string {
if (!comments || comments.length === 0) return "";
const lines: string[] = ["### Review Comments", ""];
const byFile = new Map<string, DiffComment[]>();
for (const comment of comments) {
const existing = byFile.get(comment.filePath) || [];
existing.push(comment);
byFile.set(comment.filePath, existing);
}
for (const [filePath, fileComments] of byFile) {
for (const comment of fileComments) {
const lineRange =
comment.startLine === comment.endLine
? `${comment.startLine}`
: `${comment.startLine}-${comment.endLine}`;
lines.push(`**${filePath}:${lineRange}**`);
lines.push("```");
lines.push(comment.codeContent);
lines.push("```");
lines.push(`> ${comment.text}`);
lines.push("");
}
}
lines.push("---");
lines.push("");
return lines.join("\n");
}
/** Convert text to blockquote, handling multiline text properly. */
export function toBlockquote(text: string): string {
return text
.split("\n")
.map((line) => `> ${line}`)
.join("\n");
}
/**
* Format plan comments as markdown for sending to agent.
* Uses the same style as code review comments: code block for selected text + blockquote for comment.
*/
export function formatPlanCommentsAsMarkdown(comments: PlanComment[]): string {
if (!comments || comments.length === 0) return "";
const lines: string[] = ["### Plan Comments", ""];
for (const c of comments) {
if (c.selectedText) {
lines.push("```");
lines.push(c.selectedText);
lines.push("```");
}
lines.push(toBlockquote(c.text));
lines.push("");
}
lines.push("---");
lines.push("");
return lines.join("\n");
}
/**
* Format PR feedback comments as markdown for sending to agent.
*/
export function formatPRFeedbackAsMarkdown(comments: PRFeedbackComment[]): string {
if (!comments || comments.length === 0) return "";
const lines: string[] = ["### PR Feedback", ""];
for (const c of comments) {
lines.push(c.content);
lines.push("");
}
lines.push("---");
lines.push("");
return lines.join("\n");
}
/**
* Format all pending comments for inclusion in a chat message.
*/
export function formatCommentsForMessage(comments: Comment[]): {
diffComments: DiffComment[];
planComments: PlanComment[];
prFeedbackComments: PRFeedbackComment[];
} {
const diffComments: DiffComment[] = [];
const planComments: PlanComment[] = [];
const prFeedbackComments: PRFeedbackComment[] = [];
for (const c of comments) {
if (isDiffComment(c)) diffComments.push(c);
else if (isPlanComment(c)) planComments.push(c);
else if (isPRFeedbackComment(c)) prFeedbackComments.push(c);
}
return { diffComments, planComments, prFeedbackComments };
}