@prestyj/cli 5.20.0 → 5.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,161 @@
1
+ export type GitLayout = {
2
+ worktreeRoot: string;
3
+ gitDir: string;
4
+ /** True when `.git` is a real directory (the primary checkout), false for a linked worktree. */
5
+ isMain: boolean;
6
+ };
7
+ /**
8
+ * Walk up from `startDir` to the nearest `.git`. A `.git` directory means the
9
+ * main worktree; a `.git` *file* (`gitdir: <path>`) means an already-linked
10
+ * worktree. Returns null when no repository encloses `startDir`.
11
+ */
12
+ export declare function gitLayout(startDir: string): Promise<GitLayout | null>;
13
+ /** The enclosing repo's root, but only when `startDir` is inside the MAIN worktree. */
14
+ export declare function findMainWorktreeRoot(startDir: string): Promise<string | null>;
15
+ export interface WorktreeEntry {
16
+ path: string;
17
+ branch: string | null;
18
+ head: string | null;
19
+ isBare: boolean;
20
+ isMain: boolean;
21
+ }
22
+ /**
23
+ * Parse `git worktree list --porcelain`. The first block is always the main
24
+ * worktree. Paths are canonicalised so callers can compare them by string
25
+ * equality (/var vs /private/var aliasing on macOS).
26
+ */
27
+ export declare function listWorktrees(repoDir: string): Promise<WorktreeEntry[]>;
28
+ /** True when `git status --porcelain` reports anything (tracked or untracked). */
29
+ export declare function isWorkingTreeDirty(dir: string): Promise<boolean>;
30
+ /**
31
+ * Normalise arbitrary text into a branch name git will accept. Returns "" when
32
+ * nothing usable survives, so callers can fall back to a generated name.
33
+ */
34
+ export declare function slugifyBranch(input: string): string;
35
+ /** Pure: `<home>/.ezcoder/worktrees/<basename(repoRoot)>`. */
36
+ export declare function worktreesRootFor(repoRoot: string, homeDir?: string): string;
37
+ export interface CreateWorktreeOptions {
38
+ repoDir: string;
39
+ branch?: string;
40
+ baseRef?: string;
41
+ allowDirty?: boolean;
42
+ }
43
+ export interface CreatedWorktree {
44
+ path: string;
45
+ branch: string;
46
+ baseRef: string;
47
+ created: true;
48
+ }
49
+ /**
50
+ * Create a linked worktree on a fresh branch under `worktreesRootFor(mainRoot)`.
51
+ * Refuses to run against a dirty main checkout unless `allowDirty` is set — a
52
+ * half-committed main tree is the fastest way to lose work across worktrees.
53
+ */
54
+ export declare function createWorktree(opts: CreateWorktreeOptions): Promise<CreatedWorktree>;
55
+ /**
56
+ * Pure: is `candidate` inside `root`?
57
+ *
58
+ * `path.relative` rather than `startsWith`: the string form says yes to
59
+ * `/a/worktrees-evil` for root `/a/worktrees`, and on Windows says no to a
60
+ * correct path that differs only in separator or drive-letter case. An empty
61
+ * relative path (candidate IS root) is deliberately NOT contained — removing
62
+ * the container itself is never what a caller means.
63
+ */
64
+ export declare function isInsideWorktreesRoot(root: string, candidate: string): boolean;
65
+ /**
66
+ * The first symlink at or above `dir` (stopping at the filesystem root), or
67
+ * null when the whole chain is real directories.
68
+ *
69
+ * A containment check alone cannot see this: `stat` dereferences every path
70
+ * component, so a symlink at `~/.ezcoder/worktrees` makes every path under it
71
+ * look like an ordinary contained directory while the removal lands in whatever
72
+ * checkout it points at — the user's real repo, most likely. `lstat` sees the
73
+ * link itself. Every destructive path routes through here.
74
+ */
75
+ export declare function redirectedAncestor(dir: string): Promise<string | null>;
76
+ export interface WorktreeStatus {
77
+ path: string;
78
+ branch: string | null;
79
+ /** Ref it forked from; null when unrecorded and no fallback resolved. */
80
+ baseRef: string | null;
81
+ /** Staged, modified and untracked files. Non-zero means unsaved work. */
82
+ dirtyFiles: number;
83
+ /** Commits on `branch` that `baseRef` does not contain. */
84
+ commitsAhead: number;
85
+ /** The branch is fully contained in `baseRef`. */
86
+ merged: boolean;
87
+ /** Another window is working here, so it must not be touched. */
88
+ busy: boolean;
89
+ /** Safe to remove with nothing lost. */
90
+ reclaimable: boolean;
91
+ /** Why not, in the user's words. Empty exactly when `reclaimable`. */
92
+ blockedBy: string[];
93
+ }
94
+ /**
95
+ * Describe one worktree well enough to decide its fate, from the worktree's own
96
+ * directory so a stale main-checkout view cannot mislead.
97
+ *
98
+ * Unknowns always count AGAINST reclaiming: a git call that fails leaves the
99
+ * entry blocked rather than deleted. The cost of a wrong "keep" is a stale
100
+ * folder; the cost of a wrong "delete" is lost work.
101
+ */
102
+ export declare function worktreeStatus(mainRoot: string, entry: WorktreeEntry, busyPaths?: readonly string[]): Promise<WorktreeStatus>;
103
+ /** Status for every linked worktree of `repoDir`'s repo, main checkout excluded. */
104
+ export declare function worktreeStatuses(repoDir: string, busyPaths?: readonly string[]): Promise<WorktreeStatus[]>;
105
+ /** Worktrees that can be removed right now with nothing lost. */
106
+ export declare function reclaimableWorktrees(repoDir: string, busyPaths?: readonly string[]): Promise<WorktreeStatus[]>;
107
+ export interface WorktreeRelease {
108
+ /** Something was at the path when the release started. */
109
+ existed: boolean;
110
+ /** The path is free now — a `worktree add` over it would succeed. */
111
+ freed: boolean;
112
+ /** The branch is gone too. */
113
+ branchDeleted: boolean;
114
+ /** Why it is not free. Set exactly when `existed && !freed`. */
115
+ reason?: string;
116
+ }
117
+ /**
118
+ * Free a worktree's path AND its branch. Never throws: cleanup runs on window
119
+ * close and on daemon startup, where an exception would surface as a crash in
120
+ * an unrelated flow. Everything it could not do comes back in the result.
121
+ *
122
+ * The order below is load-bearing and `prune` is not optional. `worktree
123
+ * remove` needs the directory to be there; a user reclaiming disk with
124
+ * `rm -rf ~/.ezcoder/worktrees` leaves the tree REGISTERED BUT MISSING, and git
125
+ * then refuses both of the things the next run needs:
126
+ *
127
+ * $ git worktree add <path> <branch>
128
+ * fatal: '<path>' is a missing but already registered worktree;
129
+ * use 'add -f' to override, or 'prune' or 'remove' to clear
130
+ *
131
+ * and `git branch -d <branch>`, because the branch counts as checked out in
132
+ * that phantom. `git worktree prune` is the only thing that clears the
133
+ * registration, and it is a no-op when nothing is stale — so it runs
134
+ * unconditionally, and BEFORE the branch delete that depends on it.
135
+ */
136
+ export declare function removeWorktree(opts: {
137
+ repoDir: string;
138
+ worktreePath: string;
139
+ /** Remove even with uncommitted or unmerged work. Caller must have confirmed. */
140
+ force?: boolean;
141
+ /** Delete the branch too. Default true. */
142
+ deleteBranch?: boolean;
143
+ }): Promise<WorktreeRelease>;
144
+ export interface SweepResult {
145
+ removed: WorktreeStatus[];
146
+ kept: {
147
+ status: WorktreeStatus;
148
+ reason: string;
149
+ }[];
150
+ }
151
+ /**
152
+ * Remove every worktree of `repoDir`'s repo that is provably free of work.
153
+ *
154
+ * The automatic entry point: window close and daemon startup. It never forces,
155
+ * so anything holding uncommitted or unmerged work is reported as kept, with
156
+ * the reason, and waits for a human. Failures are collected rather than thrown
157
+ * — one wedged worktree must not stop the rest of the sweep.
158
+ */
159
+ export declare function sweepWorktrees(repoDir: string, busyPaths?: readonly string[]): Promise<SweepResult>;
160
+ /** True when the repo already has at least one linked worktree registered. */
161
+ export declare function repoHasLinkedWorktrees(mainRoot: string): Promise<boolean>;