Skip to content

bug(command/skills): Interactive Consent Dialog Persists After Successful Workspace Skill Installation #21297

@HunDun0Ben

Description

@HunDun0Ben

1. Description

When installing or linking Workspace Skills (e.g., running /skills link --scope workspace) in interactive mode, the "Yes/No" consent dialog remains visible on the screen even after the user selects "Yes" and the operation completes successfully. This blocks the input area, forcing the user to run /clear or restart the CLI to resume work.

2. Steps to Reproduce

  1. Start Gemini CLI in interactive mode.
  2. Execute: /skills link <path_to_skill> --scope workspace.
  3. When the ConsentPrompt appears, use arrow keys to select "Yes" and press Enter (\r).
  4. Observe: The terminal history shows "Successfully linked...", but the selection dialog persists on top of the input area.

3. Expected Behavior

After pressing Enter to confirm, the ConsentPrompt should be immediately unmounted from the DialogManager, and the UI should return to the normal input state.

4. Actual Behavior

The dialog persists. React DevTools (or state inspection) shows that commandConfirmationRequest in UIState still holds the previous request object instead of being reset to null.

5. Technical Root Cause Analysis

A. Missing State Cleanup Logic

In packages/cli/src/config/extensions/consent.ts, the onConfirm callback in promptForConsentInteractive only resolves the promise but fails to clear the UI state.

Affected Code:

// packages/cli/src/config/extensions/consent.ts
async function promptForConsentInteractive(
  prompt: string,
  addExtensionUpdateConfirmationRequest: (value: ConfirmationRequest) => void,
): Promise<boolean> {
  return new Promise<boolean>((resolve) => {
    addExtensionUpdateConfirmationRequest({
      prompt,
      onConfirm: (resolvedConfirmed) => {
        // BUG: Missing addExtensionUpdateConfirmationRequest(null) to clear UI
        resolve(resolvedConfirmed); 
      },
    });
  });
}

B. Rendering Blocked by Heavy Async Operations (Race Condition)

In packages/cli/src/ui/commands/skillsCommand.ts, linkSkill performs heavy I/O operations (like reloadSkills). Since several synchronous tasks are executed immediately after the await, the Ink rendering engine doesn't get a "frame" to process the "hide dialog" state update before the main thread becomes busy, leading to a visual freeze.

6. Suggested Fixes

  1. Update promptForConsentInteractive: Ensure addExtensionUpdateConfirmationRequest(null) is called inside onConfirm. Wrap the resolve in setImmediate if necessary to ensure the UI update takes precedence.
  2. Refine Type Definitions: Update packages/cli/src/ui/commands/types.ts to explicitly allow setConfirmationRequest to accept null.
  3. Command-Level Cleanup: Manually call context.ui.setConfirmationRequest(null) at the end of the linkSkill action in skillsCommand.ts as a safety measure.

7. Environment Information

  • Version: Gemini CLI v0.34.0-nightly (or latest)
  • Platform: Linux/macOS
  • Renderer: Ink (React for CLI)

Metadata

Metadata

Assignees

Labels

area/coreIssues related to User Interface, OS Support, Core Functionalityhelp wantedWe will accept PRs from all issues marked as "help wanted". Thanks for your support!

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions