fix: Re-create workflow terminal when closed

Issue [VS Code] Closing Duo's terminal prevents tool ... (#2048 - closed)

Description

This change improves how the terminal manager handles terminals that get closed by users. Previously, if someone manually closed a terminal window, the system would still think it existed and try to reuse it, which could cause errors.

The update adds a listener that watches for when terminals are closed and automatically removes them from the internal tracking system. This means when a user closes a terminal and then runs another command with the same workflow, the system will create a fresh terminal instead of trying to use the closed one.

The code also switches from using a simple object to a Map for better terminal tracking, and consolidates all cleanup operations into a single disposal system for more reliable resource management.

Related Issues

Resolves #[issue_number]

How has this been tested?

  • If src/browser or src/common has been modified, please consider interoperability with the Web IDE. See Running the Extension in WebIDE.
  • Consider an end-to-end test for significant new features that aren't covered by integration tests.

As usual, it's challenging to reproduce bugs that are triggered by the non-deterministic responses of agents. There are two ways of reproducing this bug:

  1. Come up with a prompt that makes the agentic tool two execute two terminal commands.
  2. Apply the following patch that simulates the execution of two commands in a time frame:
    1. Apply the following patch

      diff --git a/src/common/duo_workflow/terminal_manager.ts b/src/common/duo_workflow/terminal_manager.ts
      index 51fc756b..ac56f89b 100644
      --- a/src/common/duo_workflow/terminal_manager.ts
      +++ b/src/common/duo_workflow/terminal_manager.ts
      @@ -20,6 +20,14 @@ export class TerminalManager implements Disposable {
               return this.#executeCommand(workflowId, command, args);
             },
           );
      +
      +    setTimeout(() => {
      +      this.#executeCommand('123', 'ls', ['$(pwd)']).catch(log.error);
      +    }, 5000);
      +
      +    setTimeout(() => {
      +      this.#executeCommand('123', 'echo', ['Hello!']).catch(log.error);
      +    }, 10000);
         }
       
         async #executeCommand(workflowId: string, command: string, args: string[]) {
    2. Start the extension. You should see the same behavior demonstrated in the videos below.

Screenshots (if appropriate)

Before After
before_fix.mov after_fix.mov

What CHANGELOG entry will this MR create?

  • fix: Bug fix fixes - a user-facing issue in production - included in changelog
  • feature: New feature - a user-facing change which adds functionality - included in changelog
  • BREAKING CHANGE: (fix or feature that would cause existing functionality to change) - should bump major version, mentioned in the changelog
  • None - other non-user-facing changes
Edited by Enrique Alcántara

Merge request reports

Loading
Loading