@@ -10,6 +10,16 @@ import {
1010
1111const asyncExec = util . promisify ( childProcess . exec ) ;
1212
13+ // Add color-supporting environment variables
14+ const getColorEnv = ( ) => ( {
15+ ...process . env ,
16+ FORCE_COLOR : "1" ,
17+ COLORTERM : "truecolor" ,
18+ TERM : "xterm-256color" ,
19+ CLICOLOR : "1" ,
20+ CLICOLOR_FORCE : "1" ,
21+ } ) ;
22+
1323const ENABLED_FOR_REMOTES = [
1424 "" ,
1525 "local" ,
@@ -56,10 +66,11 @@ export const runTerminalCommandImpl: ToolImpl = async (args, extras) => {
5666 }
5767 }
5868
59- // Use spawn instead of exec to get streaming output
69+ // Use spawn with color environment
6070 const childProc = childProcess . spawn ( args . command , {
6171 cwd,
6272 shell : true ,
73+ env : getColorEnv ( ) , // Add enhanced environment for colors
6374 } ) ;
6475
6576 childProc . stdout ?. on ( "data" , ( data ) => {
@@ -130,26 +141,7 @@ export const runTerminalCommandImpl: ToolImpl = async (args, extras) => {
130141 return ;
131142 }
132143
133- if ( ! waitForCompletion ) {
134- // Already resolved, just update the UI with final output
135- if ( extras . onPartialOutput ) {
136- const status =
137- code === 0 || ! code
138- ? "\nBackground command completed"
139- : `\nBackground command failed with exit code ${ code } ` ;
140- extras . onPartialOutput ( {
141- toolCallId,
142- contextItems : [
143- {
144- name : "Terminal" ,
145- description : "Terminal command output" ,
146- content : terminalOutput ,
147- status : status ,
148- } ,
149- ] ,
150- } ) ;
151- }
152- } else {
144+ if ( waitForCompletion ) {
153145 // Normal completion, resolve now
154146 if ( code === 0 ) {
155147 const status = "Command completed" ;
@@ -172,6 +164,25 @@ export const runTerminalCommandImpl: ToolImpl = async (args, extras) => {
172164 } ,
173165 ] ) ;
174166 }
167+ } else {
168+ // Already resolved, just update the UI with final output
169+ if ( extras . onPartialOutput ) {
170+ const status =
171+ code === 0 || ! code
172+ ? "\nBackground command completed"
173+ : `\nBackground command failed with exit code ${ code } ` ;
174+ extras . onPartialOutput ( {
175+ toolCallId,
176+ contextItems : [
177+ {
178+ name : "Terminal" ,
179+ description : "Terminal command output" ,
180+ content : terminalOutput ,
181+ status : status ,
182+ } ,
183+ ] ,
184+ } ) ;
185+ }
175186 }
176187 } ) ;
177188
@@ -197,14 +208,43 @@ export const runTerminalCommandImpl: ToolImpl = async (args, extras) => {
197208 const workspaceDirs = await extras . ide . getWorkspaceDirs ( ) ;
198209 const cwd = fileURLToPath ( workspaceDirs [ 0 ] ) ;
199210
200- if ( ! waitForCompletion ) {
211+ if ( waitForCompletion ) {
212+ // Standard execution, waiting for completion
213+ try {
214+ // Use color environment for exec as well
215+ const output = await asyncExec ( args . command , {
216+ cwd,
217+ env : getColorEnv ( ) ,
218+ } ) ;
219+ const status = "Command completed" ;
220+ return [
221+ {
222+ name : "Terminal" ,
223+ description : "Terminal command output" ,
224+ content : output . stdout ?? "" ,
225+ status : status ,
226+ } ,
227+ ] ;
228+ } catch ( error : any ) {
229+ const status = `Command failed with: ${ error . message || error . toString ( ) } ` ;
230+ return [
231+ {
232+ name : "Terminal" ,
233+ description : "Terminal command output" ,
234+ content : error . stderr ?? error . toString ( ) ,
235+ status : status ,
236+ } ,
237+ ] ;
238+ }
239+ } else {
201240 // For non-streaming but also not waiting for completion, use spawn
202241 // but don't attach any listeners other than error
203242 try {
204- // Use spawn instead of exec but don't wait
243+ // Use spawn with color environment
205244 const childProc = childProcess . spawn ( args . command , {
206245 cwd,
207246 shell : true ,
247+ env : getColorEnv ( ) , // Add color environment
208248 // Detach the process so it's not tied to the parent
209249 detached : true ,
210250 // Redirect to /dev/null equivalent (works cross-platform)
@@ -246,30 +286,6 @@ export const runTerminalCommandImpl: ToolImpl = async (args, extras) => {
246286 } ,
247287 ] ;
248288 }
249- } else {
250- // Standard execution, waiting for completion
251- try {
252- const output = await asyncExec ( args . command , { cwd } ) ;
253- const status = "Command completed" ;
254- return [
255- {
256- name : "Terminal" ,
257- description : "Terminal command output" ,
258- content : output . stdout ?? "" ,
259- status : status ,
260- } ,
261- ] ;
262- } catch ( error : any ) {
263- const status = `Command failed with: ${ error . message || error . toString ( ) } ` ;
264- return [
265- {
266- name : "Terminal" ,
267- description : "Terminal command output" ,
268- content : error . stderr ?? error . toString ( ) ,
269- status : status ,
270- } ,
271- ] ;
272- }
273289 }
274290 }
275291 }
0 commit comments