Skip to content

Commit f188080

Browse files
chat response showing
1 parent 8ff6362 commit f188080

File tree

5 files changed

+200
-1
lines changed

5 files changed

+200
-1
lines changed

creatormodetask.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ We are implementing a **new view called Creator Mode** into this extension. The
1414
- **Flexible Code Organization:** While separation is preferred, prioritize maintainability and efficiency over strict separation.
1515
- **Keep This Document Updated:** Ensure this file always reflects the latest task status for continuity.
1616
- **Clear and Concise Development:** No unnecessary complexity—keep solutions to the point and functional.
17+
- no bs.
18+
- dont hallucinate.
1719

1820
## Creator Mode Details
1921

src/shared/ExtensionMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface ExtensionMessage {
4545
| "updateCustomMode"
4646
| "deleteCustomMode"
4747
| "currentCheckpointUpdated"
48+
| "creator"
4849
text?: string
4950
action?:
5051
| "chatButtonClicked"
@@ -53,6 +54,7 @@ export interface ExtensionMessage {
5354
| "historyButtonClicked"
5455
| "promptsButtonClicked"
5556
| "didBecomeVisible"
57+
| "generateActionPlan"
5658
invoke?: "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage"
5759
state?: ExtensionState
5860
images?: string[]

src/shared/WebviewMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ export interface WebviewMessage {
9595
| "openPearAiAuth"
9696
| "deleteMcpServer"
9797
| "maxOpenTabsContext"
98+
| "creator"
99+
| "generateActionPlan"
98100
text?: string
99101
disabled?: boolean
100102
askResponse?: ClineAskResponse

src/shared/modes.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ export function getToolsForMode(groups: readonly GroupEntry[]): string[] {
7474

7575
// Main modes configuration as an ordered array
7676
export const modes: readonly ModeConfig[] = [
77+
{
78+
slug: "creator",
79+
name: "Creator",
80+
roleDefinition:
81+
"You are PearAI Agent (Powered by Roo Code / Cline), a creative and systematic software architect focused on turning high-level ideas into actionable plans. Your primary goal is to help users transform their ideas into structured action plans.",
82+
groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "browser", "mcp"],
83+
customInstructions:
84+
"Your role is to help users transform their ideas into concrete action plans. When a user provides a prompt, analyze it carefully and create a detailed, step-by-step plan that outlines how to implement their idea. Focus on breaking down complex tasks into manageable steps, considering technical requirements, potential challenges, and best practices. The plan should be clear enough that it can be directly implemented by switching to Code mode afterward.",
85+
},
7786
{
7887
slug: "code",
7988
name: "Code",

webview-ui/src/creator/creator.tsx

Lines changed: 185 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,189 @@
1+
import { useState, useCallback, useEffect, useRef } from "react"
2+
import { vscode } from "../utils/vscode"
3+
import { WebviewMessage } from "../../../src/shared/WebviewMessage"
4+
import { ExtensionMessage, ClineMessage } from "../../../src/shared/ExtensionMessage"
5+
import { Markdown } from "../components/ui/markdown"
6+
7+
interface Message {
8+
role: "user" | "assistant"
9+
content: string
10+
timestamp: number
11+
}
12+
113
const Creator = () => {
2-
return <div>creator hell yeah.</div>
14+
const [prompt, setPrompt] = useState("")
15+
const [isProcessing, setIsProcessing] = useState(false)
16+
const [response, setResponse] = useState<ClineMessage | null>(null)
17+
const [messages, setMessages] = useState<Message[]>([])
18+
const [isLoading, setIsLoading] = useState(false)
19+
const [inputValue, setInputValue] = useState("")
20+
const messagesEndRef = useRef<HTMLDivElement>(null)
21+
22+
const handleSubmit = async (e: React.FormEvent) => {
23+
e.preventDefault()
24+
if (!prompt.trim() || isProcessing) return
25+
26+
setIsProcessing(true)
27+
try {
28+
const message: WebviewMessage = {
29+
type: "creator",
30+
text: prompt.trim(),
31+
}
32+
await vscode.postMessage(message)
33+
setPrompt("")
34+
} finally {
35+
setIsProcessing(false)
36+
}
37+
}
38+
39+
const handleMessage = useCallback((e: MessageEvent<ExtensionMessage>) => {
40+
const message = e.data
41+
if (message.type === "partialMessage" && message.partialMessage) {
42+
setResponse(message.partialMessage)
43+
}
44+
}, [])
45+
46+
const scrollToBottom = () => {
47+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
48+
}
49+
50+
useEffect(() => {
51+
scrollToBottom()
52+
}, [messages])
53+
54+
const handleSendMessage = useCallback((text: string) => {
55+
if (!text.trim()) return
56+
57+
// Add user message to chat
58+
setMessages((prev) => [
59+
...prev,
60+
{
61+
role: "user",
62+
content: text.trim(),
63+
timestamp: Date.now(),
64+
},
65+
])
66+
67+
setIsLoading(true)
68+
69+
// Send message to extension
70+
vscode.postMessage({
71+
type: "newTask",
72+
text: text.trim(),
73+
})
74+
}, [])
75+
76+
// Add message event listener
77+
useEffect(() => {
78+
const handleMessage = (event: MessageEvent) => {
79+
const message = event.data
80+
81+
if (message.type === "partialMessage" && message.partialMessage) {
82+
// Handle streaming response
83+
setMessages((prev) => {
84+
const lastMessage = prev[prev.length - 1]
85+
if (lastMessage?.role === "assistant") {
86+
// Update existing assistant message
87+
return [
88+
...prev.slice(0, -1),
89+
{
90+
...lastMessage,
91+
content: lastMessage.content + message.partialMessage.text,
92+
},
93+
]
94+
} else {
95+
// Add new assistant message
96+
return [
97+
...prev,
98+
{
99+
role: "assistant",
100+
content: message.partialMessage.text || "",
101+
timestamp: Date.now(),
102+
},
103+
]
104+
}
105+
})
106+
setIsLoading(false)
107+
}
108+
}
109+
110+
window.addEventListener("message", handleMessage)
111+
return () => window.removeEventListener("message", handleMessage)
112+
}, [])
113+
114+
return (
115+
<div className="flex flex-col h-screen p-4 bg-background text-foreground">
116+
{/* Messages container with scrolling */}
117+
<div className="flex-1 overflow-y-auto space-y-4 mb-4">
118+
{messages.map((msg, i) => (
119+
<div
120+
key={msg.timestamp}
121+
className={`max-w-[80%] rounded-lg p-4 animate-fade-in transition-all duration-200 ease-in-out hover:shadow-lg ${
122+
msg.role === "user"
123+
? "ml-auto bg-[#E64C9E] text-white hover:bg-[#D33C8E]"
124+
: "bg-editor-background border border-input-border hover:border-[#E64C9E]"
125+
}`}>
126+
{/* Use Markdown component for messages */}
127+
<Markdown content={msg.content} />
128+
</div>
129+
))}
130+
131+
{isLoading && (
132+
<div className="text-muted-foreground text-center py-4 animate-pulse">
133+
<div className="flex items-center justify-center gap-2">
134+
<div className="w-2 h-2 bg-[#E64C9E] rounded-full animate-bounce"></div>
135+
<div className="w-2 h-2 bg-[#E64C9E] rounded-full animate-bounce delay-100"></div>
136+
<div className="w-2 h-2 bg-[#E64C9E] rounded-full animate-bounce delay-200"></div>
137+
</div>
138+
</div>
139+
)}
140+
141+
{/* Scroll anchor */}
142+
<div ref={messagesEndRef} />
143+
</div>
144+
145+
{/* Input container */}
146+
<div className="flex items-end gap-4 mt-auto p-4 bg-editor-background rounded-lg border border-input-border">
147+
<div className="flex-1">
148+
<textarea
149+
value={inputValue}
150+
onChange={(e) => setInputValue(e.target.value)}
151+
onKeyPress={(e) => {
152+
if (e.key === "Enter" && !e.shiftKey) {
153+
e.preventDefault()
154+
handleSendMessage(inputValue)
155+
setInputValue("")
156+
}
157+
}}
158+
placeholder="Type your message..."
159+
rows={1}
160+
className="w-full px-4 py-2 rounded-lg bg-input-background text-input-foreground border-none focus:outline-none focus:ring-2 focus:ring-[#E64C9E] resize-none"
161+
/>
162+
</div>
163+
<button
164+
onClick={() => {
165+
handleSendMessage(inputValue)
166+
setInputValue("")
167+
}}
168+
disabled={isLoading}
169+
className="px-6 py-2 bg-[#E64C9E] text-white rounded-lg flex items-center gap-2 hover:bg-[#D33C8E] disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 ease-in-out transform hover:scale-105 active:scale-95">
170+
<span>Send</span>
171+
<svg
172+
className="w-4 h-4 transition-transform duration-200 group-hover:translate-x-1"
173+
fill="none"
174+
stroke="currentColor"
175+
viewBox="0 0 24 24">
176+
<path
177+
strokeLinecap="round"
178+
strokeLinejoin="round"
179+
strokeWidth={2}
180+
d="M14 5l7 7m0 0l-7 7m7-7H3"
181+
/>
182+
</svg>
183+
</button>
184+
</div>
185+
</div>
186+
)
3187
}
4188

5189
export default Creator

0 commit comments

Comments
 (0)