feat(tools): add auto-approval support for attempt_completion commands (#8926)

* feat(tools): add auto-approval support for attempt_completion commands

- Add auto-approval logic for bash commands in AttemptCompletionHandler
- Show commands as 'say' instead of 'ask' when auto-approved
- Display notification prompting user approval when manual approval needed
- Add 30-second timeout notification for long-running auto-approved commands
- Fix Logger import path from @/shared to @shared

* Send to cline provider
This commit is contained in:
Ara
2026-02-09 15:57:29 -08:00
committed by GitHub
parent 84fef6fe1f
commit 7236d02ebb
@@ -7,9 +7,10 @@ import { showSystemNotification } from "@integrations/notifications"
import { telemetryService } from "@services/telemetry"
import { findLastIndex } from "@shared/array"
import { COMPLETION_RESULT_CHANGES_FLAG } from "@shared/ExtensionMessage"
import { Logger } from "@shared/services/Logger"
import { ClineDefaultTool } from "@shared/tools"
import { Logger } from "@/shared/services/Logger"
import type { ToolResponse } from "../../index"
import { showNotificationForApproval } from "../../utils"
import { buildUserFeedbackContent } from "../../utils/buildUserFeedbackContent"
import type { IPartialBlockHandler, IToolHandler } from "../ToolExecutorCoordinator"
import type { TaskConfig } from "../types/TaskConfig"
@@ -162,14 +163,31 @@ export class AttemptCompletionHandler implements IToolHandler, IPartialBlockHand
await config.callbacks.updateFCListFromToolResponse(block.params.task_progress)
}
// complete command message - need to ask for approval
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("command", command, config)
if (!didApprove) {
return formatResponse.toolDenied()
// Check if command should be auto-approved
// attempt_completion commands don't have requires_approval param, so we treat them as safe commands
const autoApproveResult = config.autoApprover?.shouldAutoApproveTool(ClineDefaultTool.BASH)
const autoApproveSafe = Array.isArray(autoApproveResult) ? autoApproveResult[0] : autoApproveResult
if (autoApproveSafe) {
// Auto-approve flow - show command as 'say' instead of 'ask'
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "command")
await config.callbacks.say("command", command, undefined, undefined, false)
} else {
// Manual approval flow - need to ask for approval
showNotificationForApproval(
`Cline wants to execute a command: ${command}`,
config.autoApprovalSettings.enableNotifications,
)
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("command", command, config)
if (!didApprove) {
return formatResponse.toolDenied()
}
}
// User approved, execute the command
// Execute the command
const [userRejected, execCommandResult] = await config.callbacks.executeCommandTool(command!, undefined) // no timeout for attempt_completion command
if (userRejected) {
config.taskState.didRejectTool = true
return execCommandResult