refactor: unify hook notification system, remove duplicate broadcasts

- Replace forward-hook.ps1 with notify.ps1 (now accepts optional agent param)
- Remove ejecutor settings.local.json (redundant status hooks, deriveStatus covers it)
- Remove legacy claude-permission system (route, store methods, terminal broadcast)
- Remove redundant deriveStatus + /claude-status POST from claude-hook.ts
  (broadcastClaudeHook → processHookEvent already handles status derivation)
- Clean up HookNotifications.vue permission buttons (dead code)
This commit is contained in:
2026-02-24 11:07:34 -06:00
parent 5bd115e197
commit 2edb3623c8
10 changed files with 23 additions and 333 deletions

View File

@@ -83,14 +83,8 @@ function typeClass(n: HookNotification) {
<span v-if="n.detail" class="toast-detail">{{ n.detail }}</span>
</div>
<!-- Permission buttons -->
<div v-if="n.event === 'PermissionRequest' && n.requestId" class="toast-actions">
<button class="toast-btn toast-btn--allow" @click="store.respondPermission(n.id, n.requestId!, 'allow')">Allow</button>
<button class="toast-btn toast-btn--deny" @click="store.respondPermission(n.id, n.requestId!, 'deny')">Deny</button>
</div>
<!-- Dismiss -->
<button v-else class="toast-close" @click="store.remove(n.id)">&times;</button>
<button class="toast-close" @click="store.remove(n.id)">&times;</button>
</div>
</TransitionGroup>
</Teleport>

View File

@@ -1,6 +1,5 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { apiFetch } from '@/lib/tauri'
export interface HookNotification {
id: string
@@ -11,10 +10,6 @@ export interface HookNotification {
type: 'info' | 'success' | 'warning' | 'error'
timestamp: number
persistent?: boolean
// Permission-specific
requestId?: string
toolName?: string
toolInput?: unknown
}
export const useClaudeHooksStore = defineStore('claude-hooks', () => {
@@ -144,47 +139,7 @@ export const useClaudeHooksStore = defineStore('claude-hooks', () => {
}
}
// Process a claude-permission WS message
function processPermission(data: Record<string, any>) {
const id = `perm_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`
const toolName = data.tool_name || 'Unknown'
const input = data.tool_input || {}
let detail = ''
if (toolName === 'Bash') {
const cmd = input.command || ''
detail = cmd.length > 120 ? cmd.slice(0, 120) + '...' : cmd
} else if (toolName === 'Edit' || toolName === 'Write') {
detail = input.file_path ? shortPath(input.file_path) : ''
} else {
detail = JSON.stringify(input).slice(0, 100)
}
add({
id, event: 'PermissionRequest', type: 'error',
icon: '', title: `Permission: ${toolName}`,
detail,
timestamp: Date.now(),
persistent: true,
requestId: data.requestId,
toolName,
toolInput: input
})
}
async function respondPermission(notifId: string, requestId: string, decision: 'allow' | 'deny') {
try {
await apiFetch('/api/claude-permission-respond', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ requestId, decision })
})
} catch (e) {
console.error('[Hooks] Failed to respond permission:', e)
}
remove(notifId)
}
return { notifications, visible, add, remove, clear, processHook, processPermission, respondPermission }
return { notifications, visible, add, remove, clear, processHook }
})
function shortPath(p: string): string {