mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-11 22:51:26 +00:00
feat: display hook execution in chat
This commit is contained in:
parent
8bb5b61555
commit
08b41f2b9e
4 changed files with 71 additions and 4 deletions
|
|
@ -149,6 +149,7 @@ export function isNonBlockingAsk(ask: ClineAsk): ask is NonBlockingAsk {
|
|||
* - `condense_context`: Context condensation/summarization has started
|
||||
* - `condense_context_error`: Error occurred during context condensation
|
||||
* - `codebase_search_result`: Results from searching the codebase
|
||||
* - `hook_triggered`: Notification that a hook has been executed
|
||||
*/
|
||||
export const clineSays = [
|
||||
"error",
|
||||
|
|
@ -179,6 +180,7 @@ export const clineSays = [
|
|||
"condense_context_error",
|
||||
"sliding_window_truncation",
|
||||
"codebase_search_result",
|
||||
"hook_triggered",
|
||||
"user_edit_todos",
|
||||
] as const
|
||||
|
||||
|
|
|
|||
|
|
@ -541,8 +541,12 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
})
|
||||
|
||||
// Initialize tool execution hooks
|
||||
this.toolExecutionHooks = createToolExecutionHooks(provider.getHookManager() ?? null, (status) =>
|
||||
provider.postHookStatusToWebview(status),
|
||||
this.toolExecutionHooks = createToolExecutionHooks(
|
||||
provider.getHookManager() ?? null,
|
||||
(status) => provider.postHookStatusToWebview(status),
|
||||
async (type, text) => {
|
||||
await this.say(type as ClineSay, text)
|
||||
},
|
||||
)
|
||||
|
||||
this.diffEnabled = enableDiff
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ export type HookStatusCallback = (status: {
|
|||
modified?: boolean
|
||||
}) => void
|
||||
|
||||
/**
|
||||
* Callback for emitting messages to chat history.
|
||||
*/
|
||||
export type SayCallback = (type: string, text?: string) => Promise<void>
|
||||
|
||||
/**
|
||||
* Tool Execution Hooks Service
|
||||
*
|
||||
|
|
@ -78,10 +83,12 @@ export type HookStatusCallback = (status: {
|
|||
export class ToolExecutionHooks {
|
||||
private hookManager: IHookManager | null
|
||||
private statusCallback?: HookStatusCallback
|
||||
private sayCallback?: SayCallback
|
||||
|
||||
constructor(hookManager: IHookManager | null, statusCallback?: HookStatusCallback) {
|
||||
constructor(hookManager: IHookManager | null, statusCallback?: HookStatusCallback, sayCallback?: SayCallback) {
|
||||
this.hookManager = hookManager
|
||||
this.statusCallback = statusCallback
|
||||
this.sayCallback = sayCallback
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -98,6 +105,13 @@ export class ToolExecutionHooks {
|
|||
this.statusCallback = callback
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the say callback.
|
||||
*/
|
||||
setSayCallback(callback: SayCallback | undefined): void {
|
||||
this.sayCallback = callback
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute PreToolUse hooks before a tool is executed.
|
||||
*
|
||||
|
|
@ -128,6 +142,8 @@ export class ToolExecutionHooks {
|
|||
try {
|
||||
const result = await this.hookManager.executeHooks("PreToolUse", { context: hookContext })
|
||||
|
||||
await this.emitHookTriggeredMessages(result)
|
||||
|
||||
if (result.blocked) {
|
||||
// Hook blocked the execution
|
||||
this.emitStatus({
|
||||
|
|
@ -216,6 +232,8 @@ export class ToolExecutionHooks {
|
|||
try {
|
||||
const result = await this.hookManager.executeHooks("PostToolUse", { context: hookContext })
|
||||
|
||||
await this.emitHookTriggeredMessages(result)
|
||||
|
||||
this.emitStatus({
|
||||
status: "completed",
|
||||
event: "PostToolUse",
|
||||
|
|
@ -273,6 +291,8 @@ export class ToolExecutionHooks {
|
|||
try {
|
||||
const result = await this.hookManager.executeHooks("PostToolUseFailure", { context: hookContext })
|
||||
|
||||
await this.emitHookTriggeredMessages(result)
|
||||
|
||||
this.emitStatus({
|
||||
status: "completed",
|
||||
event: "PostToolUseFailure",
|
||||
|
|
@ -331,6 +351,8 @@ export class ToolExecutionHooks {
|
|||
try {
|
||||
const result = await this.hookManager.executeHooks("PermissionRequest", { context: hookContext })
|
||||
|
||||
await this.emitHookTriggeredMessages(result)
|
||||
|
||||
if (result.blocked) {
|
||||
// Hook blocked - do not show approval dialog, deny the tool
|
||||
this.emitStatus({
|
||||
|
|
@ -444,6 +466,25 @@ export class ToolExecutionHooks {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit hook triggered messages for successful hook executions.
|
||||
*/
|
||||
private async emitHookTriggeredMessages(result: HooksExecutionResult): Promise<void> {
|
||||
if (!this.sayCallback) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const hookResult of result.results) {
|
||||
if (!hookResult.error && hookResult.exitCode === 0) {
|
||||
try {
|
||||
await this.sayCallback("hook_triggered", hookResult.hook.id)
|
||||
} catch {
|
||||
// Ignore callback errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -452,6 +493,7 @@ export class ToolExecutionHooks {
|
|||
export function createToolExecutionHooks(
|
||||
hookManager: IHookManager | null,
|
||||
statusCallback?: HookStatusCallback,
|
||||
sayCallback?: SayCallback,
|
||||
): ToolExecutionHooks {
|
||||
return new ToolExecutionHooks(hookManager, statusCallback)
|
||||
return new ToolExecutionHooks(hookManager, statusCallback, sayCallback)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1364,6 +1364,25 @@ export const ChatRowContent = ({
|
|||
checkpoint={message.checkpoint}
|
||||
/>
|
||||
)
|
||||
case "hook_triggered":
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
padding: "4px 0",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
fontSize: "12px",
|
||||
}}>
|
||||
<span
|
||||
className="codicon codicon-symbol-event"
|
||||
style={{ fontSize: "14px" }}
|
||||
aria-label="Hook icon"
|
||||
/>
|
||||
<span>Hook: {message.text} triggered</span>
|
||||
</div>
|
||||
)
|
||||
case "condense_context":
|
||||
// In-progress state
|
||||
if (message.partial) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue