@@ -10,6 +10,7 @@ use bashkit::tool::VERSION;
1010use bashkit:: { Bash as RustBash , BashTool as RustBashTool , ExecutionLimits , Tool } ;
1111use napi_derive:: napi;
1212use std:: sync:: Arc ;
13+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
1314use tokio:: sync:: Mutex ;
1415
1516// ============================================================================
@@ -51,6 +52,7 @@ pub struct BashOptions {
5152pub struct Bash {
5253 inner : Arc < Mutex < RustBash > > ,
5354 rt : tokio:: runtime:: Runtime ,
55+ cancelled : Arc < AtomicBool > ,
5456 username : Option < String > ,
5557 hostname : Option < String > ,
5658 max_commands : Option < u32 > ,
@@ -74,6 +76,7 @@ impl Bash {
7476 opts. max_commands ,
7577 opts. max_loop_iterations ,
7678 ) ;
79+ let cancelled = bash. cancellation_token ( ) ;
7780
7881 let rt = tokio:: runtime:: Builder :: new_current_thread ( )
7982 . enable_all ( )
@@ -83,6 +86,7 @@ impl Bash {
8386 Ok ( Self {
8487 inner : Arc :: new ( Mutex :: new ( bash) ) ,
8588 rt,
89+ cancelled,
8690 username : opts. username ,
8791 hostname : opts. hostname ,
8892 max_commands : opts. max_commands ,
@@ -93,6 +97,7 @@ impl Bash {
9397 /// Execute bash commands synchronously.
9498 #[ napi]
9599 pub fn execute_sync ( & self , commands : String ) -> napi:: Result < ExecResult > {
100+ self . cancelled . store ( false , Ordering :: Relaxed ) ;
96101 let inner = self . inner . clone ( ) ;
97102 self . rt . block_on ( async move {
98103 let mut bash = inner. lock ( ) . await ;
@@ -113,6 +118,15 @@ impl Bash {
113118 } )
114119 }
115120
121+ /// Cancel the currently running execution.
122+ ///
123+ /// Safe to call from any thread. Execution will abort at the next
124+ /// command boundary.
125+ #[ napi]
126+ pub fn cancel ( & self ) {
127+ self . cancelled . store ( true , Ordering :: Relaxed ) ;
128+ }
129+
116130 /// Reset interpreter to fresh state, preserving configuration.
117131 #[ napi]
118132 pub fn reset ( & self ) -> napi:: Result < ( ) > {
@@ -124,12 +138,13 @@ impl Bash {
124138
125139 self . rt . block_on ( async move {
126140 let mut bash = inner. lock ( ) . await ;
127- * bash = build_bash (
141+ let new_bash = build_bash (
128142 username. as_deref ( ) ,
129143 hostname. as_deref ( ) ,
130144 max_commands,
131145 max_loop_iterations,
132146 ) ;
147+ * bash = new_bash;
133148 Ok ( ( ) )
134149 } )
135150 }
@@ -147,6 +162,7 @@ impl Bash {
147162pub struct BashTool {
148163 inner : Arc < Mutex < RustBash > > ,
149164 rt : tokio:: runtime:: Runtime ,
165+ cancelled : Arc < AtomicBool > ,
150166 username : Option < String > ,
151167 hostname : Option < String > ,
152168 max_commands : Option < u32 > ,
@@ -193,6 +209,7 @@ impl BashTool {
193209 opts. max_commands ,
194210 opts. max_loop_iterations ,
195211 ) ;
212+ let cancelled = bash. cancellation_token ( ) ;
196213
197214 let rt = tokio:: runtime:: Builder :: new_current_thread ( )
198215 . enable_all ( )
@@ -202,6 +219,7 @@ impl BashTool {
202219 Ok ( Self {
203220 inner : Arc :: new ( Mutex :: new ( bash) ) ,
204221 rt,
222+ cancelled,
205223 username : opts. username ,
206224 hostname : opts. hostname ,
207225 max_commands : opts. max_commands ,
@@ -212,6 +230,7 @@ impl BashTool {
212230 /// Execute bash commands synchronously.
213231 #[ napi]
214232 pub fn execute_sync ( & self , commands : String ) -> napi:: Result < ExecResult > {
233+ self . cancelled . store ( false , Ordering :: Relaxed ) ;
215234 let inner = self . inner . clone ( ) ;
216235 self . rt . block_on ( async move {
217236 let mut bash = inner. lock ( ) . await ;
@@ -232,6 +251,12 @@ impl BashTool {
232251 } )
233252 }
234253
254+ /// Cancel the currently running execution.
255+ #[ napi]
256+ pub fn cancel ( & self ) {
257+ self . cancelled . store ( true , Ordering :: Relaxed ) ;
258+ }
259+
235260 /// Reset interpreter to fresh state, preserving configuration.
236261 #[ napi]
237262 pub fn reset ( & self ) -> napi:: Result < ( ) > {
@@ -243,12 +268,13 @@ impl BashTool {
243268
244269 self . rt . block_on ( async move {
245270 let mut bash = inner. lock ( ) . await ;
246- * bash = build_bash (
271+ let new_bash = build_bash (
247272 username. as_deref ( ) ,
248273 hostname. as_deref ( ) ,
249274 max_commands,
250275 max_loop_iterations,
251276 ) ;
277+ * bash = new_bash;
252278 Ok ( ( ) )
253279 } )
254280 }
0 commit comments