@@ -95,50 +95,102 @@ export class ClineProvider implements vscode.WebviewViewProvider {
9595 // The instance is pushed to the top of the stack (LIFO order).
9696 // When the task is completed, the top instance is removed, reactivating the previous task.
9797 async addClineToStack ( cline : Cline ) {
98- // if cline.getTaskNumber() is -1, it means it is a new task
99- if ( cline . getTaskNumber ( ) === - 1 ) {
100- // increase last cline number by 1
101- this . lastTaskNumber = this . lastTaskNumber + 1
102- cline . setTaskNumber ( this . lastTaskNumber )
103- }
104- // if cline.getTaskNumber() > lastTaskNumber, set lastTaskNumber to cline.getTaskNumber()
105- else if ( cline . getTaskNumber ( ) > this . lastTaskNumber ) {
106- this . lastTaskNumber = cline . getTaskNumber ( )
98+ try {
99+ if ( ! cline || ! ( cline instanceof Cline ) ) {
100+ throw new Error ( "Error invalid Cline instance provided." )
101+ }
102+
103+ // Ensure lastTaskNumber is a valid number
104+ if ( typeof this . lastTaskNumber !== "number" ) {
105+ this . lastTaskNumber = - 1
106+ }
107+
108+ const taskNumber = cline . getTaskNumber ( )
109+
110+ if ( taskNumber === - 1 ) {
111+ this . lastTaskNumber += 1
112+ cline . setTaskNumber ( this . lastTaskNumber )
113+ } else if ( taskNumber > this . lastTaskNumber ) {
114+ this . lastTaskNumber = taskNumber
115+ }
116+
117+ this . clineStack . push ( cline )
118+
119+ // Ensure getState() resolves correctly
120+ const state = await this . getState ( )
121+ if ( ! state || typeof state . mode !== "string" ) {
122+ throw new Error ( "Error failed to retrieve current mode from state." )
123+ }
124+
125+ this . log ( `[subtasks] Task: ${ cline . getTaskNumber ( ) } started at '${ state . mode } ' mode` )
126+ } catch ( error ) {
127+ this . log ( `Error in addClineToStack: ${ error . message } ` )
128+ throw error
107129 }
108- // push the cline instance to the stack
109- this . clineStack . push ( cline )
110- // get the current mode
111- const currentMode = ( await this . getState ( ) ) . mode
112- // log the task number and the mode
113- this . log ( `[subtasks] Task: ${ cline . getTaskNumber ( ) } started at '${ currentMode } ' mode` )
114130 }
115131
116132 // Removes and destroys the top Cline instance (the current finished task), activating the previous one (resuming the parent task).
117133 async removeClineFromStack ( ) {
118- // pop the top Cline instance from the stack
119- var clineToBeRemoved = this . clineStack . pop ( )
120- if ( clineToBeRemoved ) {
121- const removedTaskNumber = clineToBeRemoved . getTaskNumber ( )
122- await clineToBeRemoved . abortTask ( )
123- // make sure no reference kept, once promises end it will be garbage collected
124- clineToBeRemoved = undefined
125- this . log ( `[subtasks] Task: ${ removedTaskNumber } stopped` )
126- }
127- // if the stack is empty, reset the last task number
128- if ( this . clineStack . length === 0 ) {
129- this . lastTaskNumber = - 1
134+ try {
135+ if ( ! Array . isArray ( this . clineStack ) ) {
136+ throw new Error ( "Error clineStack is not an array." )
137+ }
138+
139+ if ( this . clineStack . length === 0 ) {
140+ this . log ( "[subtasks] No active tasks to remove." )
141+ } else {
142+ // pop the top Cline instance from the stack
143+ var clineToBeRemoved = this . clineStack . pop ( )
144+ if ( clineToBeRemoved ) {
145+ const removedTaskNumber = clineToBeRemoved . getTaskNumber ( )
146+
147+ try {
148+ await clineToBeRemoved . abortTask ( )
149+ } catch ( abortError ) {
150+ this . log ( `Error failed aborting task ${ removedTaskNumber } : ${ abortError . message } ` )
151+ }
152+
153+ // make sure no reference kept, once promises end it will be garbage collected
154+ clineToBeRemoved = undefined
155+ this . log ( `[subtasks] Task: ${ removedTaskNumber } stopped` )
156+ }
157+
158+ // if the stack is empty, reset the last task number
159+ if ( this . clineStack . length === 0 ) {
160+ this . lastTaskNumber = - 1
161+ }
162+ }
163+ } catch ( error ) {
164+ this . log ( `Error in removeClineFromStack: ${ error . message } ` )
165+ throw error
130166 }
131167 }
132168
133169 // remove the cline object with the received clineId, and all the cline objects bove it in the stack
134170 // for each cline object removed, pop it from the stack, abort the task and set it to undefined
135171 async removeClineWithIdFromStack ( clineId : string ) {
136- const index = this . clineStack . findIndex ( ( c ) => c . taskId === clineId )
137- if ( index === - 1 ) {
138- return
139- }
140- for ( let i = this . clineStack . length - 1 ; i >= index ; i -- ) {
141- this . removeClineFromStack ( )
172+ try {
173+ if ( typeof clineId !== "string" || ! clineId . trim ( ) ) {
174+ throw new Error ( "Error Invalid clineId provided." )
175+ }
176+
177+ const index = this . clineStack . findIndex ( ( c ) => c . taskId === clineId )
178+
179+ if ( index === - 1 ) {
180+ this . log ( `[subtasks] No task found with ID: ${ clineId } ` )
181+ return
182+ }
183+
184+ for ( let i = this . clineStack . length - 1 ; i >= index ; i -- ) {
185+ try {
186+ await this . removeClineFromStack ( )
187+ } catch ( removalError ) {
188+ this . log ( `Error removing task at stack index ${ i } : ${ removalError . message } ` )
189+ }
190+ }
191+ } catch ( error ) {
192+ this . log ( `Error in removeClineWithIdFromStack: ${ error . message } ` )
193+ throw error
142194 }
143195 }
144196
@@ -160,10 +212,15 @@ export class ClineProvider implements vscode.WebviewViewProvider {
160212 // and resume the previous task/cline instance (if it exists)
161213 // this is used when a sub task is finished and the parent task needs to be resumed
162214 async finishSubTask ( lastMessage ?: string ) {
163- // remove the last cline instance from the stack (this is the finished sub task)
164- await this . removeClineFromStack ( )
165- // resume the last cline instance in the stack (if it exists - this is the 'parnt' calling task)
166- this . getCurrentCline ( ) ?. resumePausedTask ( lastMessage )
215+ try {
216+ // remove the last cline instance from the stack (this is the finished sub task)
217+ await this . removeClineFromStack ( )
218+ // resume the last cline instance in the stack (if it exists - this is the 'parnt' calling task)
219+ this . getCurrentCline ( ) ?. resumePausedTask ( lastMessage )
220+ } catch ( error ) {
221+ this . log ( `Error in finishSubTask: ${ error . message } ` )
222+ throw error
223+ }
167224 }
168225
169226 /*
@@ -2031,7 +2088,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
20312088
20322089 // delete checkpoints branch from project git repo
20332090 if ( enableCheckpoints && baseDir ) {
2034-
20352091 const branchSummary = await simpleGit ( baseDir )
20362092 . branch ( [ "-D" , `roo-code-checkpoints-${ id } ` ] )
20372093 . catch ( ( ) => undefined )
@@ -2591,6 +2647,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
25912647
25922648 public log ( message : string ) {
25932649 this . outputChannel . appendLine ( message )
2650+ console . log ( message )
25942651 }
25952652
25962653 // integration tests
0 commit comments