1- import { For , Show , createEffect , createSignal , lazy } from "solid-js" ;
1+ import { For , Show , createEffect , createSignal } from "solid-js" ;
22import { appStore } from "../../stores/app-store" ;
33import * as ipc from "../../ipc" ;
44import { Markdown } from "./Markdown" ;
55import { ToolUseCard } from "./ToolUseCard" ;
66import { ThinkingBlock } from "./ThinkingBlock" ;
77import { PrDashboard } from "../github/PrDashboard" ;
8+ import { McpPanel } from "../sidebar/McpPanel" ;
9+ import { ThemeSelector } from "../settings/ThemeSelector" ;
810import type { ContentBlock } from "../../types" ;
911
10- const McpPanel = lazy ( ( ) => import ( "../sidebar/McpPanel" ) . then ( m => ( { default : m . McpPanel } ) ) ) ;
11- const ThemeSelector = lazy ( ( ) => import ( "../settings/ThemeSelector" ) . then ( m => ( { default : m . ThemeSelector } ) ) ) ;
12-
1312export function ChatArea ( ) {
1413 const { store, approveRequest, denyRequest } = appStore ;
1514 let scrollRef : HTMLDivElement | undefined ;
@@ -265,22 +264,55 @@ export function ChatArea() {
265264 </ For >
266265
267266 < For each = { store . pendingApprovals . filter ( ( a ) => a . threadId === store . activeTab ) } >
268- { ( approval ) => (
269- < div class = "approval-card" >
270- < div class = "approval-header" >
271- < svg width = "14" height = "14" viewBox = "0 0 24 24" fill = "none" stroke = "var(--amber)" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
272- < path d = "M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
273- < line x1 = "12" y1 = "9" x2 = "12" y2 = "13" /> < line x1 = "12" y1 = "17" x2 = "12.01" y2 = "17" />
274- </ svg >
275- < span class = "approval-title" > Permission Required</ span >
276- </ div >
277- < pre class = "approval-desc" > { approval . description } </ pre >
278- < div class = "approval-actions" >
279- < button class = "deny-btn" onClick = { ( ) => denyRequest ( approval ) } > Deny</ button >
280- < button class = "approve-btn" onClick = { ( ) => approveRequest ( approval ) } > Approve</ button >
267+ { ( approval ) => {
268+ const toolName = ( ) => approval . description . split ( ":" ) [ 0 ] ?. trim ( ) || "tool" ;
269+
270+ function handleApproveAndRemember ( ) {
271+ // Store an allow rule for this tool
272+ const rule = `${ toolName ( ) } ` ;
273+ ipc . getSetting ( "allowed_tools" ) . then ( ( current ) => {
274+ const rules = current ? current . split ( "," ) : [ ] ;
275+ if ( ! rules . includes ( rule ) ) {
276+ rules . push ( rule ) ;
277+ ipc . setSetting ( "allowed_tools" , rules . join ( "," ) ) ;
278+ }
279+ } ) . catch ( ( ) => { } ) ;
280+ approveRequest ( approval ) ;
281+ }
282+
283+ function handleBypassSession ( ) {
284+ // Approve this request and set session to bypass
285+ ipc . setSetting ( "permission_mode" , "bypassPermissions" ) . catch ( ( ) => { } ) ;
286+ // Approve all pending approvals for this thread
287+ store . pendingApprovals
288+ . filter ( ( a ) => a . threadId === approval . threadId )
289+ . forEach ( ( a ) => approveRequest ( a ) ) ;
290+ }
291+
292+ return (
293+ < div class = "approval-card" >
294+ < div class = "approval-header" >
295+ < svg width = "14" height = "14" viewBox = "0 0 24 24" fill = "none" stroke = "var(--amber)" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
296+ < path d = "M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
297+ < line x1 = "12" y1 = "9" x2 = "12" y2 = "13" /> < line x1 = "12" y1 = "17" x2 = "12.01" y2 = "17" />
298+ </ svg >
299+ < span class = "approval-title" > Permission Required</ span >
300+ < span class = "approval-tool" > { toolName ( ) } </ span >
301+ </ div >
302+ < pre class = "approval-desc" > { approval . description } </ pre >
303+ < div class = "approval-actions" >
304+ < button class = "deny-btn" onClick = { ( ) => denyRequest ( approval ) } > Deny</ button >
305+ < button class = "approve-btn" onClick = { ( ) => approveRequest ( approval ) } > Approve</ button >
306+ < button class = "approve-remember-btn" onClick = { handleApproveAndRemember } title = { `Always allow ${ toolName ( ) } ` } >
307+ Approve & Remember
308+ </ button >
309+ < button class = "bypass-btn" onClick = { handleBypassSession } title = "Auto-approve everything for this session" >
310+ Bypass All
311+ </ button >
312+ </ div >
281313 </ div >
282- </ div >
283- ) }
314+ ) ;
315+ } }
284316 </ For >
285317
286318 < Show when = { isGenerating ( ) && messages ( ) . length === 0 } >
@@ -868,11 +900,20 @@ if (!document.getElementById("chat-styles")) {
868900 overflow-y: auto;
869901 margin: 0 0 12px;
870902 }
871- .approval-actions { display: flex; gap: 8px; justify-content: flex-end; }
872- .approve-btn, .deny-btn {
873- padding: 7px 16px;
903+ .approval-tool {
904+ font-size: 11px;
905+ font-family: var(--font-mono);
906+ color: var(--text-tertiary);
907+ margin-left: auto;
908+ padding: 1px 6px;
909+ background: var(--bg-accent);
910+ border-radius: var(--radius-pill);
911+ }
912+ .approval-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
913+ .approve-btn, .deny-btn, .approve-remember-btn, .bypass-btn {
914+ padding: 6px 12px;
874915 border-radius: var(--radius-sm);
875- font-size: 12px ;
916+ font-size: 11px ;
876917 font-weight: 600;
877918 transition: all 0.12s;
878919 }
@@ -881,6 +922,24 @@ if (!document.getElementById("chat-styles")) {
881922 color: #fff;
882923 }
883924 .approve-btn:hover { filter: brightness(1.1); transform: translateY(-1px); }
925+ .approve-remember-btn {
926+ background: rgba(76, 214, 148, 0.12);
927+ border: 1px solid rgba(76, 214, 148, 0.25);
928+ color: var(--green);
929+ }
930+ .approve-remember-btn:hover {
931+ background: rgba(76, 214, 148, 0.2);
932+ border-color: rgba(76, 214, 148, 0.4);
933+ }
934+ .bypass-btn {
935+ background: rgba(240, 184, 64, 0.1);
936+ border: 1px solid rgba(240, 184, 64, 0.2);
937+ color: var(--amber);
938+ }
939+ .bypass-btn:hover {
940+ background: rgba(240, 184, 64, 0.18);
941+ border-color: rgba(240, 184, 64, 0.35);
942+ }
884943 .deny-btn {
885944 background: var(--bg-muted);
886945 border: 1px solid var(--border);
0 commit comments