@@ -72,6 +72,7 @@ import { speakText, stopSpeaking } from "@/lib/tts";
7272import { computeLineDiff } from "@/lib/diff" ;
7373import { useToast } from "@/components/toast" ;
7474import { isTransientError } from "@/lib/transient-errors" ;
75+ import { canAlwaysAllow } from "@/lib/tool-approval" ;
7576import {
7677 COMPACTION_BUDGET_TOKENS ,
7778 COMPACTION_KEEP_RECENT ,
@@ -116,36 +117,12 @@ const RAG_THRESHOLD_CHARS = 20_000;
116117// the most recent window renders by default, with older ones revealed a
117118// window at a time on request rather than all at once.
118119const RENDER_WINDOW_SIZE = 60 ;
119- // Read-only tools are safe to let the model call repeatedly without a fresh
120- // click each time — write_file and run_command always require explicit
121- // per-call approval since they have real, potentially irreversible effects.
120+
122121interface PlanStep {
123122 text : string ;
124123 done : boolean ;
125124}
126125
127- const READ_ONLY_TOOLS = new Set ( [
128- "read_file" ,
129- "find_files" ,
130- "file_info" ,
131- "list_dir" ,
132- "search_files" ,
133- "git_status" ,
134- "git_diff" ,
135- "git_log" ,
136- "web_search" ,
137- "fetch_url" ,
138- "read_notes" ,
139- "github_list_repositories" ,
140- "github_repository_tree" ,
141- "github_read_file" ,
142- "get_background_output" ,
143- "list_background_commands" ,
144- "capture_page_screenshot" ,
145- "find_symbol_references" ,
146- "read_terminal_output" ,
147- ] ) ;
148-
149126// Vision models can already reason over any attached image — these just save
150127// re-typing a good prompt for the common "I attached a diagram/wireframe"
151128// case. Selecting one fills the composer; the user can still edit before sending.
@@ -2233,7 +2210,7 @@ export default function Chat() {
22332210 >
22342211 < X className = "size-3.5" /> { t . deny }
22352212 </ Button >
2236- { READ_ONLY_TOOLS . has ( call . name ) && (
2213+ { canAlwaysAllow ( call . name ) && (
22372214 < Button
22382215 size = "sm"
22392216 variant = "ghost"
0 commit comments