@yoavsh/treekeeper 0.0.0-stage → 0.1.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.
Files changed (166) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +237 -2
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +165 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/archive.d.ts +3 -0
  9. package/dist/commands/archive.d.ts.map +1 -0
  10. package/dist/commands/archive.js +55 -0
  11. package/dist/commands/archive.js.map +1 -0
  12. package/dist/commands/config.d.ts +2 -0
  13. package/dist/commands/config.d.ts.map +1 -0
  14. package/dist/commands/config.js +54 -0
  15. package/dist/commands/config.js.map +1 -0
  16. package/dist/commands/context.d.ts +34 -0
  17. package/dist/commands/context.d.ts.map +1 -0
  18. package/dist/commands/context.js +53 -0
  19. package/dist/commands/context.js.map +1 -0
  20. package/dist/commands/daemon.d.ts +3 -0
  21. package/dist/commands/daemon.d.ts.map +1 -0
  22. package/dist/commands/daemon.js +81 -0
  23. package/dist/commands/daemon.js.map +1 -0
  24. package/dist/commands/doctor.d.ts +3 -0
  25. package/dist/commands/doctor.d.ts.map +1 -0
  26. package/dist/commands/doctor.js +119 -0
  27. package/dist/commands/doctor.js.map +1 -0
  28. package/dist/commands/gc.d.ts +3 -0
  29. package/dist/commands/gc.d.ts.map +1 -0
  30. package/dist/commands/gc.js +98 -0
  31. package/dist/commands/gc.js.map +1 -0
  32. package/dist/commands/status.d.ts +4 -0
  33. package/dist/commands/status.d.ts.map +1 -0
  34. package/dist/commands/status.js +52 -0
  35. package/dist/commands/status.js.map +1 -0
  36. package/dist/commands/watch.d.ts +10 -0
  37. package/dist/commands/watch.d.ts.map +1 -0
  38. package/dist/commands/watch.js +41 -0
  39. package/dist/commands/watch.js.map +1 -0
  40. package/dist/core/apply.d.ts +47 -0
  41. package/dist/core/apply.d.ts.map +1 -0
  42. package/dist/core/apply.js +223 -0
  43. package/dist/core/apply.js.map +1 -0
  44. package/dist/core/archive.d.ts +69 -0
  45. package/dist/core/archive.d.ts.map +1 -0
  46. package/dist/core/archive.js +202 -0
  47. package/dist/core/archive.js.map +1 -0
  48. package/dist/core/config.d.ts +69 -0
  49. package/dist/core/config.d.ts.map +1 -0
  50. package/dist/core/config.js +261 -0
  51. package/dist/core/config.js.map +1 -0
  52. package/dist/core/decide.d.ts +102 -0
  53. package/dist/core/decide.d.ts.map +1 -0
  54. package/dist/core/decide.js +148 -0
  55. package/dist/core/decide.js.map +1 -0
  56. package/dist/core/forge.d.ts +39 -0
  57. package/dist/core/forge.d.ts.map +1 -0
  58. package/dist/core/forge.js +190 -0
  59. package/dist/core/forge.js.map +1 -0
  60. package/dist/core/git.d.ts +63 -0
  61. package/dist/core/git.d.ts.map +1 -0
  62. package/dist/core/git.js +194 -0
  63. package/dist/core/git.js.map +1 -0
  64. package/dist/core/plan.d.ts +75 -0
  65. package/dist/core/plan.d.ts.map +1 -0
  66. package/dist/core/plan.js +288 -0
  67. package/dist/core/plan.js.map +1 -0
  68. package/dist/core/render.d.ts +14 -0
  69. package/dist/core/render.d.ts.map +1 -0
  70. package/dist/core/render.js +128 -0
  71. package/dist/core/render.js.map +1 -0
  72. package/dist/core/scan.d.ts +22 -0
  73. package/dist/core/scan.d.ts.map +1 -0
  74. package/dist/core/scan.js +99 -0
  75. package/dist/core/scan.js.map +1 -0
  76. package/dist/core/sessions.d.ts +37 -0
  77. package/dist/core/sessions.d.ts.map +1 -0
  78. package/dist/core/sessions.js +300 -0
  79. package/dist/core/sessions.js.map +1 -0
  80. package/dist/core/size.d.ts +3 -0
  81. package/dist/core/size.d.ts.map +1 -0
  82. package/dist/core/size.js +11 -0
  83. package/dist/core/size.js.map +1 -0
  84. package/dist/daemon/lock.d.ts +10 -0
  85. package/dist/daemon/lock.d.ts.map +1 -0
  86. package/dist/daemon/lock.js +64 -0
  87. package/dist/daemon/lock.js.map +1 -0
  88. package/dist/daemon/service.d.ts +34 -0
  89. package/dist/daemon/service.d.ts.map +1 -0
  90. package/dist/daemon/service.js +257 -0
  91. package/dist/daemon/service.js.map +1 -0
  92. package/dist/daemon/state.d.ts +19 -0
  93. package/dist/daemon/state.d.ts.map +1 -0
  94. package/dist/daemon/state.js +32 -0
  95. package/dist/daemon/state.js.map +1 -0
  96. package/dist/index.d.ts +26 -0
  97. package/dist/index.d.ts.map +1 -0
  98. package/dist/index.js +19 -0
  99. package/dist/index.js.map +1 -0
  100. package/dist/util/bytes.d.ts +4 -0
  101. package/dist/util/bytes.d.ts.map +1 -0
  102. package/dist/util/bytes.js +14 -0
  103. package/dist/util/bytes.js.map +1 -0
  104. package/dist/util/color.d.ts +16 -0
  105. package/dist/util/color.d.ts.map +1 -0
  106. package/dist/util/color.js +32 -0
  107. package/dist/util/color.js.map +1 -0
  108. package/dist/util/exec.d.ts +27 -0
  109. package/dist/util/exec.d.ts.map +1 -0
  110. package/dist/util/exec.js +57 -0
  111. package/dist/util/exec.js.map +1 -0
  112. package/dist/util/log.d.ts +29 -0
  113. package/dist/util/log.d.ts.map +1 -0
  114. package/dist/util/log.js +72 -0
  115. package/dist/util/log.js.map +1 -0
  116. package/dist/util/paths.d.ts +18 -0
  117. package/dist/util/paths.d.ts.map +1 -0
  118. package/dist/util/paths.js +87 -0
  119. package/dist/util/paths.js.map +1 -0
  120. package/dist/util/prompt.d.ts +3 -0
  121. package/dist/util/prompt.d.ts.map +1 -0
  122. package/dist/util/prompt.js +15 -0
  123. package/dist/util/prompt.js.map +1 -0
  124. package/dist/util/redact.d.ts +15 -0
  125. package/dist/util/redact.d.ts.map +1 -0
  126. package/dist/util/redact.js +44 -0
  127. package/dist/util/redact.js.map +1 -0
  128. package/dist/util/time.d.ts +13 -0
  129. package/dist/util/time.d.ts.map +1 -0
  130. package/dist/util/time.js +77 -0
  131. package/dist/util/time.js.map +1 -0
  132. package/docs/integrations.md +128 -0
  133. package/docs/safety.md +62 -0
  134. package/package.json +69 -4
  135. package/src/cli.ts +175 -0
  136. package/src/commands/archive.ts +72 -0
  137. package/src/commands/config.ts +57 -0
  138. package/src/commands/context.ts +86 -0
  139. package/src/commands/daemon.ts +86 -0
  140. package/src/commands/doctor.ts +131 -0
  141. package/src/commands/gc.ts +108 -0
  142. package/src/commands/status.ts +68 -0
  143. package/src/commands/watch.ts +48 -0
  144. package/src/core/apply.ts +276 -0
  145. package/src/core/archive.ts +269 -0
  146. package/src/core/config.ts +339 -0
  147. package/src/core/decide.ts +230 -0
  148. package/src/core/forge.ts +243 -0
  149. package/src/core/git.ts +254 -0
  150. package/src/core/plan.ts +431 -0
  151. package/src/core/render.ts +168 -0
  152. package/src/core/scan.ts +105 -0
  153. package/src/core/sessions.ts +339 -0
  154. package/src/core/size.ts +10 -0
  155. package/src/daemon/lock.ts +65 -0
  156. package/src/daemon/service.ts +321 -0
  157. package/src/daemon/state.ts +49 -0
  158. package/src/index.ts +36 -0
  159. package/src/util/bytes.ts +11 -0
  160. package/src/util/color.ts +33 -0
  161. package/src/util/exec.ts +80 -0
  162. package/src/util/log.ts +88 -0
  163. package/src/util/paths.ts +84 -0
  164. package/src/util/prompt.ts +13 -0
  165. package/src/util/redact.ts +43 -0
  166. package/src/util/time.ts +75 -0
@@ -0,0 +1,190 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { have, run } from "../util/exec.js";
5
+ import { treekeeperHome } from "../util/paths.js";
6
+ import { redactRemote } from "../util/redact.js";
7
+ import { parseDuration } from "../util/time.js";
8
+ import { originUrl } from "./git.js";
9
+ export function createForge(opts) {
10
+ // Not a problem worth warning about: the repo header already shows that a
11
+ // sweep ran without pull-request data.
12
+ if (opts.kind === "none")
13
+ return new NullForge(null);
14
+ return new GitHubForge(opts);
15
+ }
16
+ class NullForge {
17
+ kind = "none";
18
+ unavailableReason;
19
+ constructor(reason) {
20
+ this.unavailableReason = reason;
21
+ }
22
+ async lookup() {
23
+ return null;
24
+ }
25
+ }
26
+ class GitHubForge {
27
+ opts;
28
+ kind = "github";
29
+ unavailableReason = null;
30
+ ttlMs;
31
+ memo = new Map();
32
+ ghChecked = false;
33
+ constructor(opts) {
34
+ this.opts = opts;
35
+ this.ttlMs = parseDuration(opts.cacheTtl);
36
+ }
37
+ async lookup(repo) {
38
+ if (this.memo.has(repo))
39
+ return this.memo.get(repo);
40
+ const result = await this.fetch(repo);
41
+ this.memo.set(repo, result);
42
+ return result;
43
+ }
44
+ async fetch(repo) {
45
+ const remote = await originUrl(repo);
46
+ if (!remote) {
47
+ this.opts.logger?.debug(`forge: ${repo} has no origin remote`);
48
+ return null;
49
+ }
50
+ if (!isGitHubRemote(remote)) {
51
+ this.opts.logger?.debug(`forge: ${redactRemote(remote)} is not a github remote`);
52
+ return null;
53
+ }
54
+ const cachePath = join(treekeeperHome(), "cache", `gh-${hash(remote)}.json`);
55
+ if (!this.opts.refresh) {
56
+ const cached = await readCache(cachePath);
57
+ if (cached && Date.now() - cached.fetchedAt < this.ttlMs) {
58
+ this.opts.logger?.debug(`forge: cache hit for ${redactRemote(remote)}`);
59
+ return index(cached.prs);
60
+ }
61
+ }
62
+ if (!this.ghChecked) {
63
+ this.ghChecked = true;
64
+ if (!(await have("gh"))) {
65
+ this.unavailableReason =
66
+ "the GitHub CLI (gh) is not installed, so squash-merged branches cannot be detected";
67
+ this.opts.logger?.warn(this.unavailableReason);
68
+ }
69
+ }
70
+ if (this.unavailableReason) {
71
+ const cached = await readCache(cachePath);
72
+ return cached ? index(cached.prs) : null;
73
+ }
74
+ const r = await run("gh", [
75
+ "pr", "list",
76
+ "--repo", remote,
77
+ "--state", "all",
78
+ "--limit", String(this.opts.limit ?? 300),
79
+ "--json", "number,state,headRefName,headRefOid,mergedAt,closedAt,url,title",
80
+ ], { timeoutMs: 60_000 });
81
+ if (r.code !== 0) {
82
+ const detail = (r.stderr || r.stdout).trim().split("\n")[0] ?? "unknown error";
83
+ this.opts.logger?.warn(`forge: gh pr list failed for ${redactRemote(remote)}: ${detail}`);
84
+ // Stale data beats no data: ancestry alone misses squash merges, and a
85
+ // missing PR record can only ever make treekeeper *more* conservative.
86
+ const cached = await readCache(cachePath);
87
+ return cached ? index(cached.prs) : null;
88
+ }
89
+ let parsed;
90
+ try {
91
+ parsed = JSON.parse(r.stdout);
92
+ }
93
+ catch {
94
+ this.opts.logger?.warn(`forge: could not parse gh output for ${redactRemote(remote)}`);
95
+ return null;
96
+ }
97
+ if (!Array.isArray(parsed))
98
+ return null;
99
+ const prs = parsed.flatMap((item) => (isPrLike(item) ? [toPrRef(item)] : []));
100
+ await writeCache(cachePath, { version: 1, fetchedAt: Date.now(), remote: redactRemote(remote), prs });
101
+ this.opts.logger?.debug(`forge: fetched ${prs.length} PRs for ${redactRemote(remote)}`);
102
+ return index(prs);
103
+ }
104
+ }
105
+ function index(prs) {
106
+ const map = new Map();
107
+ for (const pr of prs) {
108
+ const list = map.get(pr.headRefName);
109
+ if (list)
110
+ list.push(pr);
111
+ else
112
+ map.set(pr.headRefName, [pr]);
113
+ }
114
+ for (const list of map.values())
115
+ list.sort((a, b) => b.number - a.number);
116
+ return map;
117
+ }
118
+ /**
119
+ * Pick the PR that decides a branch's fate. A branch name can be reused across
120
+ * several PRs, so prefer a merged PR whose head sha still matches the local tip,
121
+ * then any merged PR, then the newest.
122
+ */
123
+ export function selectPr(prs, localTip) {
124
+ if (!prs || prs.length === 0)
125
+ return null;
126
+ if (localTip) {
127
+ const exact = prs.find((p) => p.headRefOid === localTip && p.state === "MERGED");
128
+ if (exact)
129
+ return exact;
130
+ }
131
+ const merged = prs.find((p) => p.state === "MERGED");
132
+ if (merged)
133
+ return merged;
134
+ const open = prs.find((p) => p.state === "OPEN");
135
+ if (open)
136
+ return open;
137
+ return prs[0] ?? null;
138
+ }
139
+ function isGitHubRemote(remote) {
140
+ return /github\.com/i.test(remote) || /^git@github\.com/i.test(remote);
141
+ }
142
+ function hash(s) {
143
+ return createHash("sha1").update(s).digest("hex").slice(0, 16);
144
+ }
145
+ async function readCache(path) {
146
+ try {
147
+ const parsed = JSON.parse(await readFile(path, "utf8"));
148
+ if (parsed !== null && typeof parsed === "object" &&
149
+ parsed.version === 1 && Array.isArray(parsed.prs)) {
150
+ return parsed;
151
+ }
152
+ }
153
+ catch {
154
+ /* no usable cache */
155
+ }
156
+ return null;
157
+ }
158
+ async function writeCache(path, data) {
159
+ try {
160
+ await mkdir(join(path, ".."), { recursive: true });
161
+ await writeFile(path, JSON.stringify(data));
162
+ }
163
+ catch {
164
+ /* a cache that cannot be written is not an error */
165
+ }
166
+ }
167
+ function isPrLike(v) {
168
+ return v !== null && typeof v === "object" && typeof v["number"] === "number";
169
+ }
170
+ function toPrRef(item) {
171
+ const stateRaw = String(item["state"] ?? "").toUpperCase();
172
+ const state = stateRaw === "MERGED" || stateRaw === "CLOSED" ? stateRaw : "OPEN";
173
+ return {
174
+ number: Number(item["number"]),
175
+ state,
176
+ headRefName: String(item["headRefName"] ?? ""),
177
+ headRefOid: String(item["headRefOid"] ?? ""),
178
+ mergedAt: toEpoch(item["mergedAt"]),
179
+ closedAt: toEpoch(item["closedAt"]),
180
+ url: String(item["url"] ?? ""),
181
+ title: String(item["title"] ?? ""),
182
+ };
183
+ }
184
+ function toEpoch(v) {
185
+ if (typeof v !== "string" || v === "")
186
+ return null;
187
+ const t = Date.parse(v);
188
+ return Number.isFinite(t) ? t : null;
189
+ }
190
+ //# sourceMappingURL=forge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forge.js","sourceRoot":"","sources":["../../src/core/forge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ export interface Worktree {
2
+ path: string;
3
+ /** Short branch name, or null when detached/bare. */
4
+ branch: string | null;
5
+ head: string | null;
6
+ isMain: boolean;
7
+ detached: boolean;
8
+ bare: boolean;
9
+ locked: boolean;
10
+ lockReason: string | null;
11
+ prunable: boolean;
12
+ }
13
+ export interface LocalBranch {
14
+ name: string;
15
+ head: string;
16
+ upstream: string | null;
17
+ }
18
+ /** Top-level directory of the worktree containing `dir`, or null. */
19
+ export declare function repoToplevel(dir: string): Promise<string | null>;
20
+ /**
21
+ * The *main* worktree of the repo containing `dir`. Given a linked worktree this
22
+ * returns the original clone, which is where worktree and branch operations have
23
+ * to run.
24
+ */
25
+ export declare function mainRepoPath(dir: string): Promise<string | null>;
26
+ export declare function isGitRepo(dir: string): Promise<boolean>;
27
+ /** Parse `git worktree list --porcelain`. The first record is the main worktree. */
28
+ export declare function parseWorktreeList(porcelain: string): Worktree[];
29
+ export declare function listWorktrees(repo: string): Promise<Worktree[]>;
30
+ export declare function pruneWorktrees(repo: string): Promise<void>;
31
+ /** origin/HEAD if known, else the first of main/master/trunk that exists. */
32
+ export declare function defaultBranch(repo: string): Promise<string>;
33
+ export declare function refExists(repo: string, ref: string): Promise<boolean>;
34
+ export declare function revParse(repo: string, ref: string): Promise<string | null>;
35
+ export declare function originUrl(repo: string): Promise<string | null>;
36
+ export declare function isAncestor(repo: string, maybeAncestor: string, descendant: string): Promise<boolean>;
37
+ /** Commits on `branch` that are not reachable from `base`. */
38
+ export declare function commitsNotIn(repo: string, base: string, branch: string): Promise<string[]>;
39
+ export declare function localBranches(repo: string): Promise<LocalBranch[]>;
40
+ export interface DirtyState {
41
+ dirty: boolean;
42
+ /** Up to a few entries, for the explanation shown to the user. */
43
+ sample: string[];
44
+ count: number;
45
+ }
46
+ /** Uncommitted changes, including untracked files but not ignored ones. */
47
+ export declare function dirtyState(worktreePath: string): Promise<DirtyState>;
48
+ export declare function untrackedFiles(worktreePath: string): Promise<string[]>;
49
+ /** Seconds-precision commit time of a ref, as epoch ms. */
50
+ export declare function commitTime(repo: string, ref: string): Promise<number | null>;
51
+ export interface RemoveResult {
52
+ ok: boolean;
53
+ method: "git" | "none";
54
+ error?: string;
55
+ }
56
+ export declare function removeWorktree(repo: string, worktreePath: string, force: boolean): Promise<RemoveResult>;
57
+ export declare function deleteBranch(repo: string, branch: string, force?: boolean): Promise<boolean>;
58
+ export declare function remotePrune(repo: string, remote?: string): Promise<boolean>;
59
+ export declare function createBundle(repo: string, destFile: string, revs: string[]): Promise<boolean>;
60
+ /** `git diff HEAD --binary` for a worktree, or null when there is nothing to save. */
61
+ export declare function diffAgainstHead(worktreePath: string): Promise<string | null>;
62
+ export declare function gitVersion(): Promise<string | null>;
63
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,194 @@
1
+ import { run, runLines, runOk } from "../util/exec.js";
2
+ import { dirname, resolve } from "node:path";
3
+ const GIT_TIMEOUT = 30_000;
4
+ async function git(cwd, args) {
5
+ return runOk("git", ["-C", cwd, ...args], { timeoutMs: GIT_TIMEOUT });
6
+ }
7
+ /** Top-level directory of the worktree containing `dir`, or null. */
8
+ export async function repoToplevel(dir) {
9
+ const out = await git(dir, ["rev-parse", "--show-toplevel"]);
10
+ return out ? resolve(out) : null;
11
+ }
12
+ /**
13
+ * The *main* worktree of the repo containing `dir`. Given a linked worktree this
14
+ * returns the original clone, which is where worktree and branch operations have
15
+ * to run.
16
+ */
17
+ export async function mainRepoPath(dir) {
18
+ const common = await git(dir, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
19
+ if (!common)
20
+ return null;
21
+ const abs = resolve(common);
22
+ // ".../repo/.git" -> ".../repo"; a bare repo's common dir is the repo itself.
23
+ const base = abs.endsWith("/.git") || abs.endsWith("\\.git") ? dirname(abs) : abs;
24
+ return base;
25
+ }
26
+ export async function isGitRepo(dir) {
27
+ const out = await git(dir, ["rev-parse", "--is-inside-work-tree"]);
28
+ return out === "true";
29
+ }
30
+ /** Parse `git worktree list --porcelain`. The first record is the main worktree. */
31
+ export function parseWorktreeList(porcelain) {
32
+ const out = [];
33
+ let current = null;
34
+ const push = () => {
35
+ if (current)
36
+ out.push(current);
37
+ };
38
+ for (const rawLine of porcelain.split("\n")) {
39
+ const line = rawLine.replace(/\r$/, "");
40
+ if (line.startsWith("worktree ")) {
41
+ push();
42
+ current = {
43
+ path: resolve(line.slice("worktree ".length)),
44
+ branch: null,
45
+ head: null,
46
+ isMain: out.length === 0,
47
+ detached: false,
48
+ bare: false,
49
+ locked: false,
50
+ lockReason: null,
51
+ prunable: false,
52
+ };
53
+ }
54
+ else if (!current) {
55
+ continue;
56
+ }
57
+ else if (line.startsWith("HEAD ")) {
58
+ current.head = line.slice("HEAD ".length).trim();
59
+ }
60
+ else if (line.startsWith("branch ")) {
61
+ current.branch = line.slice("branch ".length).replace(/^refs\/heads\//, "").trim();
62
+ }
63
+ else if (line === "detached") {
64
+ current.detached = true;
65
+ }
66
+ else if (line === "bare") {
67
+ current.bare = true;
68
+ }
69
+ else if (line.startsWith("locked")) {
70
+ current.locked = true;
71
+ const reason = line.slice("locked".length).trim();
72
+ current.lockReason = reason === "" ? null : reason;
73
+ }
74
+ else if (line.startsWith("prunable")) {
75
+ current.prunable = true;
76
+ }
77
+ }
78
+ push();
79
+ return out;
80
+ }
81
+ export async function listWorktrees(repo) {
82
+ const out = await git(repo, ["worktree", "list", "--porcelain"]);
83
+ return out === null ? [] : parseWorktreeList(out);
84
+ }
85
+ export async function pruneWorktrees(repo) {
86
+ await git(repo, ["worktree", "prune"]);
87
+ }
88
+ /** origin/HEAD if known, else the first of main/master/trunk that exists. */
89
+ export async function defaultBranch(repo) {
90
+ const symref = await git(repo, ["symbolic-ref", "--quiet", "refs/remotes/origin/HEAD"]);
91
+ if (symref)
92
+ return symref.replace(/^refs\/remotes\/origin\//, "");
93
+ const remoteShow = await git(repo, ["rev-parse", "--abbrev-ref", "origin/HEAD"]);
94
+ if (remoteShow && remoteShow !== "origin/HEAD")
95
+ return remoteShow.replace(/^origin\//, "");
96
+ for (const candidate of ["main", "master", "trunk"]) {
97
+ if (await refExists(repo, `refs/heads/${candidate}`))
98
+ return candidate;
99
+ }
100
+ const head = await git(repo, ["rev-parse", "--abbrev-ref", "HEAD"]);
101
+ return head && head !== "HEAD" ? head : "main";
102
+ }
103
+ export async function refExists(repo, ref) {
104
+ const r = await run("git", ["-C", repo, "show-ref", "--verify", "--quiet", ref], {
105
+ timeoutMs: GIT_TIMEOUT,
106
+ });
107
+ return r.code === 0;
108
+ }
109
+ export async function revParse(repo, ref) {
110
+ return git(repo, ["rev-parse", "--verify", "--quiet", ref]);
111
+ }
112
+ export async function originUrl(repo) {
113
+ return git(repo, ["remote", "get-url", "origin"]);
114
+ }
115
+ export async function isAncestor(repo, maybeAncestor, descendant) {
116
+ const r = await run("git", ["-C", repo, "merge-base", "--is-ancestor", maybeAncestor, descendant], { timeoutMs: GIT_TIMEOUT });
117
+ return r.code === 0;
118
+ }
119
+ /** Commits on `branch` that are not reachable from `base`. */
120
+ export async function commitsNotIn(repo, base, branch) {
121
+ return runLines("git", ["-C", repo, "rev-list", `${base}..${branch}`], { timeoutMs: GIT_TIMEOUT });
122
+ }
123
+ export async function localBranches(repo) {
124
+ const lines = await runLines("git", ["-C", repo, "for-each-ref", "--format=%(refname:short)%09%(objectname)%09%(upstream:short)", "refs/heads/"], { timeoutMs: GIT_TIMEOUT });
125
+ const out = [];
126
+ for (const line of lines) {
127
+ const [name, head, upstream] = line.split("\t");
128
+ if (!name || !head)
129
+ continue;
130
+ out.push({ name, head, upstream: upstream && upstream !== "" ? upstream : null });
131
+ }
132
+ return out;
133
+ }
134
+ /** Uncommitted changes, including untracked files but not ignored ones. */
135
+ export async function dirtyState(worktreePath) {
136
+ const out = await git(worktreePath, ["status", "--porcelain", "--untracked-files=normal"]);
137
+ if (out === null)
138
+ return { dirty: false, sample: [], count: 0 };
139
+ const lines = out.split("\n").filter((l) => l.trim() !== "");
140
+ return { dirty: lines.length > 0, sample: lines.slice(0, 5), count: lines.length };
141
+ }
142
+ export async function untrackedFiles(worktreePath) {
143
+ return runLines("git", ["-C", worktreePath, "ls-files", "--others", "--exclude-standard"], { timeoutMs: GIT_TIMEOUT });
144
+ }
145
+ /** Seconds-precision commit time of a ref, as epoch ms. */
146
+ export async function commitTime(repo, ref) {
147
+ const out = await git(repo, ["log", "-1", "--format=%ct", ref]);
148
+ if (!out)
149
+ return null;
150
+ const n = Number(out);
151
+ return Number.isFinite(n) ? n * 1000 : null;
152
+ }
153
+ export async function removeWorktree(repo, worktreePath, force) {
154
+ const args = ["-C", repo, "worktree", "remove"];
155
+ if (force)
156
+ args.push("--force");
157
+ args.push(worktreePath);
158
+ const r = await run("git", args, { timeoutMs: 120_000 });
159
+ if (r.code === 0)
160
+ return { ok: true, method: "git" };
161
+ return { ok: false, method: "none", error: (r.stderr || r.stdout).trim() };
162
+ }
163
+ export async function deleteBranch(repo, branch, force = true) {
164
+ const r = await run("git", ["-C", repo, "branch", force ? "-D" : "-d", branch], {
165
+ timeoutMs: GIT_TIMEOUT,
166
+ });
167
+ return r.code === 0;
168
+ }
169
+ export async function remotePrune(repo, remote = "origin") {
170
+ const r = await run("git", ["-C", repo, "remote", "prune", remote], { timeoutMs: 60_000 });
171
+ return r.code === 0;
172
+ }
173
+ export async function createBundle(repo, destFile, revs) {
174
+ if (revs.length === 0)
175
+ return false;
176
+ const r = await run("git", ["-C", repo, "bundle", "create", destFile, ...revs], {
177
+ timeoutMs: 180_000,
178
+ });
179
+ return r.code === 0;
180
+ }
181
+ /** `git diff HEAD --binary` for a worktree, or null when there is nothing to save. */
182
+ export async function diffAgainstHead(worktreePath) {
183
+ const r = await run("git", ["-C", worktreePath, "diff", "HEAD", "--binary"], {
184
+ timeoutMs: 120_000,
185
+ });
186
+ if (r.code !== 0)
187
+ return null;
188
+ return r.stdout.trim() === "" ? null : r.stdout;
189
+ }
190
+ export async function gitVersion() {
191
+ const out = await runOk("git", ["--version"], { timeoutMs: 10_000 });
192
+ return out ? out.replace(/^git version\s*/, "") : null;
193
+ }
194
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import type { Config } from "./config.js";
2
+ import type { MergeStatus, Policy, Verdict } from "./decide.js";
3
+ import type { Forge, PrIndex } from "./forge.js";
4
+ import type { ActivityHit } from "./sessions.js";
5
+ import type { Logger } from "../util/log.js";
6
+ export interface WorktreeCandidate {
7
+ repo: string;
8
+ repoName: string;
9
+ path: string;
10
+ branch: string | null;
11
+ head: string | null;
12
+ sizeKb: number | null;
13
+ verdict: Verdict;
14
+ merge: MergeStatus;
15
+ activity: ActivityHit | null;
16
+ lastTouched: number;
17
+ dirty: boolean;
18
+ dirtyCount: number;
19
+ }
20
+ export interface BranchCandidate {
21
+ repo: string;
22
+ repoName: string;
23
+ name: string;
24
+ head: string;
25
+ verdict: Verdict;
26
+ merge: MergeStatus;
27
+ }
28
+ export interface RepoPlan {
29
+ repo: string;
30
+ name: string;
31
+ defaultBranch: string;
32
+ forgeAvailable: boolean;
33
+ worktrees: WorktreeCandidate[];
34
+ branches: BranchCandidate[];
35
+ /** Set when the repo was skipped entirely (opted out, unreadable). */
36
+ skipped: string | null;
37
+ }
38
+ export interface PlanSummary {
39
+ repos: number;
40
+ worktreesScanned: number;
41
+ worktreesReclaimable: number;
42
+ worktreesKept: number;
43
+ branchesDeletable: number;
44
+ reclaimKb: number;
45
+ }
46
+ export interface Plan {
47
+ version: 1;
48
+ generatedAt: string;
49
+ now: number;
50
+ roots: string[];
51
+ repos: RepoPlan[];
52
+ summary: PlanSummary;
53
+ warnings: string[];
54
+ }
55
+ export interface PlanOptions {
56
+ config: Config;
57
+ repos: string[];
58
+ forge: Forge;
59
+ logger?: Logger;
60
+ now?: number;
61
+ cwd?: string;
62
+ force?: boolean;
63
+ /** Measure every worktree, not just the ones being reclaimed. */
64
+ allSizes?: boolean;
65
+ /** Plan branch deletions only, leaving every worktree in place. */
66
+ skipWorktrees?: boolean;
67
+ }
68
+ export declare function policyFromConfig(cfg: Config, force?: boolean): Policy;
69
+ export declare function buildPlan(opts: PlanOptions): Promise<Plan>;
70
+ export declare function mergeStatus(repo: string, branch: string, tip: string | null, bases: string[], prIndex: PrIndex | null): Promise<MergeStatus>;
71
+ export declare function isProtectedBranch(cfg: Config, branch: string): boolean;
72
+ export declare function isProtectedPath(cfg: Config, path: string): boolean;
73
+ /** Every worktree the plan would remove, flattened. */
74
+ export declare function reclaimable(plan: Plan): WorktreeCandidate[];
75
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/core/plan.ts"],"names":[],"mappings":"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"}