@@ -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