@@ -22,6 +22,10 @@ function stubLifecycleService(calls: Array<{ method: string; value: unknown }>)
2222 async mergeWorktree ( branch : string ) : Promise < void > {
2323 calls . push ( { method : "mergeWorktree" , value : branch } ) ;
2424 } ,
25+ async pruneWorktrees ( ) : Promise < { removedBranches : string [ ] } > {
26+ calls . push ( { method : "pruneWorktrees" , value : null } ) ;
27+ return { removedBranches : [ "feature/search" , "feature/api" ] } ;
28+ } ,
2529 } ;
2630}
2731
@@ -183,6 +187,66 @@ describe("runWorktreeCommand", () => {
183187 expect ( stdout ) . toEqual ( [ "Merged feature/search into develop" ] ) ;
184188 } ) ;
185189
190+ it ( "prunes all worktrees after confirmation" , async ( ) => {
191+ const { runtime, calls } = makeRuntime ( ) ;
192+ runtime . git = stubGit ( [
193+ { path : "/repo" , branch : "main" , bare : false } ,
194+ { path : "/repo/.worktrees/feature-search" , branch : "feature/search" , bare : false } ,
195+ { path : "/repo/.worktrees/feature-api" , branch : "feature/api" , bare : false } ,
196+ ] ) ;
197+ const stdout : string [ ] = [ ] ;
198+ const confirmCalls : number [ ] = [ ] ;
199+
200+ const exitCode = await runWorktreeCommand (
201+ {
202+ command : "prune" ,
203+ args : [ ] ,
204+ projectDir : "/repo" ,
205+ port : 5111 ,
206+ } ,
207+ {
208+ createRuntime : ( ) => runtime ,
209+ confirmPrune : async ( count ) => {
210+ confirmCalls . push ( count ) ;
211+ return true ;
212+ } ,
213+ stdout : ( message ) => stdout . push ( message ) ,
214+ } ,
215+ ) ;
216+
217+ expect ( exitCode ) . toBe ( 0 ) ;
218+ expect ( confirmCalls ) . toEqual ( [ 2 ] ) ;
219+ expect ( calls ) . toEqual ( [ { method : "pruneWorktrees" , value : null } ] ) ;
220+ expect ( stdout ) . toEqual ( [ "Pruned 2 worktrees: feature/search, feature/api" ] ) ;
221+ } ) ;
222+
223+ it ( "aborts prune when confirmation is declined" , async ( ) => {
224+ const { runtime, calls } = makeRuntime ( ) ;
225+ runtime . git = stubGit ( [
226+ { path : "/repo" , branch : "main" , bare : false } ,
227+ { path : "/repo/.worktrees/feature-search" , branch : "feature/search" , bare : false } ,
228+ ] ) ;
229+ const stdout : string [ ] = [ ] ;
230+
231+ const exitCode = await runWorktreeCommand (
232+ {
233+ command : "prune" ,
234+ args : [ ] ,
235+ projectDir : "/repo" ,
236+ port : 5111 ,
237+ } ,
238+ {
239+ createRuntime : ( ) => runtime ,
240+ confirmPrune : async ( ) => false ,
241+ stdout : ( message ) => stdout . push ( message ) ,
242+ } ,
243+ ) ;
244+
245+ expect ( exitCode ) . toBe ( 0 ) ;
246+ expect ( calls ) . toEqual ( [ ] ) ;
247+ expect ( stdout ) . toEqual ( [ "Aborted." ] ) ;
248+ } ) ;
249+
186250 it ( "returns a failing exit code when lifecycle execution fails" , async ( ) => {
187251 const stdout : string [ ] = [ ] ;
188252 const stderr : string [ ] = [ ] ;
@@ -220,6 +284,9 @@ describe("runWorktreeCommand", () => {
220284 async mergeWorktree ( ) : Promise < void > {
221285 throw new Error ( "not used" ) ;
222286 } ,
287+ async pruneWorktrees ( ) : Promise < { removedBranches : string [ ] } > {
288+ throw new Error ( "not used" ) ;
289+ } ,
223290 } ,
224291 } ) ,
225292 stdout : ( message ) => stdout . push ( message ) ,
@@ -329,4 +396,24 @@ describe("runWorktreeCommand", () => {
329396 expect ( createRuntimeCalled ) . toBe ( false ) ;
330397 expect ( stdout ) . toEqual ( [ "Usage:\n webmux list" ] ) ;
331398 } ) ;
399+
400+ it ( "prints prune help without creating a runtime" , async ( ) => {
401+ let createRuntimeCalled = false ;
402+ const stdout : string [ ] = [ ] ;
403+
404+ const exitCode = await runWorktreeCommand (
405+ { command : "prune" , args : [ "--help" ] , projectDir : "/repo" , port : 5111 } ,
406+ {
407+ createRuntime : ( ) => {
408+ createRuntimeCalled = true ;
409+ throw new Error ( "unexpected" ) ;
410+ } ,
411+ stdout : ( msg ) => stdout . push ( msg ) ,
412+ } ,
413+ ) ;
414+
415+ expect ( exitCode ) . toBe ( 0 ) ;
416+ expect ( createRuntimeCalled ) . toBe ( false ) ;
417+ expect ( stdout ) . toEqual ( [ "Usage:\n webmux prune" ] ) ;
418+ } ) ;
332419} ) ;
0 commit comments