Skip to content

Commit 086fb13

Browse files
committed
refactor: tasks now are related to curreyt workspace directory
1 parent f263698 commit 086fb13

File tree

4 files changed

+139
-43
lines changed

4 files changed

+139
-43
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Roo Code (prev. Roo Cline)",
44
"description": "A whole dev team of AI agents in your editor.",
55
"publisher": "RooVeterinaryInc",
6-
"version": "3.8.6",
6+
"version": "0.8.6",
77
"icon": "assets/icons/rocket.png",
88
"galleryBanner": {
99
"color": "#617A91",

src/core/Cline.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,11 @@ export class Cline extends EventEmitter<ClineEvents> {
278278
// Storing task to disk for history
279279

280280
private async ensureTaskDirectoryExists(): Promise<string> {
281-
const globalStoragePath = this.providerRef.deref()?.context.globalStorageUri.fsPath
282-
if (!globalStoragePath) {
283-
throw new Error("Global storage uri is invalid")
281+
const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri.fsPath
282+
if (!workspaceRoot) {
283+
throw new Error("No workspace folder found")
284284
}
285-
const taskDir = path.join(globalStoragePath, "tasks", this.taskId)
285+
const taskDir = path.join(workspaceRoot, ".roocode", "tasks", this.taskId)
286286
await fs.mkdir(taskDir, { recursive: true })
287287
return taskDir
288288
}

src/core/webview/ClineProvider.ts

Lines changed: 132 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@ export class ClineProvider implements vscode.WebviewViewProvider {
107107
.catch((error) => {
108108
this.outputChannel.appendLine(`Failed to initialize MCP Hub: ${error}`)
109109
})
110+
111+
// 监听项目任务文件变化
112+
const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri.fsPath
113+
if (workspaceRoot) {
114+
const tasksPath = path.join(workspaceRoot, ".roocode", "tasks")
115+
const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(tasksPath, "**/*.json"))
116+
117+
watcher.onDidChange(() => {
118+
this.postStateToWebview()
119+
})
120+
watcher.onDidCreate(() => {
121+
this.postStateToWebview()
122+
})
123+
watcher.onDidDelete(() => {
124+
this.postStateToWebview()
125+
})
126+
127+
this.disposables.push(watcher)
128+
}
110129
}
111130

112131
// Adds a new Cline instance to clineStack, marking the start of a new task.
@@ -2167,28 +2186,57 @@ export class ClineProvider implements vscode.WebviewViewProvider {
21672186
uiMessagesFilePath: string
21682187
apiConversationHistory: Anthropic.MessageParam[]
21692188
}> {
2170-
const history = ((await this.getGlobalState("taskHistory")) as HistoryItem[] | undefined) || []
2171-
const historyItem = history.find((item) => item.id === id)
2172-
if (historyItem) {
2173-
const taskDirPath = path.join(this.contextProxy.globalStorageUri.fsPath, "tasks", id)
2174-
const apiConversationHistoryFilePath = path.join(taskDirPath, GlobalFileNames.apiConversationHistory)
2175-
const uiMessagesFilePath = path.join(taskDirPath, GlobalFileNames.uiMessages)
2176-
const fileExists = await fileExistsAtPath(apiConversationHistoryFilePath)
2177-
if (fileExists) {
2178-
const apiConversationHistory = JSON.parse(await fs.readFile(apiConversationHistoryFilePath, "utf8"))
2179-
return {
2180-
historyItem,
2181-
taskDirPath,
2182-
apiConversationHistoryFilePath,
2183-
uiMessagesFilePath,
2184-
apiConversationHistory,
2185-
}
2186-
}
2189+
const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri.fsPath
2190+
if (!workspaceRoot) {
2191+
throw new Error("No workspace folder found")
2192+
}
2193+
const taskDirPath = path.join(workspaceRoot, ".roocode", "tasks", id)
2194+
const apiConversationHistoryFilePath = path.join(taskDirPath, GlobalFileNames.apiConversationHistory)
2195+
const uiMessagesFilePath = path.join(taskDirPath, GlobalFileNames.uiMessages)
2196+
2197+
// 从项目任务列表中获取 historyItem
2198+
const projectTasks = await this.getProjectTaskHistory()
2199+
const historyItem = projectTasks.find((item) => item.id === id)
2200+
if (!historyItem) {
2201+
// 如果在项目任务中找不到,说明任务不存在或不属于当前项目
2202+
throw new Error("Task not found in current project")
2203+
}
2204+
2205+
// 读取 API 会话历史
2206+
let apiConversationHistory: Anthropic.MessageParam[] = []
2207+
if (await fileExistsAtPath(apiConversationHistoryFilePath)) {
2208+
apiConversationHistory = JSON.parse(await fs.readFile(apiConversationHistoryFilePath, "utf8"))
2209+
}
2210+
2211+
// 读取 UI 消息
2212+
//let uiMessages: ClineMessage[] = []
2213+
//if (await fileExistsAtPath(uiMessagesFilePath)) {
2214+
// uiMessages = JSON.parse(await fs.readFile(uiMessagesFilePath, "utf8"))
2215+
//}
2216+
2217+
// 如果两个文件都不存在,说明任务不存在
2218+
if (
2219+
!(await fileExistsAtPath(apiConversationHistoryFilePath)) &&
2220+
!(await fileExistsAtPath(uiMessagesFilePath))
2221+
) {
2222+
throw new Error("Task not found")
2223+
}
2224+
2225+
return {
2226+
historyItem,
2227+
taskDirPath,
2228+
apiConversationHistoryFilePath,
2229+
uiMessagesFilePath,
2230+
apiConversationHistory,
21872231
}
2188-
// if we tried to get a task that doesn't exist, remove it from state
2189-
// FIXME: this seems to happen sometimes when the json file doesnt save to disk for some reason
2190-
await this.deleteTaskFromState(id)
2191-
throw new Error("Task not found")
2232+
}
2233+
2234+
private async getProjectTaskHistory(): Promise<HistoryItem[]> {
2235+
// 直接从项目状态中获取任务历史
2236+
const tasks = (await this.getProjectState<HistoryItem[]>("taskHistory")) || []
2237+
2238+
// 确保任务列表按时间戳排序
2239+
return tasks.sort((a, b) => b.ts - a.ts)
21922240
}
21932241

21942242
async showTaskWithId(id: string) {
@@ -2249,12 +2297,16 @@ export class ClineProvider implements vscode.WebviewViewProvider {
22492297
}
22502298

22512299
async deleteTaskFromState(id: string) {
2252-
// Remove the task from history
2253-
const taskHistory = ((await this.getGlobalState("taskHistory")) as HistoryItem[]) || []
2254-
const updatedTaskHistory = taskHistory.filter((task) => task.id !== id)
2255-
await this.updateGlobalState("taskHistory", updatedTaskHistory)
2300+
// 从项目状态中获取任务历史
2301+
const tasks = (await this.getProjectState<HistoryItem[]>("taskHistory")) || []
2302+
2303+
// 移除指定任务
2304+
const updatedTasks = tasks.filter((task) => task.id !== id)
2305+
2306+
// 更新项目状态
2307+
await this.updateProjectState("taskHistory", updatedTasks)
22562308

2257-
// Notify the webview that the task has been deleted
2309+
// 通知 webview 更新状态
22582310
await this.postStateToWebview()
22592311
}
22602312

@@ -2331,9 +2383,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
23312383
? (taskHistory || []).find((item: HistoryItem) => item.id === this.getCurrentCline()?.taskId)
23322384
: undefined,
23332385
clineMessages: this.getCurrentCline()?.clineMessages || [],
2334-
taskHistory: (taskHistory || [])
2335-
.filter((item: HistoryItem) => item.ts && item.task)
2336-
.sort((a: HistoryItem, b: HistoryItem) => b.ts - a.ts),
2386+
taskHistory: (await this.getProjectState<HistoryItem[]>("taskHistory")) || [],
23372387
soundEnabled: soundEnabled ?? false,
23382388
diffEnabled: diffEnabled ?? true,
23392389
enableCheckpoints: enableCheckpoints ?? true,
@@ -2531,17 +2581,63 @@ export class ClineProvider implements vscode.WebviewViewProvider {
25312581
}
25322582
}
25332583

2584+
// 项目状态管理
2585+
private async getProjectStatePath(): Promise<string> {
2586+
const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri.fsPath
2587+
if (!workspaceRoot) {
2588+
throw new Error("No workspace folder found")
2589+
}
2590+
return path.join(workspaceRoot, ".roocode", "project_state.json")
2591+
}
2592+
2593+
private async getProjectState<T>(key: string): Promise<T | undefined> {
2594+
const statePath = await this.getProjectStatePath()
2595+
if (!(await fileExistsAtPath(statePath))) {
2596+
return undefined
2597+
}
2598+
const state = JSON.parse(await fs.readFile(statePath, "utf8"))
2599+
return state[key]
2600+
}
2601+
2602+
private async updateProjectState<T>(key: string, value: T): Promise<void> {
2603+
const statePath = await this.getProjectStatePath()
2604+
const stateDir = path.dirname(statePath)
2605+
2606+
// 确保目录存在
2607+
await fs.mkdir(stateDir, { recursive: true })
2608+
2609+
// 读取现有状态
2610+
let state: Record<string, any> = {}
2611+
if (await fileExistsAtPath(statePath)) {
2612+
state = JSON.parse(await fs.readFile(statePath, "utf8"))
2613+
}
2614+
2615+
// 更新状态
2616+
state[key] = value
2617+
2618+
// 写入文件
2619+
await fs.writeFile(statePath, JSON.stringify(state, null, 2))
2620+
}
2621+
25342622
async updateTaskHistory(item: HistoryItem): Promise<HistoryItem[]> {
2535-
const history = ((await this.getGlobalState("taskHistory")) as HistoryItem[] | undefined) || []
2536-
const existingItemIndex = history.findIndex((h) => h.id === item.id)
2623+
// 获取现有任务历史
2624+
const tasks = (await this.getProjectState<HistoryItem[]>("taskHistory")) || []
25372625

2538-
if (existingItemIndex !== -1) {
2539-
history[existingItemIndex] = item
2626+
// 更新或添加任务
2627+
const index = tasks.findIndex((t) => t.id === item.id)
2628+
if (index !== -1) {
2629+
tasks[index] = item
25402630
} else {
2541-
history.push(item)
2631+
tasks.push(item)
25422632
}
2543-
await this.updateGlobalState("taskHistory", history)
2544-
return history
2633+
2634+
// 按时间戳排序
2635+
tasks.sort((a, b) => b.ts - a.ts)
2636+
2637+
// 保存更新后的任务历史
2638+
await this.updateProjectState("taskHistory", tasks)
2639+
2640+
return tasks
25452641
}
25462642

25472643
// global

0 commit comments

Comments
 (0)