@@ -256,11 +256,33 @@ function pathLikeTokens(command: string): string[] {
256256 return out ;
257257}
258258
259+ // AgentId-addressed fleet continuation verbs (see the CL-9362 note on
260+ // callTargetsRestricted below).
261+ const AGENT_ID_TARGETED_FLEET_TOOLS = new Set ( [
262+ "close_agent" ,
263+ "interrupt_agent" ,
264+ "send_input" ,
265+ ] ) ;
266+
259267export function callTargetsRestricted (
260268 call : ToolCall ,
261269 isRestricted : ( path : string , isWrite : boolean ) => boolean ,
262270) : boolean {
263271 const name = canonicalToolName ( call . name ) ;
272+ // Fleet verbs that address workers by opaque agent id (`target`), never by
273+ // path (CL-9362). There is nothing path-shaped here for isRestricted to
274+ // judge, so agentId-to-worktree resolution deliberately does not live in
275+ // this function and the gate's auto-allow `!restricted` guard stays
276+ // vacuous for these calls — intentionally, not by oversight. Path
277+ // restriction is enforced where paths are actually touched: inside the
278+ // target worker, whose own gate binds restriction judgments to its process
279+ // cwd (bindRestrictedToProcessCwd in gate.ts). Resolving ids to worktrees
280+ // here would duplicate that enforcement at a layer with no session access,
281+ // so these calls always report "not restricted", exactly like
282+ // spawn_agent/wait_agents. (The full fleet verb list lives in
283+ // subagent/authority.ts as FLEET_VERBS; only the agentId-addressed
284+ // continuation verbs need naming here.)
285+ if ( AGENT_ID_TARGETED_FLEET_TOOLS . has ( name ) ) return false ;
264286 if ( name === "run_shell" )
265287 return commandTargetsRestricted ( stringArg ( call , "command" ) , isRestricted ) ;
266288 if ( name === "apply_patch" ) {
0 commit comments