Skip to content

Commit 3a325a6

Browse files
celestial-vaultElephant Lumps
andauthored
Open the hood (RooCodeInc#3949)
* add open disk conversation history button * changeset * change icon due to lack of artistic freedom --------- Co-authored-by: Elephant Lumps <[email protected]>
1 parent f73172a commit 3a325a6

File tree

11 files changed

+164
-137
lines changed

11 files changed

+164
-137
lines changed

.changeset/gorgeous-mugs-repair.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"claude-dev": minor
3+
---
4+
5+
Add dev only button to open task conversation history

proto/file.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ service FileService {
5252

5353
// Refreshes all rule toggles (Cline, External, and Workflows)
5454
rpc refreshRules(EmptyRequest) returns (RefreshedRules);
55+
56+
// Opens a task's conversation history file on disk
57+
rpc openTaskHistory(StringRequest) returns (Empty);
5558
}
5659

5760
// Response for refreshRules operation
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Controller } from ".."
2+
import { Empty, StringRequest } from "@shared/proto/common"
3+
import { openFile as openFileIntegration } from "@integrations/misc/open-file"
4+
import { FileMethodHandler } from "./index"
5+
import path from "path"
6+
/**
7+
* Opens a file in the editor
8+
* @param controller The controller instance
9+
* @param request The request message containing the file path in the 'value' field
10+
* @returns Empty response
11+
*/
12+
export const openTaskHistory: FileMethodHandler = async (controller: Controller, request: StringRequest): Promise<Empty> => {
13+
const globalStoragePath = controller.context.globalStorageUri.fsPath
14+
const taskHistoryPath = path.join(globalStoragePath, "tasks", request.value, "api_conversation_history.json")
15+
if (request.value) {
16+
openFileIntegration(taskHistoryPath)
17+
}
18+
return Empty.create()
19+
}

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import BrowserSessionRow from "@/components/chat/BrowserSessionRow"
2626
import ChatRow from "@/components/chat/ChatRow"
2727
import ChatTextArea from "@/components/chat/ChatTextArea"
2828
import QuotedMessagePreview from "@/components/chat/QuotedMessagePreview"
29-
import TaskHeader from "@/components/chat/TaskHeader"
29+
import TaskHeader from "@/components/chat/task-header/TaskHeader"
3030
import TelemetryBanner from "@/components/common/TelemetryBanner"
3131
import { unified } from "unified"
3232
import remarkStringify from "remark-stringify"

webview-ui/src/components/chat/UserMessage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ClineCheckpointRestore } from "@shared/WebviewMessage"
55
import { CheckpointRestoreRequest } from "@shared/proto/checkpoints"
66
import React, { forwardRef, useRef, useState } from "react"
77
import DynamicTextArea from "react-textarea-autosize"
8-
import { highlightText } from "./TaskHeader"
8+
import { highlightText } from "./task-header/TaskHeader"
99

1010
interface UserMessageProps {
1111
text?: string

webview-ui/src/components/chat/TaskHeader.tsx renamed to webview-ui/src/components/chat/task-header/TaskHeader.tsx

Lines changed: 16 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
1212
import React, { memo, useEffect, useMemo, useRef, useState } from "react"
1313
import { useWindowSize } from "react-use"
1414
import TaskTimeline from "./TaskTimeline"
15+
import DeleteTaskButton from "./buttons/DeleteTaskButton"
16+
import CopyTaskButton from "./buttons/CopyTaskButton"
17+
import OpenDiskTaskHistoryButton from "./buttons/OpenDiskTaskHistoryButton"
18+
1519
const { IS_DEV } = process.env
1620

1721
interface TaskHeaderProps {
@@ -412,9 +416,12 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
412416
</div>
413417
{!shouldShowPromptCacheInfo() && (
414418
<div className="flex items-center flex-wrap">
415-
<CopyButton taskText={task.text} />
416-
{IS_DEV === '"true"' && <TaskFolderButton taskId={currentTaskItem?.id} />}
417-
<DeleteButton taskSize={formatSize(currentTaskItem?.size)} taskId={currentTaskItem?.id} />
419+
{IS_DEV === '"true"' && <OpenDiskTaskHistoryButton taskId={currentTaskItem?.id} />}
420+
<CopyTaskButton taskText={task.text} />
421+
<DeleteTaskButton
422+
taskSize={formatSize(currentTaskItem?.size)}
423+
taskId={currentTaskItem?.id}
424+
/>
418425
</div>
419426
)}
420427
</div>
@@ -468,9 +475,12 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
468475
)}
469476
</div>
470477
<div className="flex items-center flex-wrap">
471-
<CopyButton taskText={task.text} />
472-
{IS_DEV === '"true"' && <TaskFolderButton taskId={currentTaskItem?.id} />}
473-
<DeleteButton taskSize={formatSize(currentTaskItem?.size)} taskId={currentTaskItem?.id} />
478+
{IS_DEV === '"true"' && <OpenDiskTaskHistoryButton taskId={currentTaskItem?.id} />}
479+
<CopyTaskButton taskText={task.text} />
480+
<DeleteTaskButton
481+
taskSize={formatSize(currentTaskItem?.size)}
482+
taskId={currentTaskItem?.id}
483+
/>
474484
</div>
475485
</div>
476486
)}
@@ -533,34 +543,6 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
533543
</>
534544
)}
535545
</div>
536-
{/* {apiProvider === "" && (
537-
<div
538-
style={{
539-
backgroundColor: "color-mix(in srgb, var(--vscode-badge-background) 50%, transparent)",
540-
color: "var(--vscode-badge-foreground)",
541-
borderRadius: "0 0 3px 3px",
542-
display: "flex",
543-
justifyContent: "space-between",
544-
alignItems: "center",
545-
padding: "4px 12px 6px 12px",
546-
fontSize: "0.9em",
547-
marginLeft: "10px",
548-
marginRight: "10px",
549-
}}>
550-
<div style={{ fontWeight: "500" }}>Credits Remaining:</div>
551-
<div>
552-
{formatPrice(Credits || 0)}
553-
{(Credits || 0) < 1 && (
554-
<>
555-
{" "}
556-
<VSCodeLink style={{ fontSize: "0.9em" }} href={getAddCreditsUrl(vscodeUriScheme)}>
557-
(get more?)
558-
</VSCodeLink>
559-
</>
560-
)}
561-
</div>
562-
</div>
563-
)} */}
564546
</div>
565547
)
566548
}
@@ -643,103 +625,4 @@ export const highlightText = (text?: string, withShadow = true) => {
643625
return [text]
644626
}
645627

646-
const CopyButton: React.FC<{
647-
taskText?: string
648-
}> = ({ taskText }) => {
649-
const [copied, setCopied] = useState(false)
650-
651-
const handleCopy = () => {
652-
if (!taskText) return
653-
654-
navigator.clipboard.writeText(taskText).then(() => {
655-
setCopied(true)
656-
setTimeout(() => setCopied(false), 1500)
657-
})
658-
}
659-
660-
return (
661-
<HeroTooltip content="Copy Task">
662-
<VSCodeButton
663-
appearance="icon"
664-
onClick={handleCopy}
665-
style={{ padding: "0px 0px" }}
666-
className="p-0"
667-
aria-label="Copy Task">
668-
<div className="flex items-center gap-[3px] text-[8px] font-bold opacity-60">
669-
<i className={`codicon codicon-${copied ? "check" : "copy"}`} />
670-
</div>
671-
</VSCodeButton>
672-
</HeroTooltip>
673-
)
674-
}
675-
676-
const TaskFolderButton: React.FC<{
677-
taskId?: string
678-
}> = ({ taskId }) => {
679-
const [copied, setCopied] = useState(false)
680-
681-
const handleCopy = () => {
682-
if (!taskId) return
683-
684-
navigator.clipboard.writeText(taskId).then(() => {
685-
setCopied(true)
686-
setTimeout(() => setCopied(false), 1500)
687-
})
688-
}
689-
690-
return (
691-
<HeroTooltip content="Copy Task ID">
692-
<VSCodeButton
693-
appearance="icon"
694-
onClick={handleCopy}
695-
style={{ padding: "0px 0px" }}
696-
className="p-0"
697-
aria-label="Copy Task ID">
698-
<div className="flex items-center gap-[3px] text-[8px] font-bold opacity-60">
699-
<i className={`codicon codicon-${copied ? "check" : "folder"}`} />
700-
</div>
701-
</VSCodeButton>
702-
</HeroTooltip>
703-
)
704-
}
705-
706-
const DeleteButton: React.FC<{
707-
taskSize: string
708-
taskId?: string
709-
}> = ({ taskSize, taskId }) => (
710-
<HeroTooltip content="Delete Task & Checkpoints">
711-
<VSCodeButton
712-
appearance="icon"
713-
onClick={() => taskId && TaskServiceClient.deleteTasksWithIds(StringArrayRequest.create({ value: [taskId] }))}
714-
style={{ padding: "0px 0px" }}>
715-
<div
716-
style={{
717-
display: "flex",
718-
alignItems: "center",
719-
gap: "3px",
720-
fontSize: "10px",
721-
fontWeight: "bold",
722-
opacity: 0.6,
723-
}}>
724-
<i className={`codicon codicon-trash`} />
725-
{taskSize}
726-
</div>
727-
</VSCodeButton>
728-
</HeroTooltip>
729-
)
730-
731-
// const ExportButton = () => (
732-
// <VSCodeButton
733-
// appearance="icon"
734-
// onClick={() => vscode.postMessage({ type: "exportCurrentTask" })}
735-
// style={
736-
// {
737-
// // marginBottom: "-2px",
738-
// // marginRight: "-2.5px",
739-
// }
740-
// }>
741-
// <div style={{ fontSize: "10.5px", fontWeight: "bold", opacity: 0.6 }}>EXPORT</div>
742-
// </VSCodeButton>
743-
// )
744-
745628
export default memo(TaskHeader)

webview-ui/src/components/chat/TaskTimeline.tsx renamed to webview-ui/src/components/chat/task-header/TaskTimeline.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,16 @@ import { ClineMessage } from "@shared/ExtensionMessage"
44
import { combineApiRequests } from "@shared/combineApiRequests"
55
import { combineCommandSequences } from "@shared/combineCommandSequences"
66
import TaskTimelineTooltip from "./TaskTimelineTooltip"
7-
import { COLOR_WHITE, COLOR_GRAY, COLOR_DARK_GRAY, COLOR_BEIGE, COLOR_BLUE, COLOR_RED, COLOR_PURPLE, COLOR_GREEN } from "./colors"
7+
import {
8+
COLOR_WHITE,
9+
COLOR_GRAY,
10+
COLOR_DARK_GRAY,
11+
COLOR_BEIGE,
12+
COLOR_BLUE,
13+
COLOR_RED,
14+
COLOR_PURPLE,
15+
COLOR_GREEN,
16+
} from "../colors"
817

918
// Timeline dimensions and spacing
1019
const TIMELINE_HEIGHT = "18px"

webview-ui/src/components/chat/TaskTimelineTooltip.tsx renamed to webview-ui/src/components/chat/task-header/TaskTimelineTooltip.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import React from "react"
22
import { ClineMessage } from "@shared/ExtensionMessage"
3-
import { COLOR_WHITE, COLOR_GRAY, COLOR_DARK_GRAY, COLOR_BEIGE, COLOR_BLUE, COLOR_RED, COLOR_PURPLE, COLOR_GREEN } from "./colors"
3+
import {
4+
COLOR_WHITE,
5+
COLOR_GRAY,
6+
COLOR_DARK_GRAY,
7+
COLOR_BEIGE,
8+
COLOR_BLUE,
9+
COLOR_RED,
10+
COLOR_PURPLE,
11+
COLOR_GREEN,
12+
} from "../colors"
413
import { Tooltip } from "@heroui/react"
514

615
// Color mapping for different message types
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import HeroTooltip from "@/components/common/HeroTooltip"
2+
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
3+
import { useState } from "react"
4+
5+
const CopyTaskButton: React.FC<{
6+
taskText?: string
7+
}> = ({ taskText }) => {
8+
const [copied, setCopied] = useState(false)
9+
10+
const handleCopy = () => {
11+
if (!taskText) return
12+
13+
navigator.clipboard.writeText(taskText).then(() => {
14+
setCopied(true)
15+
setTimeout(() => setCopied(false), 1500)
16+
})
17+
}
18+
19+
return (
20+
<HeroTooltip content="Copy Task">
21+
<VSCodeButton
22+
appearance="icon"
23+
onClick={handleCopy}
24+
style={{ padding: "0px 0px" }}
25+
className="p-0"
26+
aria-label="Copy Task">
27+
<div className="flex items-center gap-[3px] text-[8px] font-bold opacity-60">
28+
<i className={`codicon codicon-${copied ? "check" : "copy"}`} />
29+
</div>
30+
</VSCodeButton>
31+
</HeroTooltip>
32+
)
33+
}
34+
35+
export default CopyTaskButton
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import HeroTooltip from "@/components/common/HeroTooltip"
2+
import { TaskServiceClient } from "@/services/grpc-client"
3+
import { StringArrayRequest } from "@shared/proto/common"
4+
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
5+
6+
const DeleteTaskButton: React.FC<{
7+
taskSize: string
8+
taskId?: string
9+
}> = ({ taskSize, taskId }) => (
10+
<HeroTooltip content="Delete Task & Checkpoints">
11+
<VSCodeButton
12+
appearance="icon"
13+
onClick={() => taskId && TaskServiceClient.deleteTasksWithIds(StringArrayRequest.create({ value: [taskId] }))}
14+
style={{ padding: "0px 0px" }}>
15+
<div
16+
style={{
17+
display: "flex",
18+
alignItems: "center",
19+
gap: "3px",
20+
fontSize: "10px",
21+
fontWeight: "bold",
22+
opacity: 0.6,
23+
}}>
24+
<i className={`codicon codicon-trash`} />
25+
{taskSize}
26+
</div>
27+
</VSCodeButton>
28+
</HeroTooltip>
29+
)
30+
31+
export default DeleteTaskButton

0 commit comments

Comments
 (0)