Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions evals/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ async function testTerminalCommand(
processId: Promise.resolve(123),
creationOptions: {},
exitStatus: undefined,
state: { isInteractedWith: true },
state: { isInteractedWith: true, shell: "/bin/bash" },
dispose: jest.fn(),
hide: jest.fn(),
show: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async function testCmdCommand(
processId: Promise.resolve(123),
creationOptions: {},
exitStatus: undefined,
state: { isInteractedWith: true },
state: { isInteractedWith: true, shell: "C:\\Windows\\System32\\cmd.exe" },
dispose: jest.fn(),
hide: jest.fn(),
show: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async function testPowerShellCommand(
processId: Promise.resolve(123),
creationOptions: {},
exitStatus: undefined,
state: { isInteractedWith: true },
state: { isInteractedWith: true, shell: "pwsh" },
dispose: jest.fn(),
hide: jest.fn(),
show: jest.fn(),
Expand Down
6 changes: 5 additions & 1 deletion src/shared/combineApiRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,11 @@ export function combineApiRequests(messages: ClineMessage[]): ClineMessage[] {
}
} catch (e) {}

result[startIndex] = { ...startMessage, text: JSON.stringify({ ...startData, ...finishData }) }
result[startIndex] = {
...startMessage,
text: JSON.stringify({ ...startData, ...finishData }),
partial: message.partial ?? false,
} // Propagate partial status from the finish message
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/shared/combineCommandSequences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ export function combineCommandSequences(messages: ClineMessage[]): ClineMessage[
j++
}

combinedCommands.push({ ...messages[i], text: combinedText })
const lastIndex = j - 1
const lastMessageInSequence = messages[lastIndex]
combinedCommands.push({
...messages[i],
text: combinedText,
partial: lastMessageInSequence?.partial ?? false, // Propagate partial status from the last message
})

// Move to the index just before the next command or end of array.
i = j - 1
Expand Down
3 changes: 3 additions & 0 deletions webview-ui/jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ module.exports = {
"^src/i18n/TranslationContext$": "<rootDir>/src/__mocks__/i18n/TranslationContext.tsx",
"^\\.\\./TranslationContext$": "<rootDir>/src/__mocks__/i18n/TranslationContext.tsx",
"^\\./TranslationContext$": "<rootDir>/src/__mocks__/i18n/TranslationContext.tsx",
'^react-markdown$': 'identity-obj-proxy',
'^remark-gfm$': 'identity-obj-proxy',
'^shiki$': 'identity-obj-proxy'
},
reporters: [["jest-simple-dot-reporter", {}]],
transformIgnorePatterns: [
Expand Down
14 changes: 10 additions & 4 deletions webview-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 73 additions & 10 deletions webview-ui/src/components/chat/ChatRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { Button } from "@src/components/ui"
import { ToolUseBlock, ToolUseBlockHeader } from "../common/ToolUseBlock"
import CodeAccordian from "../common/CodeAccordian"
import CodeBlock from "../common/CodeBlock"
import MarkdownBlock from "../common/MarkdownBlock"
import { ReasoningBlock } from "./ReasoningBlock"
import Thumbnails from "../common/Thumbnails"
import McpResourceRow from "../mcp/McpResourceRow"
Expand All @@ -27,8 +26,8 @@ import McpToolRow from "../mcp/McpToolRow"
import { Mention } from "./Mention"
import { CheckpointSaved } from "./checkpoints/CheckpointSaved"
import { FollowUpSuggest } from "./FollowUpSuggest"
import { Markdown } from "@/components/ui/markdown/Markdown"
import { ProgressIndicator } from "./ProgressIndicator"
import { Markdown } from "./Markdown"
import { CommandExecution } from "./CommandExecution"
import { CommandExecutionError } from "./CommandExecutionError"

Expand Down Expand Up @@ -80,6 +79,70 @@ const ChatRow = memo(

export default ChatRow

// Define the new wrapper component with copy functionality
const MarkdownWithCopy = memo(({ content, partial }: { content: string; partial?: boolean }) => {
const [isHovering, setIsHovering] = useState(false)
// Assuming useCopyToClipboard is imported correctly (it is, line 5)
const { copyWithFeedback } = useCopyToClipboard(200) // Use shorter feedback duration like original

return (
<div
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
style={{ position: "relative" }}>
{/* Apply negative margins and text wrap styles */}
<div style={{ wordBreak: "break-word", overflowWrap: "anywhere" }}>
<Markdown content={content} isComplete={!partial} />
</div>
{/* Conditional Copy Button */}
{content && !partial && isHovering && (
<div
style={{
position: "absolute",
bottom: "-4px",
right: "8px",
opacity: 0,
animation: "fadeIn 0.2s ease-in-out forwards",
borderRadius: "4px",
}}>
<style>
{`
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1.0; }
}
`}
</style>
<VSCodeButton
className="copy-button"
appearance="icon"
style={{
height: "24px",
border: "none",
background: "var(--vscode-editor-background)",
transition: "background 0.2s ease-in-out",
}}
onClick={async () => {
const success = await copyWithFeedback(content) // Use content prop
if (success) {
const button = document.activeElement as HTMLElement
if (button) {
button.style.background = "var(--vscode-button-background)"
setTimeout(() => {
button.style.background = ""
}, 200)
}
}
}}
title="Copy as markdown">
<span className="codicon codicon-copy"></span>
</VSCodeButton>
</div>
)}
</div>
)
})

export const ChatRowContent = ({
message,
lastModifiedMessage,
Expand Down Expand Up @@ -577,7 +640,7 @@ export const ChatRowContent = ({
{t("chat:subtasks.newTaskContent")}
</div>
<div style={{ padding: "12px 16px", backgroundColor: "var(--vscode-editor-background)" }}>
<MarkdownBlock markdown={tool.content} />
<Markdown content={tool.content || ""} />
</div>
</div>
</>
Expand Down Expand Up @@ -614,7 +677,7 @@ export const ChatRowContent = ({
{t("chat:subtasks.completionContent")}
</div>
<div style={{ padding: "12px 16px", backgroundColor: "var(--vscode-editor-background)" }}>
<MarkdownBlock markdown={t("chat:subtasks.completionInstructions")} />
<Markdown content={t("chat:subtasks.completionInstructions") || ""} />
</div>
</div>
</>
Expand Down Expand Up @@ -748,7 +811,7 @@ export const ChatRowContent = ({
padding: "12px 16px",
backgroundColor: "var(--vscode-editor-background)",
}}>
<MarkdownBlock markdown={message.text} />
<Markdown content={message.text || ""} />
</div>
</div>
</div>
Expand Down Expand Up @@ -830,7 +893,7 @@ export const ChatRowContent = ({
case "text":
return (
<div>
<Markdown markdown={message.text} partial={message.partial} />
<MarkdownWithCopy content={message.text || ""} partial={message.partial} />
</div>
)
case "user_feedback":
Expand Down Expand Up @@ -889,7 +952,7 @@ export const ChatRowContent = ({
{title}
</div>
<div style={{ color: "var(--vscode-charts-green)", paddingTop: 10 }}>
<Markdown markdown={message.text} />
<MarkdownWithCopy content={message.text || ""} partial={message.partial} />
</div>
</>
)
Expand Down Expand Up @@ -936,7 +999,7 @@ export const ChatRowContent = ({
</div>
)}
<div style={{ paddingTop: 10 }}>
<Markdown markdown={message.text} partial={message.partial} />
<MarkdownWithCopy content={message.text || ""} partial={message.partial} />
</div>
</>
)
Expand Down Expand Up @@ -1055,7 +1118,7 @@ export const ChatRowContent = ({
{title}
</div>
<div style={{ color: "var(--vscode-charts-green)", paddingTop: 10 }}>
<Markdown markdown={message.text} partial={message.partial} />
<Markdown content={message.text || ""} />
</div>
</div>
)
Expand All @@ -1073,7 +1136,7 @@ export const ChatRowContent = ({
)}
<div style={{ paddingTop: 10, paddingBottom: 15 }}>
<Markdown
markdown={message.partial === true ? message?.text : followUpData?.question}
content={(message.partial === true ? message?.text : followUpData?.question) || ""}
/>
</div>
<FollowUpSuggest
Expand Down
65 changes: 0 additions & 65 deletions webview-ui/src/components/chat/Markdown.tsx

This file was deleted.

Loading