@@ -50,6 +50,7 @@ import { CheckpointServiceOptions, RepoPerTaskCheckpointService } from "../servi
5050// integrations
5151import { DIFF_VIEW_URI_SCHEME , DiffViewProvider } from "../integrations/editor/DiffViewProvider"
5252import { findToolName , formatContentBlockToMarkdown } from "../integrations/misc/export-markdown"
53+ import { RooTerminalProcess } from "../integrations/terminal/types"
5354import { Terminal } from "../integrations/terminal/Terminal"
5455import { TerminalRegistry } from "../integrations/terminal/TerminalRegistry"
5556
@@ -197,6 +198,9 @@ export class Cline extends EventEmitter<ClineEvents> {
197198 // metrics
198199 private toolUsage : ToolUsage = { }
199200
201+ // terminal
202+ public terminalProcess ?: RooTerminalProcess
203+
200204 constructor ( {
201205 provider,
202206 apiConfiguration,
@@ -480,6 +484,14 @@ export class Cline extends EventEmitter<ClineEvents> {
480484 this . askResponseImages = images
481485 }
482486
487+ async handleTerminalOperation ( terminalOperation : "continue" | "abort" ) {
488+ if ( terminalOperation === "continue" ) {
489+ this . terminalProcess ?. continue ( )
490+ } else if ( terminalOperation === "abort" ) {
491+ this . terminalProcess ?. abort ( )
492+ }
493+ }
494+
483495 async say (
484496 type : ClineSay ,
485497 text ?: string ,
@@ -1974,6 +1986,7 @@ export class Cline extends EventEmitter<ClineEvents> {
19741986
19751987 // It could be useful for cline to know if the user went from one or no file to another between messages, so we always include this context
19761988 details += "\n\n# VSCode Visible Files"
1989+
19771990 const visibleFilePaths = vscode . window . visibleTextEditors
19781991 ?. map ( ( editor ) => editor . document ?. uri ?. fsPath )
19791992 . filter ( Boolean )
@@ -2012,11 +2025,12 @@ export class Cline extends EventEmitter<ClineEvents> {
20122025 details += "\n(No open tabs)"
20132026 }
20142027
2015- // Get task-specific and background terminals
2028+ // Get task-specific and background terminals.
20162029 const busyTerminals = [
20172030 ...TerminalRegistry . getTerminals ( true , this . taskId ) ,
20182031 ...TerminalRegistry . getBackgroundTerminals ( true ) ,
20192032 ]
2033+
20202034 const inactiveTerminals = [
20212035 ...TerminalRegistry . getTerminals ( false , this . taskId ) ,
20222036 ...TerminalRegistry . getBackgroundTerminals ( false ) ,
@@ -2027,77 +2041,66 @@ export class Cline extends EventEmitter<ClineEvents> {
20272041 }
20282042
20292043 if ( busyTerminals . length > 0 ) {
2030- // wait for terminals to cool down
2044+ // Wait for terminals to cool down.
20312045 await pWaitFor ( ( ) => busyTerminals . every ( ( t ) => ! TerminalRegistry . isProcessHot ( t . id ) ) , {
20322046 interval : 100 ,
20332047 timeout : 15_000 ,
20342048 } ) . catch ( ( ) => { } )
20352049 }
20362050
2037- // we want to get diagnostics AFTER terminal cools down for a few reasons: terminal could be scaffolding a project, dev servers (compilers like webpack) will first re-compile and then send diagnostics, etc
2038- /*
2039- let diagnosticsDetails = ""
2040- const diagnostics = await this.diagnosticsMonitor.getCurrentDiagnostics(this.didEditFile || terminalWasBusy) // if cline ran a command (ie npm install) or edited the workspace then wait a bit for updated diagnostics
2041- for (const [uri, fileDiagnostics] of diagnostics) {
2042- const problems = fileDiagnostics.filter((d) => d.severity === vscode.DiagnosticSeverity.Error)
2043- if (problems.length > 0) {
2044- diagnosticsDetails += `\n## ${path.relative(this.cwd, uri.fsPath)}`
2045- for (const diagnostic of problems) {
2046- // let severity = diagnostic.severity === vscode.DiagnosticSeverity.Error ? "Error" : "Warning"
2047- const line = diagnostic.range.start.line + 1 // VSCode lines are 0-indexed
2048- const source = diagnostic.source ? `[${diagnostic.source}] ` : ""
2049- diagnosticsDetails += `\n- ${source}Line ${line}: ${diagnostic.message}`
2050- }
2051- }
2052- }
2053- */
2054- this . didEditFile = false // reset, this lets us know when to wait for saved files to update terminals
2051+ // Reset, this lets us know when to wait for saved files to update terminals.
2052+ this . didEditFile = false
20552053
2056- // waiting for updated diagnostics lets terminal output be the most up-to-date possible
2054+ // Waiting for updated diagnostics lets terminal output be the most
2055+ // up-to-date possible.
20572056 let terminalDetails = ""
2057+
20582058 if ( busyTerminals . length > 0 ) {
2059- // terminals are cool, let's retrieve their output
2059+ // Terminals are cool, let's retrieve their output.
20602060 terminalDetails += "\n\n# Actively Running Terminals"
2061+
20612062 for ( const busyTerminal of busyTerminals ) {
20622063 terminalDetails += `\n## Original command: \`${ busyTerminal . getLastCommand ( ) } \``
20632064 let newOutput = TerminalRegistry . getUnretrievedOutput ( busyTerminal . id )
2065+
20642066 if ( newOutput ) {
20652067 newOutput = Terminal . compressTerminalOutput ( newOutput , terminalOutputLineLimit )
20662068 terminalDetails += `\n### New Output\n${ newOutput } `
2067- } else {
2068- // details += `\n(Still running, no new output)` // don't want to show this right after running the command
20692069 }
20702070 }
20712071 }
20722072
2073- // First check if any inactive terminals in this task have completed processes with output
2073+ // First check if any inactive terminals in this task have completed
2074+ // processes with output.
20742075 const terminalsWithOutput = inactiveTerminals . filter ( ( terminal ) => {
20752076 const completedProcesses = terminal . getProcessesWithOutput ( )
20762077 return completedProcesses . length > 0
20772078 } )
20782079
2079- // Only add the header if there are terminals with output
2080+ // Only add the header if there are terminals with output.
20802081 if ( terminalsWithOutput . length > 0 ) {
20812082 terminalDetails += "\n\n# Inactive Terminals with Completed Process Output"
20822083
2083- // Process each terminal with output
2084+ // Process each terminal with output.
20842085 for ( const inactiveTerminal of terminalsWithOutput ) {
20852086 let terminalOutputs : string [ ] = [ ]
20862087
2087- // Get output from completed processes queue
2088+ // Get output from completed processes queue.
20882089 const completedProcesses = inactiveTerminal . getProcessesWithOutput ( )
2090+
20892091 for ( const process of completedProcesses ) {
20902092 let output = process . getUnretrievedOutput ( )
2093+
20912094 if ( output ) {
20922095 output = Terminal . compressTerminalOutput ( output , terminalOutputLineLimit )
20932096 terminalOutputs . push ( `Command: \`${ process . command } \`\n${ output } ` )
20942097 }
20952098 }
20962099
2097- // Clean the queue after retrieving output
2100+ // Clean the queue after retrieving output.
20982101 inactiveTerminal . cleanCompletedProcessQueue ( )
20992102
2100- // Add this terminal's outputs to the details
2103+ // Add this terminal's outputs to the details.
21012104 if ( terminalOutputs . length > 0 ) {
21022105 terminalDetails += `\n## Terminal ${ inactiveTerminal . id } `
21032106 terminalOutputs . forEach ( ( output ) => {
@@ -2107,15 +2110,11 @@ export class Cline extends EventEmitter<ClineEvents> {
21072110 }
21082111 }
21092112
2110- // details += "\n\n# VSCode Workspace Errors"
2111- // if (diagnosticsDetails) {
2112- // details += diagnosticsDetails
2113- // } else {
2114- // details += "\n(No errors detected)"
2115- // }
2113+ // console.log(`[Cline#getEnvironmentDetails] terminalDetails: ${terminalDetails}`)
21162114
2117- // Add recently modified files section
2115+ // Add recently modified files section.
21182116 const recentlyModifiedFiles = this . fileContextTracker . getAndClearRecentlyModifiedFiles ( )
2117+
21192118 if ( recentlyModifiedFiles . length > 0 ) {
21202119 details +=
21212120 "\n\n# Recently Modified Files\nThese files have been modified since you last accessed them (file was just edited so you may need to re-read it before editing):"
@@ -2128,8 +2127,9 @@ export class Cline extends EventEmitter<ClineEvents> {
21282127 details += terminalDetails
21292128 }
21302129
2131- // Add current time information with timezone
2130+ // Add current time information with timezone.
21322131 const now = new Date ( )
2132+
21332133 const formatter = new Intl . DateTimeFormat ( undefined , {
21342134 year : "numeric" ,
21352135 month : "numeric" ,
@@ -2139,22 +2139,26 @@ export class Cline extends EventEmitter<ClineEvents> {
21392139 second : "numeric" ,
21402140 hour12 : true ,
21412141 } )
2142+
21422143 const timeZone = formatter . resolvedOptions ( ) . timeZone
21432144 const timeZoneOffset = - now . getTimezoneOffset ( ) / 60 // Convert to hours and invert sign to match conventional notation
21442145 const timeZoneOffsetHours = Math . floor ( Math . abs ( timeZoneOffset ) )
21452146 const timeZoneOffsetMinutes = Math . abs ( Math . round ( ( Math . abs ( timeZoneOffset ) - timeZoneOffsetHours ) * 60 ) )
21462147 const timeZoneOffsetStr = `${ timeZoneOffset >= 0 ? "+" : "-" } ${ timeZoneOffsetHours } :${ timeZoneOffsetMinutes . toString ( ) . padStart ( 2 , "0" ) } `
21472148 details += `\n\n# Current Time\n${ formatter . format ( now ) } (${ timeZone } , UTC${ timeZoneOffsetStr } )`
21482149
2149- // Add context tokens information
2150+ // Add context tokens information.
21502151 const { contextTokens, totalCost } = getApiMetrics ( this . clineMessages )
21512152 const modelInfo = this . api . getModel ( ) . info
21522153 const contextWindow = modelInfo . contextWindow
2154+
21532155 const contextPercentage =
21542156 contextTokens && contextWindow ? Math . round ( ( contextTokens / contextWindow ) * 100 ) : undefined
2157+
21552158 details += `\n\n# Current Context Size (Tokens)\n${ contextTokens ? `${ contextTokens . toLocaleString ( ) } (${ contextPercentage } %)` : "(Not available)" } `
21562159 details += `\n\n# Current Cost\n${ totalCost !== null ? `$${ totalCost . toFixed ( 2 ) } ` : "(Not available)" } `
2157- // Add current mode and any mode-specific warnings
2160+
2161+ // Add current mode and any mode-specific warnings.
21582162 const {
21592163 mode,
21602164 customModes,
@@ -2164,28 +2168,31 @@ export class Cline extends EventEmitter<ClineEvents> {
21642168 customInstructions : globalCustomInstructions ,
21652169 language,
21662170 } = ( await this . providerRef . deref ( ) ?. getState ( ) ) ?? { }
2171+
21672172 const currentMode = mode ?? defaultModeSlug
2173+
21682174 const modeDetails = await getFullModeDetails ( currentMode , customModes , customModePrompts , {
21692175 cwd : this . cwd ,
21702176 globalCustomInstructions,
21712177 language : language ?? formatLanguage ( vscode . env . language ) ,
21722178 } )
2179+
21732180 details += `\n\n# Current Mode\n`
21742181 details += `<slug>${ currentMode } </slug>\n`
21752182 details += `<name>${ modeDetails . name } </name>\n`
21762183 details += `<model>${ apiModelId } </model>\n`
2184+
21772185 if ( Experiments . isEnabled ( experiments ?? { } , EXPERIMENT_IDS . POWER_STEERING ) ) {
21782186 details += `<role>${ modeDetails . roleDefinition } </role>\n`
2187+
21792188 if ( modeDetails . customInstructions ) {
21802189 details += `<custom_instructions>${ modeDetails . customInstructions } </custom_instructions>\n`
21812190 }
21822191 }
21832192
2184- // Add warning if not in code mode
2193+ // Add warning if not in code mode.
21852194 if (
2186- ! isToolAllowedForMode ( "write_to_file" , currentMode , customModes ?? [ ] , {
2187- apply_diff : this . diffEnabled ,
2188- } ) &&
2195+ ! isToolAllowedForMode ( "write_to_file" , currentMode , customModes ?? [ ] , { apply_diff : this . diffEnabled } ) &&
21892196 ! isToolAllowedForMode ( "apply_diff" , currentMode , customModes ?? [ ] , { apply_diff : this . diffEnabled } )
21902197 ) {
21912198 const currentModeName = getModeBySlug ( currentMode , customModes ) ?. name ?? currentMode
@@ -2196,20 +2203,24 @@ export class Cline extends EventEmitter<ClineEvents> {
21962203 if ( includeFileDetails ) {
21972204 details += `\n\n# Current Workspace Directory (${ this . cwd . toPosix ( ) } ) Files\n`
21982205 const isDesktop = arePathsEqual ( this . cwd , path . join ( os . homedir ( ) , "Desktop" ) )
2206+
21992207 if ( isDesktop ) {
2200- // don't want to immediately access desktop since it would show permission popup
2208+ // Don't want to immediately access desktop since it would show
2209+ // permission popup.
22012210 details += "(Desktop files not shown automatically. Use list_files to explore if needed.)"
22022211 } else {
22032212 const maxFiles = maxWorkspaceFiles ?? 200
22042213 const [ files , didHitLimit ] = await listFiles ( this . cwd , true , maxFiles )
22052214 const { showRooIgnoredFiles = true } = ( await this . providerRef . deref ( ) ?. getState ( ) ) ?? { }
2215+
22062216 const result = formatResponse . formatFilesList (
22072217 this . cwd ,
22082218 files ,
22092219 didHitLimit ,
22102220 this . rooIgnoreController ,
22112221 showRooIgnoredFiles ,
22122222 )
2223+
22132224 details += result
22142225 }
22152226 }
0 commit comments