22 * Shared archive-time worktree cleanup flow.
33 *
44 * The server owns the safety decision (preview + conditional cleanup RPCs);
5- * this module owns the client sequencing shared by web and mobile: prompt
6- * only when the server reports a candidate and a confirmation surface
7- * exists, archive regardless of the answer, run cleanup only after a
8- * confirmed archive, and report cleanup problems without failing the
9- * archive itself.
5+ * this module owns the client sequencing shared by web and mobile: act only
6+ * when the server reports a candidate, optionally confirm based on client
7+ * policy, archive before cleanup, and report cleanup problems without
8+ * failing the archive itself.
109 */
1110import type { WorktreeCleanupStatus } from "@t3tools/contracts" ;
1211
@@ -41,10 +40,14 @@ export type ArchiveWithWorktreeCleanupResult<TArchive, TAbort> =
4140 | { readonly kind : "archived" ; readonly result : TArchive }
4241 | { readonly kind : "aborted" ; readonly result : TAbort } ;
4342
43+ export type WorktreeRemovalPolicy = "confirm" | "remove" ;
44+
4445export async function runArchiveWithWorktreeCleanup < TArchive , TAbort = never > ( input : {
4546 /** Server-authoritative preview; null when ineligible or when the preview failed. */
4647 readonly previewCandidate : ( ) => Promise < ArchiveWorktreeCleanupCandidate | null > ;
47- /** Confirmation surface, or null when none is available (no prompt, no cleanup). */
48+ /** Whether an eligible worktree is confirmed first or removed automatically. */
49+ readonly removalPolicy : WorktreeRemovalPolicy ;
50+ /** Confirmation surface, or null when none is available. */
4851 readonly confirmRemoval :
4952 | ( ( prompt : {
5053 readonly candidate : ArchiveWorktreeCleanupCandidate ;
@@ -60,13 +63,17 @@ export async function runArchiveWithWorktreeCleanup<TArchive, TAbort = never>(in
6063 const candidate = await input . previewCandidate ( ) ;
6164 let shouldCleanup = false ;
6265 let displayWorktreePath : string | null = null ;
63- if ( candidate && input . confirmRemoval ) {
66+ if ( candidate ) {
6467 displayWorktreePath = formatWorktreePathForDisplay ( candidate . worktreePath ) ;
65- const confirmation = await input . confirmRemoval ( { candidate, displayWorktreePath } ) ;
66- if ( confirmation . kind === "aborted" ) {
67- return { kind : "aborted" , result : confirmation . result } ;
68+ if ( input . removalPolicy === "remove" ) {
69+ shouldCleanup = true ;
70+ } else if ( input . confirmRemoval ) {
71+ const confirmation = await input . confirmRemoval ( { candidate, displayWorktreePath } ) ;
72+ if ( confirmation . kind === "aborted" ) {
73+ return { kind : "aborted" , result : confirmation . result } ;
74+ }
75+ shouldCleanup = confirmation . kind === "confirmed" ;
6876 }
69- shouldCleanup = confirmation . kind === "confirmed" ;
7077 }
7178
7279 const archiveResult = await input . archive ( ) ;
0 commit comments