Skip to content

Commit 0730f58

Browse files
committed
Merge branch 'acorn/creator-view-refactored'
2 parents bfc299f + eb384f6 commit 0730f58

File tree

9 files changed

+143
-4
lines changed

9 files changed

+143
-4
lines changed

package-lock.json

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/activate/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { handleUri } from "./handleUri"
22
export { registerCommands } from "./registerCommands"
33
export { registerCodeActions } from "./registerCodeActions"
44
export { registerTerminalActions } from "./registerTerminalActions"
5+
export { registerPearListener } from "./registerPearListener"

src/activate/registerPearListener.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import * as vscode from "vscode"
2+
import { ClineProvider } from "../core/webview/ClineProvider"
3+
import { assert } from "../utils/util"
4+
5+
export const getPearaiExtension = async () => {
6+
const pearAiExtension = vscode.extensions.getExtension("pearai.pearai")
7+
8+
assert(!!pearAiExtension, "PearAI extension not found")
9+
10+
if (!pearAiExtension.isActive) {
11+
await pearAiExtension.activate()
12+
}
13+
14+
return pearAiExtension
15+
}
16+
17+
export const registerPearListener = async () => {
18+
// Getting the pear ai extension instance
19+
const pearAiExtension = await getPearaiExtension()
20+
21+
// Access the API directly from exports
22+
if (pearAiExtension.exports) {
23+
pearAiExtension.exports.pearAPI.creatorMode.onDidRequestExecutePlan(async (msg: any) => {
24+
console.dir(`onDidRequestNewTask triggered with: ${JSON.stringify(msg)}`)
25+
26+
// Get the sidebar provider
27+
const sidebarProvider = ClineProvider.getSidebarInstance()
28+
29+
if (sidebarProvider) {
30+
// Focus the sidebar first
31+
await vscode.commands.executeCommand("pearai-roo-cline.SidebarProvider.focus")
32+
33+
// Wait for the view to be ready using a helper function
34+
await ensureViewIsReady(sidebarProvider)
35+
36+
// Switch to creator mode
37+
await sidebarProvider.handleModeSwitch("creator")
38+
await sidebarProvider.postStateToWebview()
39+
40+
// Navigate to chat view
41+
await sidebarProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" })
42+
43+
// Wait a brief moment for UI to update
44+
await new Promise((resolve) => setTimeout(resolve, 300))
45+
46+
// Initialize with task
47+
await sidebarProvider.initClineWithTask(msg.plan, undefined, undefined, true)
48+
}
49+
})
50+
} else {
51+
console.error("⚠️⚠️ PearAI API not available in exports ⚠️⚠️")
52+
}
53+
}
54+
55+
// TODO: decide if this is needed
56+
// Helper function to ensure the webview is ready
57+
async function ensureViewIsReady(provider: ClineProvider): Promise<void> {
58+
// If the view is already launched, we're good to go
59+
if (provider.viewLaunched) {
60+
return
61+
}
62+
63+
// Otherwise, we need to wait for it to initialize
64+
return new Promise((resolve) => {
65+
// Set up a one-time listener for when the view is ready
66+
const disposable = provider.on("clineAdded", () => {
67+
// Clean up the listener
68+
disposable.dispose()
69+
resolve()
70+
})
71+
72+
// Set a timeout just in case
73+
setTimeout(() => {
74+
disposable.dispose()
75+
resolve()
76+
}, 5000)
77+
})
78+
}

src/core/webview/ClineProvider.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
111111
readonly context: vscode.ExtensionContext,
112112
private readonly outputChannel: vscode.OutputChannel,
113113
private readonly renderContext: "sidebar" | "editor" = "sidebar",
114+
private readonly isCreatorView: boolean = false,
114115
) {
115116
super()
116117

@@ -137,6 +138,16 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
137138
})
138139
}
139140

141+
public static getSidebarInstance(): ClineProvider | undefined {
142+
const sidebar = Array.from(this.activeInstances).find((instance) => !instance.isCreatorView)
143+
144+
if (!sidebar?.view?.visible) {
145+
vscode.commands.executeCommand("pearai-roo-cline.SidebarProvider.focus")
146+
}
147+
148+
return sidebar
149+
}
150+
140151
// Adds a new Cline instance to clineStack, marking the start of a new task.
141152
// The instance is pushed to the top of the stack (LIFO order).
142153
// When the task is completed, the top instance is removed, reactivating the previous task.
@@ -477,7 +488,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
477488
// when initializing a new task, (not from history but from a tool command new_task) there is no need to remove the previouse task
478489
// since the new task is a sub task of the previous one, and when it finishes it is removed from the stack and the caller is resumed
479490
// in this way we can have a chain of tasks, each one being a sub task of the previous one until the main task is finished
480-
public async initClineWithTask(task?: string, images?: string[], parentTask?: Cline) {
491+
public async initClineWithTask(task?: string, images?: string[], parentTask?: Cline, creatorMode?: boolean) {
481492
const {
482493
apiConfiguration,
483494
customModePrompts,
@@ -497,7 +508,11 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
497508

498509
const cline = new Cline({
499510
provider: this,
500-
apiConfiguration: { ...apiConfiguration, pearaiAgentModels },
511+
apiConfiguration: {
512+
...apiConfiguration,
513+
creatorMode,
514+
pearaiAgentModels,
515+
},
501516
customInstructions: effectiveInstructions,
502517
enableDiff,
503518
enableCheckpoints,

src/extension.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ import { telemetryService } from "./services/telemetry/TelemetryService"
2323
import { TerminalRegistry } from "./integrations/terminal/TerminalRegistry"
2424
import { API } from "./exports/api"
2525

26-
import { handleUri, registerCommands, registerCodeActions, registerTerminalActions } from "./activate"
26+
import {
27+
handleUri,
28+
registerCommands,
29+
registerCodeActions,
30+
registerTerminalActions,
31+
registerPearListener,
32+
} from "./activate"
2733
import { formatLanguage } from "./shared/language"
2834

2935
/**
@@ -255,6 +261,7 @@ export function activate(context: vscode.ExtensionContext) {
255261

256262
registerCodeActions(context)
257263
registerTerminalActions(context)
264+
registerPearListener()
258265

259266
context.subscriptions.push(
260267
vscode.commands.registerCommand("roo-cline.focus", async (...args: any[]) => {

src/shared/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export interface ApiHandlerOptions {
9090
export type ApiConfiguration = ApiHandlerOptions & {
9191
apiProvider?: ApiProvider
9292
id?: string // stable unique identifier
93+
creatorMode?: boolean
9394
}
9495

9596
// Import GlobalStateKey type from globalState.ts

src/shared/creatorMode.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const CREATOR_MODE_PLANNING_PROMPT = `
2+
Depending on the user's request, you may need to do some information gathering (for example using read_file or search_files) to get more context about the task.
3+
You may also ask the user clarifying questions to get a better understanding of the task.
4+
Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task.
5+
Focus on breaking down complex tasks into manageable steps, considering technical requirements, potential challenges, and best practices.
6+
The plan should be clear enough that it can be directly implemented by switching to Code mode afterward.
7+
(Directly write the plan to a markdown file instead of showing it as normal response.)\n\n
8+
Once you create and write the plan, you mark the task as completed.
9+
You only make plans and you should not ask or switch to any other mode.
10+
Keep the plan brief, mainly feature based (include a feature list), and no steps, a product outline.`

src/shared/modes.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from "vscode"
22
import { TOOL_GROUPS, ToolGroup, ALWAYS_AVAILABLE_TOOLS } from "./tool-groups"
33
import { addCustomInstructions } from "../core/prompts/sections/custom-instructions"
4+
import { CREATOR_MODE_PLANNING_PROMPT } from "./creatorMode"
45

56
// Mode types
67
export type Mode = string
@@ -78,6 +79,14 @@ export function getToolsForMode(groups: readonly GroupEntry[]): string[] {
7879

7980
// Main modes configuration as an ordered array
8081
export const modes: readonly ModeConfig[] = [
82+
{
83+
slug: "creator",
84+
name: "Creator",
85+
roleDefinition:
86+
"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.",
87+
groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "browser", "mcp"],
88+
customInstructions: CREATOR_MODE_PLANNING_PROMPT,
89+
},
8190
{
8291
slug: "code",
8392
name: "Code",

src/utils/util.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class AssertionError extends Error {
2+
constructor(message: string) {
3+
super(message)
4+
// Adding the stack info to error.
5+
// Inspired by: https://blog.dennisokeeffe.com/blog/2020-08-07-error-tracing-with-sentry-and-es6-classes
6+
if (Error.captureStackTrace) {
7+
Error.captureStackTrace(this, AssertionError)
8+
} else {
9+
this.stack = new Error(message).stack
10+
}
11+
this.name = "AssertionError"
12+
}
13+
}
14+
15+
export function assert(condition: boolean, message: string): asserts condition {
16+
if (!condition) {
17+
throw new AssertionError(message)
18+
}
19+
}

0 commit comments

Comments
 (0)