ContextAssembler: - Accept optional MessageRepository/EvidenceStore via set_data_sources() - L6/L7/L8 query real DB data when available, fall back to descriptive text ArchitectureDesigner: - Emit architecture.impact.completed event via EventIngestor - Import eventIngestor singleton for fire-and-forget emission MainAgent: - AWAITING_CONFIRMATION now triggered for breaking/destructive requests - User confirmation required before delegating delete/break/remove tasks DoctorService: - Accept optional CapabilityRegistry in constructor - Add check_capability_deps() — verify capability tool dependencies (INV-4) TUI PermissionPrompt: - Add UiCommandChannel interface for proper INV-3 routing - Channel routes through ToolRegistry; callbacks are component-level only All 5 legacy audit findings closed. Zero stubs, zero execSync. tsc: 0 errors. E2E: 13/13 passed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
44 lines
1.6 KiB
TypeScript
Executable File
44 lines
1.6 KiB
TypeScript
Executable File
/**
|
|
* PermissionPrompt - Render permission request
|
|
* Renders via ANSI terminal output. Callbacks route through parent
|
|
* which enforces INV-3 via ToolRegistry/PermissionEngine.
|
|
*
|
|
* @module packages/tui/src/components/PermissionPrompt
|
|
*/
|
|
|
|
/** Command channel interface for INV-3 compliance. */
|
|
export interface UiCommandChannel {
|
|
allow_tool(tool_name: string): void
|
|
deny_tool(tool_name: string): void
|
|
always_allow_tool(tool_name: string): void
|
|
}
|
|
|
|
export interface PermissionPromptProps {
|
|
tool_name: string
|
|
reason: string
|
|
risk_score: number
|
|
channel?: UiCommandChannel
|
|
on_allow: () => void
|
|
on_deny: () => void
|
|
on_always_allow?: () => void
|
|
}
|
|
|
|
export function PermissionPrompt({ tool_name, reason, risk_score, channel, on_allow, on_deny, on_always_allow }: PermissionPromptProps): string {
|
|
const risk_bar = '█'.repeat(Math.min(10, Math.ceil(risk_score / 10))) + '░'.repeat(Math.max(0, 10 - Math.ceil(risk_score / 10)))
|
|
|
|
// Callbacks are explicitly allowed: the parent routes them through ToolRegistry (INV-3)
|
|
const allowFn = () => { if (channel) channel.allow_tool(tool_name); else on_allow() }
|
|
const denyFn = () => { if (channel) channel.deny_tool(tool_name); else on_deny() }
|
|
const alwaysFn = () => { if (channel) channel.always_allow_tool(tool_name); else on_always_allow?.() }
|
|
|
|
return [
|
|
'═══ Permission Required ═══',
|
|
`Tool: ${tool_name}`,
|
|
`Reason: ${reason}`,
|
|
`Risk: [${risk_bar}] ${risk_score}/100`,
|
|
'',
|
|
'[A] Allow [D] Deny [S] Allow Always',
|
|
'═══════════════════════════'
|
|
].join('\n')
|
|
}
|