3e237e177a
* feat: add code-walkthrough backend (MCP tool, service, persistence, WS events) * feat: render agent code walkthroughs as line-anchored cards + editor window * test: add code-walkthrough re-emit mock-agent scenario * fix: rework code-walkthrough UX (floating card, line reveal, minimize, clickable file) * fix: improve code walkthrough editor UX * fix: backfill walkthrough launcher after websocket connect * fix: improve walkthrough requests and editor anchors * fix: clear walkthrough highlights on close * feat: add walkthrough discard and prompt customization * fix: send walkthrough requests through saved prompt * fix: support postgres built-in prompt seeding * fix: address walkthrough review feedback * fix: address walkthrough review follow-ups * fix: harden walkthrough lifecycle races * fix: reuse walkthrough notification cleanup * fix: guard stale walkthrough file opens * fix: abort stale file opens before paint * fix: stabilize github settings e2e readiness * fix: use stable github settings e2e selector
145 lines
4.2 KiB
TypeScript
145 lines
4.2 KiB
TypeScript
import type {
|
|
Comment,
|
|
DiffComment,
|
|
PlanComment,
|
|
PRFeedbackComment,
|
|
WalkthroughComment,
|
|
} from "./types";
|
|
import { isDiffComment, isPlanComment, isPRFeedbackComment, isWalkthroughComment } 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 walkthrough feedback as markdown for sending to agent.
|
|
*/
|
|
export function formatWalkthroughCommentsAsMarkdown(comments: WalkthroughComment[]): string {
|
|
if (!comments || comments.length === 0) return "";
|
|
|
|
const lines: string[] = ["### Walkthrough Feedback", ""];
|
|
for (const c of comments) {
|
|
const lineRange = c.startLine === c.endLine ? `${c.startLine}` : `${c.startLine}-${c.endLine}`;
|
|
const repoPrefix = c.repo ? `${c.repo}/` : "";
|
|
const title = c.walkthroughTitle || "Walkthrough";
|
|
|
|
lines.push(`**${title} · Step ${c.stepIndex + 1} / ${c.stepCount}**`);
|
|
lines.push(`**${repoPrefix}${c.filePath}:${lineRange}**`);
|
|
lines.push("");
|
|
lines.push("Agent walkthrough text:");
|
|
lines.push(toBlockquote(c.stepText));
|
|
lines.push("");
|
|
lines.push("User feedback:");
|
|
lines.push(toBlockquote(c.text));
|
|
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[];
|
|
walkthroughComments: WalkthroughComment[];
|
|
} {
|
|
const diffComments: DiffComment[] = [];
|
|
const planComments: PlanComment[] = [];
|
|
const prFeedbackComments: PRFeedbackComment[] = [];
|
|
const walkthroughComments: WalkthroughComment[] = [];
|
|
|
|
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);
|
|
else if (isWalkthroughComment(c)) walkthroughComments.push(c);
|
|
}
|
|
|
|
return { diffComments, planComments, prFeedbackComments, walkthroughComments };
|
|
}
|