From 9b3e9bd09acb2ce5689e4ae5d7d593d371e15d9f Mon Sep 17 00:00:00 2001 From: Bruno Bornsztein Date: Tue, 17 Feb 2026 21:24:58 -0600 Subject: [PATCH] Fix permission detail display by stashing tool info from PreToolUse hook The Notification hook (permission_prompt) doesn't include tool_name/tool_input fields - those are only available in PreToolUse hooks. PR #458 called formatPermissionDetail() on the notification input, which always returned "" because ToolName was empty. Fix: store the formatted tool detail as a "pending_tool" log entry during PreToolUse, then retrieve it in the notification handler to append to the permission message. Also filter pending_tool entries from the execution log display since they're internal bookkeeping. Co-Authored-By: Claude Opus 4.6 --- cmd/task/main.go | 30 ++++++++++++++++++++++++++++-- internal/ui/detail.go | 4 ++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/cmd/task/main.go b/cmd/task/main.go index a303bede..4b2b2cf4 100644 --- a/cmd/task/main.go +++ b/cmd/task/main.go @@ -3514,8 +3514,10 @@ func handleNotificationHook(database *db.DB, taskID int64, input *ClaudeHookInpu if input.Message != "" { msg = "Waiting for permission: " + input.Message } - // Append tool detail so the approval dialog shows what's being requested - if detail := formatPermissionDetail(input); detail != "" { + // The Notification hook doesn't include tool_name/tool_input, but the + // PreToolUse hook (which fires just before) stashes the detail as a + // "pending_tool" log entry. Retrieve and append to the permission message. + if detail := latestPendingToolDetail(database, taskID); detail != "" { msg += "\n" + detail } } @@ -3604,6 +3606,13 @@ func handlePreToolUseHook(database *db.DB, taskID int64, input *ClaudeHookInput) database.AppendTaskLog(taskID, "system", "Claude resumed working") } + // Store tool detail so the Notification(permission_prompt) handler can show it. + // The Notification hook doesn't include tool_name/tool_input, but PreToolUse + // fires right before it, so we stash the detail here for retrieval. + if detail := formatPermissionDetail(input); detail != "" { + database.AppendTaskLog(taskID, "pending_tool", detail) + } + return nil } @@ -3762,6 +3771,23 @@ func formatPermissionDetail(input *ClaudeHookInput) string { return detail } +// latestPendingToolDetail retrieves the most recent "pending_tool" log entry +// for a task. This is written by handlePreToolUseHook and consumed here by the +// notification handler to show what tool/command is requesting permission. +func latestPendingToolDetail(database *db.DB, taskID int64) string { + logs, err := database.GetTaskLogs(taskID, 5) + if err != nil { + return "" + } + // Logs are in DESC order (most recent first). + for _, l := range logs { + if l.LineType == "pending_tool" { + return l.Content + } + } + return "" +} + // tailClaudeLogs tails all claude session logs for debugging. func tailClaudeLogs() error { home, err := os.UserHomeDir() diff --git a/internal/ui/detail.go b/internal/ui/detail.go index 6129a6cf..a3851594 100644 --- a/internal/ui/detail.go +++ b/internal/ui/detail.go @@ -2550,6 +2550,10 @@ func (m *DetailModel) renderContent() string { b.WriteString("\n\n") for _, log := range m.logs { + // Skip internal-only log entries not meant for display + if log.LineType == "pending_tool" { + continue + } icon := " " switch log.LineType { case "system":