Handle rename & deletes in proposal

This commit is contained in:
Will Chen
2025-04-21 16:19:40 -07:00
parent b07defc9b8
commit 7041525c20
3 changed files with 59 additions and 18 deletions

View File

@@ -10,6 +10,8 @@ import {
Check, Check,
Loader2, Loader2,
Package, Package,
FileX,
SendToBack,
} from "lucide-react"; } from "lucide-react";
import type React from "react"; import type React from "react";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
@@ -32,6 +34,7 @@ import {
Proposal, Proposal,
SuggestedAction, SuggestedAction,
ProposalResult, ProposalResult,
FileChange,
} from "@/lib/schemas"; } from "@/lib/schemas";
import type { Message } from "@/ipc/ipc_types"; import type { Message } from "@/ipc/ipc_types";
import { isPreviewOpenAtom } from "@/atoms/viewAtoms"; import { isPreviewOpenAtom } from "@/atoms/viewAtoms";
@@ -461,10 +464,7 @@ function ChatInputActions({
<ul className="space-y-1"> <ul className="space-y-1">
{proposal.filesChanged.map((file, index) => ( {proposal.filesChanged.map((file, index) => (
<li key={index} className="flex items-center space-x-2"> <li key={index} className="flex items-center space-x-2">
<FileText {getIconForFileChange(file)}
size={16}
className="text-muted-foreground flex-shrink-0"
/>
<span title={file.path} className="truncate cursor-default"> <span title={file.path} className="truncate cursor-default">
{file.name} {file.name}
</span> </span>
@@ -481,3 +481,20 @@ function ChatInputActions({
</div> </div>
); );
} }
function getIconForFileChange(file: FileChange) {
switch (file.type) {
case "write":
return (
<FileText size={16} className="text-muted-foreground flex-shrink-0" />
);
case "rename":
return (
<SendToBack size={16} className="text-muted-foreground flex-shrink-0" />
);
case "delete":
return (
<FileX size={16} className="text-muted-foreground flex-shrink-0" />
);
}
}

View File

@@ -1,5 +1,9 @@
import { ipcMain, type IpcMainInvokeEvent } from "electron"; import { ipcMain, type IpcMainInvokeEvent } from "electron";
import type { CodeProposal, ProposalResult } from "@/lib/schemas"; import type {
CodeProposal,
FileChange,
ProposalResult,
} from "../../lib/schemas";
import { db } from "../../db"; import { db } from "../../db";
import { messages } from "../../db/schema"; import { messages } from "../../db/schema";
import { desc, eq, and, Update } from "drizzle-orm"; import { desc, eq, and, Update } from "drizzle-orm";
@@ -8,6 +12,8 @@ import path from "node:path"; // Import path for basename
import { import {
getDyadAddDependencyTags, getDyadAddDependencyTags,
getDyadChatSummaryTag, getDyadChatSummaryTag,
getDyadDeleteTags,
getDyadRenameTags,
getDyadWriteTags, getDyadWriteTags,
processFullResponseActions, processFullResponseActions,
} from "../processors/response_processor"; } from "../processors/response_processor";
@@ -65,34 +71,51 @@ const getProposalHandler = async (
); );
const messageContent = latestAssistantMessage.content; const messageContent = latestAssistantMessage.content;
// Parse tags directly from message content
const proposalTitle = getDyadChatSummaryTag(messageContent); const proposalTitle = getDyadChatSummaryTag(messageContent);
const proposalFiles = getDyadWriteTags(messageContent); // Gets { path: string, content: string }[]
const proposalWriteFiles = getDyadWriteTags(messageContent);
const proposalRenameFiles = getDyadRenameTags(messageContent);
const proposalDeleteFiles = getDyadDeleteTags(messageContent);
const packagesAdded = getDyadAddDependencyTags(messageContent); const packagesAdded = getDyadAddDependencyTags(messageContent);
const filesChanged = [
...proposalWriteFiles.map((tag) => ({
name: path.basename(tag.path),
path: tag.path,
summary: tag.description ?? "(no change summary found)", // Generic summary
type: "write" as const,
})),
...proposalRenameFiles.map((tag) => ({
name: path.basename(tag.to),
path: tag.to,
summary: `Rename from ${tag.from} to ${tag.to}`,
type: "rename" as const,
})),
...proposalDeleteFiles.map((tag) => ({
name: path.basename(tag),
path: tag,
summary: `Delete file`,
type: "delete" as const,
})),
];
// Check if we have enough information to create a proposal // Check if we have enough information to create a proposal
if ( if (filesChanged.length > 0 || packagesAdded.length > 0) {
proposalTitle ||
proposalFiles.length > 0 ||
packagesAdded.length > 0
) {
const proposal: CodeProposal = { const proposal: CodeProposal = {
type: "code-proposal", type: "code-proposal",
// Use parsed title or a default title if summary tag is missing but write tags exist // Use parsed title or a default title if summary tag is missing but write tags exist
title: proposalTitle ?? "Proposed File Changes", title: proposalTitle ?? "Proposed File Changes",
securityRisks: [], // Keep empty securityRisks: [], // Keep empty
filesChanged: proposalFiles.map((tag) => ({ filesChanged,
name: path.basename(tag.path),
path: tag.path,
summary: tag.description ?? "(no change summary found)", // Generic summary
})),
packagesAdded, packagesAdded,
}; };
logger.log( logger.log(
"Generated code proposal. title=", "Generated code proposal. title=",
proposal.title, proposal.title,
"files=", "files=",
proposal.filesChanged.length proposal.filesChanged.length,
"packages=",
proposal.packagesAdded.length
); );
return { proposal, chatId, messageId }; // Return proposal and messageId return { proposal, chatId, messageId }; // Return proposal and messageId
} else { } else {

View File

@@ -111,6 +111,7 @@ export interface FileChange {
name: string; name: string;
path: string; path: string;
summary: string; summary: string;
type: "write" | "rename" | "delete";
} }
export interface CodeProposal { export interface CodeProposal {