Refactor ClineProvider

This commit is contained in:
Saoud Rizwan
2024-10-05 23:16:25 -04:00
parent f0315c1520
commit da3aa7a658
5 changed files with 23 additions and 26 deletions

View File

@@ -41,7 +41,7 @@ import { parseAssistantMessage } from "./prompts/parse-assistant-message"
import { formatResponse } from "./prompts/responses"
import { addCustomInstructions, SYSTEM_PROMPT } from "./prompts/system"
import { truncateHalfConversation } from "./sliding-window"
import { ClaudeDevProvider, GlobalFileNames } from "./webview/ClaudeDevProvider"
import { ClineProvider, GlobalFileNames } from "./webview/ClaudeDevProvider"
const cwd =
vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) ?? path.join(os.homedir(), "Desktop") // may or may not exist but fs checking existence would immediately ask for permission which would be bad UX, need to come up with a better solution
@@ -66,7 +66,7 @@ export class ClaudeDev {
private askResponseImages?: string[]
private lastMessageTs?: number
private consecutiveMistakeCount: number = 0
private providerRef: WeakRef<ClaudeDevProvider>
private providerRef: WeakRef<ClineProvider>
private abort: boolean = false
didFinishAborting = false
private diffViewProvider: DiffViewProvider
@@ -82,7 +82,7 @@ export class ClaudeDev {
private didCompleteReadingStream = false
constructor(
provider: ClaudeDevProvider,
provider: ClineProvider,
apiConfiguration: ApiConfiguration,
customInstructions?: string,
alwaysAllowReadOnly?: boolean,

View File

@@ -61,10 +61,10 @@ export const GlobalFileNames = {
openRouterModels: "openrouter_models.json",
}
export class ClaudeDevProvider implements vscode.WebviewViewProvider {
export class ClineProvider implements vscode.WebviewViewProvider {
public static readonly sideBarId = "claude-dev.SidebarProvider" // used in package.json as the view's id. This value cannot be changed due to how vscode caches views based on their id, and updating the id would break existing instances of the extension.
public static readonly tabPanelId = "claude-dev.TabPanelProvider"
private static activeInstances: Set<ClaudeDevProvider> = new Set()
private static activeInstances: Set<ClineProvider> = new Set()
private disposables: vscode.Disposable[] = []
private view?: vscode.WebviewView | vscode.WebviewPanel
private claudeDev?: ClaudeDev
@@ -72,8 +72,8 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
private latestAnnouncementId = "sep-21-2024" // update to some unique identifier when we add a new announcement
constructor(readonly context: vscode.ExtensionContext, private readonly outputChannel: vscode.OutputChannel) {
this.outputChannel.appendLine("ClaudeDevProvider instantiated")
ClaudeDevProvider.activeInstances.add(this)
this.outputChannel.appendLine("ClineProvider instantiated")
ClineProvider.activeInstances.add(this)
this.workspaceTracker = new WorkspaceTracker(this)
this.revertKodu()
}
@@ -105,7 +105,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
- https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
*/
async dispose() {
this.outputChannel.appendLine("Disposing ClaudeDevProvider...")
this.outputChannel.appendLine("Disposing ClineProvider...")
await this.clearTask()
this.outputChannel.appendLine("Cleared task")
if (this.view && "dispose" in this.view) {
@@ -121,10 +121,10 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
this.workspaceTracker?.dispose()
this.workspaceTracker = undefined
this.outputChannel.appendLine("Disposed all disposables")
ClaudeDevProvider.activeInstances.delete(this)
ClineProvider.activeInstances.delete(this)
}
public static getVisibleInstance(): ClaudeDevProvider | undefined {
public static getVisibleInstance(): ClineProvider | undefined {
return findLast(Array.from(this.activeInstances), (instance) => instance.view?.visible === true)
}
@@ -752,10 +752,10 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
/*
Now that we use retainContextWhenHidden, we don't have to store a cache of claude messages in the user's state, but we could to reduce memory footprint in long conversations.
- We have to be careful of what state is shared between ClaudeDevProvider instances since there could be multiple instances of the extension running at once. For example when we cached claude messages using the same key, two instances of the extension could end up using the same key and overwriting each other's messages.
- We have to be careful of what state is shared between ClineProvider instances since there could be multiple instances of the extension running at once. For example when we cached claude messages using the same key, two instances of the extension could end up using the same key and overwriting each other's messages.
- Some state does need to be shared between the instances, i.e. the API key--however there doesn't seem to be a good way to notfy the other instances that the API key has changed.
We need to use a unique identifier for each ClaudeDevProvider instance's message cache since we could be running several instances of the extension outside of just the sidebar i.e. in editor panels.
We need to use a unique identifier for each ClineProvider instance's message cache since we could be running several instances of the extension outside of just the sidebar i.e. in editor panels.
For now since we don't need to store task history, we'll just use an identifier unique to this provider instance (since there can be several provider instances open at once).
However in the future when we implement task history, we'll need to use a unique identifier for each task. As well as manage a data structure that keeps track of task history with their associated identifiers and the task message itself, to present in a 'Task History' view.

View File

@@ -1,11 +1,8 @@
import * as vscode from "vscode"
import { ClaudeDevProvider } from "../core/webview/ClaudeDevProvider"
import { ClineProvider } from "../core/webview/ClaudeDevProvider"
import { ClaudeDevAPI } from "./claude-dev"
export function createClaudeDevAPI(
outputChannel: vscode.OutputChannel,
sidebarProvider: ClaudeDevProvider
): ClaudeDevAPI {
export function createClaudeDevAPI(outputChannel: vscode.OutputChannel, sidebarProvider: ClineProvider): ClaudeDevAPI {
const api: ClaudeDevAPI = {
setCustomInstructions: async (value: string) => {
await sidebarProvider.updateCustomInstructions(value)

View File

@@ -1,7 +1,7 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from "vscode"
import { ClaudeDevProvider } from "./core/webview/ClaudeDevProvider"
import { ClineProvider } from "./core/webview/ClaudeDevProvider"
import delay from "delay"
import { createClaudeDevAPI } from "./exports"
import "./utils/path" // necessary to have access to String.prototype.toPosix
@@ -39,10 +39,10 @@ export function activate(context: vscode.ExtensionContext) {
// })
// context.subscriptions.push(disposable)
const sidebarProvider = new ClaudeDevProvider(context, outputChannel)
const sidebarProvider = new ClineProvider(context, outputChannel)
context.subscriptions.push(
vscode.window.registerWebviewViewProvider(ClaudeDevProvider.sideBarId, sidebarProvider, {
vscode.window.registerWebviewViewProvider(ClineProvider.sideBarId, sidebarProvider, {
webviewOptions: { retainContextWhenHidden: true },
})
)
@@ -60,7 +60,7 @@ export function activate(context: vscode.ExtensionContext) {
outputChannel.appendLine("Opening Claude Dev in new tab")
// (this example uses webviewProvider activation event which is necessary to deserialize cached webview, but since we use retainContextWhenHidden, we don't need to use that event)
// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
const tabProvider = new ClaudeDevProvider(context, outputChannel)
const tabProvider = new ClineProvider(context, outputChannel)
//const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined
const lastCol = Math.max(...vscode.window.visibleTextEditors.map((editor) => editor.viewColumn || 0))
@@ -71,7 +71,7 @@ export function activate(context: vscode.ExtensionContext) {
}
const targetCol = hasVisibleEditors ? Math.max(lastCol + 1, 1) : vscode.ViewColumn.Two
const panel = vscode.window.createWebviewPanel(ClaudeDevProvider.tabPanelId, "Claude Dev", targetCol, {
const panel = vscode.window.createWebviewPanel(ClineProvider.tabPanelId, "Claude Dev", targetCol, {
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [context.extensionUri],
@@ -126,7 +126,7 @@ export function activate(context: vscode.ExtensionContext) {
const handleUri = async (uri: vscode.Uri) => {
const path = uri.path
const query = new URLSearchParams(uri.query.replace(/\+/g, "%2B"))
const visibleProvider = ClaudeDevProvider.getVisibleInstance()
const visibleProvider = ClineProvider.getVisibleInstance()
if (!visibleProvider) {
return
}

View File

@@ -1,17 +1,17 @@
import * as vscode from "vscode"
import * as path from "path"
import { listFiles } from "../../services/glob/list-files"
import { ClaudeDevProvider } from "../../core/webview/ClaudeDevProvider"
import { ClineProvider } from "../../core/webview/ClaudeDevProvider"
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0)
// Note: this is not a drop-in replacement for listFiles at the start of tasks, since that will be done for Desktops when there is no workspace selected
class WorkspaceTracker {
private providerRef: WeakRef<ClaudeDevProvider>
private providerRef: WeakRef<ClineProvider>
private disposables: vscode.Disposable[] = []
private filePaths: Set<string> = new Set()
constructor(provider: ClaudeDevProvider) {
constructor(provider: ClineProvider) {
this.providerRef = new WeakRef(provider)
this.registerListeners()
}