feat: Add intelligent auto-router and enhanced integrations
- Add intelligent-router.sh hook for automatic agent routing - Add AUTO-TRIGGER-SUMMARY.md documentation - Add FINAL-INTEGRATION-SUMMARY.md documentation - Complete Prometheus integration (6 commands + 4 tools) - Complete Dexto integration (12 commands + 5 tools) - Enhanced Ralph with access to all agents - Fix /clawd command (removed disable-model-invocation) - Update hooks.json to v5 with intelligent routing - 291 total skills now available - All 21 commands with automatic routing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
158
dexto/packages/webui/lib/stores/approvalStore.ts
Normal file
158
dexto/packages/webui/lib/stores/approvalStore.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Approval Store
|
||||
*
|
||||
* Manages approval requests from the agent using Zustand.
|
||||
* Handles queueing when multiple approvals arrive simultaneously.
|
||||
*
|
||||
* Flow:
|
||||
* 1. approval:request event → addApproval() → sets pendingApproval or queues
|
||||
* 2. User responds via UI → sends response to agent
|
||||
* 3. approval:response event → processResponse() → clears and processes next
|
||||
*/
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { ApprovalStatus } from '@dexto/core';
|
||||
import type { ApprovalRequest, ApprovalResponse } from '@dexto/core';
|
||||
|
||||
export interface PendingApproval {
|
||||
request: ApprovalRequest;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
interface ApprovalStore {
|
||||
// Current pending approval being displayed
|
||||
pendingApproval: ApprovalRequest | null;
|
||||
|
||||
// Queue of pending approvals waiting to be displayed
|
||||
queue: ApprovalRequest[];
|
||||
|
||||
// Actions
|
||||
addApproval: (request: ApprovalRequest) => void;
|
||||
processResponse: (response: ApprovalResponse) => void;
|
||||
clearApproval: () => void;
|
||||
clearAll: () => void;
|
||||
|
||||
// Selectors
|
||||
getPendingCount: () => number;
|
||||
getPendingForSession: (sessionId: string) => ApprovalRequest[];
|
||||
hasPendingApproval: () => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if approval response status is terminal (ends the approval)
|
||||
*/
|
||||
function isTerminalStatus(status: ApprovalStatus): boolean {
|
||||
return (
|
||||
status === ApprovalStatus.APPROVED ||
|
||||
status === ApprovalStatus.DENIED ||
|
||||
status === ApprovalStatus.CANCELLED
|
||||
);
|
||||
}
|
||||
|
||||
export const useApprovalStore = create<ApprovalStore>((set, get) => ({
|
||||
pendingApproval: null,
|
||||
queue: [],
|
||||
|
||||
/**
|
||||
* Add a new approval request
|
||||
* If there's already a pending approval, queue it
|
||||
*/
|
||||
addApproval: (request: ApprovalRequest) => {
|
||||
set((state) => {
|
||||
// If there's already a pending approval, add to queue
|
||||
if (state.pendingApproval) {
|
||||
return {
|
||||
queue: [...state.queue, request],
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise, set as pending
|
||||
return {
|
||||
pendingApproval: request,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Process an approval response
|
||||
* If status is terminal (approved/denied/cancelled), clear pending and process next
|
||||
*/
|
||||
processResponse: (response: ApprovalResponse) => {
|
||||
set((state) => {
|
||||
// Only process if this response matches the current pending approval
|
||||
if (state.pendingApproval?.approvalId !== response.approvalId) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// If terminal status, clear pending and process next
|
||||
if (isTerminalStatus(response.status)) {
|
||||
// Get next from queue
|
||||
const [next, ...rest] = state.queue;
|
||||
|
||||
return {
|
||||
pendingApproval: next ?? null,
|
||||
queue: rest,
|
||||
};
|
||||
}
|
||||
|
||||
// Non-terminal status (e.g., future streaming updates), keep pending
|
||||
return state;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear current approval and process next in queue
|
||||
* Used for manual dismissal or timeout
|
||||
*/
|
||||
clearApproval: () => {
|
||||
set((state) => {
|
||||
const [next, ...rest] = state.queue;
|
||||
return {
|
||||
pendingApproval: next ?? null,
|
||||
queue: rest,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all pending approvals
|
||||
* Used when switching sessions or resetting state
|
||||
*/
|
||||
clearAll: () => {
|
||||
set({
|
||||
pendingApproval: null,
|
||||
queue: [],
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get total count of pending approvals (current + queued)
|
||||
*/
|
||||
getPendingCount: () => {
|
||||
const state = get();
|
||||
return (state.pendingApproval ? 1 : 0) + state.queue.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all pending approvals for a specific session
|
||||
*/
|
||||
getPendingForSession: (sessionId: string) => {
|
||||
const state = get();
|
||||
const results: ApprovalRequest[] = [];
|
||||
|
||||
if (state.pendingApproval?.sessionId === sessionId) {
|
||||
results.push(state.pendingApproval);
|
||||
}
|
||||
|
||||
results.push(...state.queue.filter((req) => req.sessionId === sessionId));
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if there's a pending approval
|
||||
*/
|
||||
hasPendingApproval: () => {
|
||||
return get().pendingApproval !== null;
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user