@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.
- package/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +237 -2
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +165 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/archive.d.ts +3 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +55 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +54 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/context.d.ts +34 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +53 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/daemon.d.ts +3 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +81 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +119 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/gc.d.ts +3 -0
- package/dist/commands/gc.d.ts.map +1 -0
- package/dist/commands/gc.js +98 -0
- package/dist/commands/gc.js.map +1 -0
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +52 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/watch.d.ts +10 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +41 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/core/apply.d.ts +47 -0
- package/dist/core/apply.d.ts.map +1 -0
- package/dist/core/apply.js +223 -0
- package/dist/core/apply.js.map +1 -0
- package/dist/core/archive.d.ts +69 -0
- package/dist/core/archive.d.ts.map +1 -0
- package/dist/core/archive.js +202 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/config.d.ts +69 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +261 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/decide.d.ts +102 -0
- package/dist/core/decide.d.ts.map +1 -0
- package/dist/core/decide.js +148 -0
- package/dist/core/decide.js.map +1 -0
- package/dist/core/forge.d.ts +39 -0
- package/dist/core/forge.d.ts.map +1 -0
- package/dist/core/forge.js +190 -0
- package/dist/core/forge.js.map +1 -0
- package/dist/core/git.d.ts +63 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +194 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/plan.d.ts +75 -0
- package/dist/core/plan.d.ts.map +1 -0
- package/dist/core/plan.js +288 -0
- package/dist/core/plan.js.map +1 -0
- package/dist/core/render.d.ts +14 -0
- package/dist/core/render.d.ts.map +1 -0
- package/dist/core/render.js +128 -0
- package/dist/core/render.js.map +1 -0
- package/dist/core/scan.d.ts +22 -0
- package/dist/core/scan.d.ts.map +1 -0
- package/dist/core/scan.js +99 -0
- package/dist/core/scan.js.map +1 -0
- package/dist/core/sessions.d.ts +37 -0
- package/dist/core/sessions.d.ts.map +1 -0
- package/dist/core/sessions.js +300 -0
- package/dist/core/sessions.js.map +1 -0
- package/dist/core/size.d.ts +3 -0
- package/dist/core/size.d.ts.map +1 -0
- package/dist/core/size.js +11 -0
- package/dist/core/size.js.map +1 -0
- package/dist/daemon/lock.d.ts +10 -0
- package/dist/daemon/lock.d.ts.map +1 -0
- package/dist/daemon/lock.js +64 -0
- package/dist/daemon/lock.js.map +1 -0
- package/dist/daemon/service.d.ts +34 -0
- package/dist/daemon/service.d.ts.map +1 -0
- package/dist/daemon/service.js +257 -0
- package/dist/daemon/service.js.map +1 -0
- package/dist/daemon/state.d.ts +19 -0
- package/dist/daemon/state.d.ts.map +1 -0
- package/dist/daemon/state.js +32 -0
- package/dist/daemon/state.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/util/bytes.d.ts +4 -0
- package/dist/util/bytes.d.ts.map +1 -0
- package/dist/util/bytes.js +14 -0
- package/dist/util/bytes.js.map +1 -0
- package/dist/util/color.d.ts +16 -0
- package/dist/util/color.d.ts.map +1 -0
- package/dist/util/color.js +32 -0
- package/dist/util/color.js.map +1 -0
- package/dist/util/exec.d.ts +27 -0
- package/dist/util/exec.d.ts.map +1 -0
- package/dist/util/exec.js +57 -0
- package/dist/util/exec.js.map +1 -0
- package/dist/util/log.d.ts +29 -0
- package/dist/util/log.d.ts.map +1 -0
- package/dist/util/log.js +72 -0
- package/dist/util/log.js.map +1 -0
- package/dist/util/paths.d.ts +18 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +87 -0
- package/dist/util/paths.js.map +1 -0
- package/dist/util/prompt.d.ts +3 -0
- package/dist/util/prompt.d.ts.map +1 -0
- package/dist/util/prompt.js +15 -0
- package/dist/util/prompt.js.map +1 -0
- package/dist/util/redact.d.ts +15 -0
- package/dist/util/redact.d.ts.map +1 -0
- package/dist/util/redact.js +44 -0
- package/dist/util/redact.js.map +1 -0
- package/dist/util/time.d.ts +13 -0
- package/dist/util/time.d.ts.map +1 -0
- package/dist/util/time.js +77 -0
- package/dist/util/time.js.map +1 -0
- package/docs/integrations.md +128 -0
- package/docs/safety.md +62 -0
- package/package.json +69 -4
- package/src/cli.ts +175 -0
- package/src/commands/archive.ts +72 -0
- package/src/commands/config.ts +57 -0
- package/src/commands/context.ts +86 -0
- package/src/commands/daemon.ts +86 -0
- package/src/commands/doctor.ts +131 -0
- package/src/commands/gc.ts +108 -0
- package/src/commands/status.ts +68 -0
- package/src/commands/watch.ts +48 -0
- package/src/core/apply.ts +276 -0
- package/src/core/archive.ts +269 -0
- package/src/core/config.ts +339 -0
- package/src/core/decide.ts +230 -0
- package/src/core/forge.ts +243 -0
- package/src/core/git.ts +254 -0
- package/src/core/plan.ts +431 -0
- package/src/core/render.ts +168 -0
- package/src/core/scan.ts +105 -0
- package/src/core/sessions.ts +339 -0
- package/src/core/size.ts +10 -0
- package/src/daemon/lock.ts +65 -0
- package/src/daemon/service.ts +321 -0
- package/src/daemon/state.ts +49 -0
- package/src/index.ts +36 -0
- package/src/util/bytes.ts +11 -0
- package/src/util/color.ts +33 -0
- package/src/util/exec.ts +80 -0
- package/src/util/log.ts +88 -0
- package/src/util/paths.ts +84 -0
- package/src/util/prompt.ts +13 -0
- package/src/util/redact.ts +43 -0
- package/src/util/time.ts +75 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { expandPath, treekeeperHome } from "../util/paths.js";
|
|
4
|
+
import { parseDuration } from "../util/time.js";
|
|
5
|
+
export const CONFIG_FILENAME = "config.json";
|
|
6
|
+
export const REPO_CONFIG_FILENAME = ".treekeeper.json";
|
|
7
|
+
export function defaultConfig() {
|
|
8
|
+
const home = treekeeperHome();
|
|
9
|
+
return {
|
|
10
|
+
roots: ["~/src"],
|
|
11
|
+
maxDepth: 3,
|
|
12
|
+
minAge: "30m",
|
|
13
|
+
closedPrGrace: "7d",
|
|
14
|
+
onDirty: "archive",
|
|
15
|
+
onClosedPr: "archive",
|
|
16
|
+
onExtraCommits: "keep",
|
|
17
|
+
protectBranches: ["main", "master", "trunk", "develop", "dev", "release/*"],
|
|
18
|
+
protectPaths: [],
|
|
19
|
+
pruneBranches: true,
|
|
20
|
+
pruneRemotes: false,
|
|
21
|
+
forge: "github",
|
|
22
|
+
forgeCacheTtl: "10m",
|
|
23
|
+
interval: "15m",
|
|
24
|
+
sessions: {
|
|
25
|
+
grace: "20m",
|
|
26
|
+
detectors: ["claude-code", "codex", "aider", "process", "mtime"],
|
|
27
|
+
extraPaths: [],
|
|
28
|
+
commands: [],
|
|
29
|
+
},
|
|
30
|
+
archive: {
|
|
31
|
+
enabled: true,
|
|
32
|
+
dir: join(home, "archive"),
|
|
33
|
+
retention: "14d",
|
|
34
|
+
maxUntrackedBytes: 64 * 1024 * 1024,
|
|
35
|
+
},
|
|
36
|
+
logFile: join(home, "treekeeper.log"),
|
|
37
|
+
logLevel: "info",
|
|
38
|
+
enabled: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function globalConfigPath() {
|
|
42
|
+
const override = process.env.TREEKEEPER_CONFIG;
|
|
43
|
+
if (override && override.trim() !== "")
|
|
44
|
+
return expandPath(override);
|
|
45
|
+
return join(treekeeperHome(), CONFIG_FILENAME);
|
|
46
|
+
}
|
|
47
|
+
/** Load the user-level config, falling back to defaults when absent. */
|
|
48
|
+
export async function loadConfig(path = globalConfigPath()) {
|
|
49
|
+
const base = defaultConfig();
|
|
50
|
+
const warnings = [];
|
|
51
|
+
const sources = [];
|
|
52
|
+
const raw = await readJsonIfPresent(path, warnings);
|
|
53
|
+
if (raw !== null) {
|
|
54
|
+
sources.push(path);
|
|
55
|
+
mergeInto(base, raw, warnings, path);
|
|
56
|
+
}
|
|
57
|
+
normalize(base, warnings);
|
|
58
|
+
return { config: base, sources, warnings };
|
|
59
|
+
}
|
|
60
|
+
/** Layer a repo-local `.treekeeper.json` on top of an already-loaded config. */
|
|
61
|
+
export async function loadRepoConfig(repoPath, parent) {
|
|
62
|
+
const path = join(repoPath, REPO_CONFIG_FILENAME);
|
|
63
|
+
const warnings = [];
|
|
64
|
+
const raw = await readJsonIfPresent(path, warnings);
|
|
65
|
+
if (raw === null)
|
|
66
|
+
return { config: parent, sources: [], warnings };
|
|
67
|
+
const merged = structuredClone(parent);
|
|
68
|
+
mergeInto(merged, raw, warnings, path);
|
|
69
|
+
normalize(merged, warnings);
|
|
70
|
+
return { config: merged, sources: [path], warnings };
|
|
71
|
+
}
|
|
72
|
+
async function readJsonIfPresent(path, warnings) {
|
|
73
|
+
let text;
|
|
74
|
+
try {
|
|
75
|
+
text = await readFile(path, "utf8");
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const code = err.code;
|
|
79
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
80
|
+
warnings.push(`could not read ${path}: ${err.message}`);
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
// Tolerate `//` and `/* */` comments and trailing commas — these files get
|
|
85
|
+
// hand-edited, and a strict parser turns a comment into a crashed daemon.
|
|
86
|
+
const stripped = text
|
|
87
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
88
|
+
.replace(/(^|[^:"'\\])\/\/.*$/gm, "$1")
|
|
89
|
+
.replace(/,(\s*[}\]])/g, "$1");
|
|
90
|
+
try {
|
|
91
|
+
const parsed = JSON.parse(stripped);
|
|
92
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
93
|
+
warnings.push(`${path}: expected a JSON object, ignoring`);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return parsed;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
warnings.push(`${path}: invalid JSON (${err.message}), ignoring`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const KNOWN_KEYS = new Set([
|
|
104
|
+
"roots", "maxDepth", "minAge", "closedPrGrace", "onDirty", "onClosedPr",
|
|
105
|
+
"onExtraCommits", "protectBranches", "protectPaths", "pruneBranches",
|
|
106
|
+
"pruneRemotes", "forge", "forgeCacheTtl", "interval", "sessions", "archive",
|
|
107
|
+
"logFile", "logLevel", "enabled", "$schema",
|
|
108
|
+
]);
|
|
109
|
+
function mergeInto(target, raw, warnings, source) {
|
|
110
|
+
for (const key of Object.keys(raw)) {
|
|
111
|
+
if (!KNOWN_KEYS.has(key))
|
|
112
|
+
warnings.push(`${source}: unknown option "${key}"`);
|
|
113
|
+
}
|
|
114
|
+
strArray(raw, "roots", warnings, source, (v) => (target.roots = v));
|
|
115
|
+
num(raw, "maxDepth", warnings, source, (v) => (target.maxDepth = v));
|
|
116
|
+
dur(raw, "minAge", warnings, source, (v) => (target.minAge = v));
|
|
117
|
+
dur(raw, "closedPrGrace", warnings, source, (v) => (target.closedPrGrace = v));
|
|
118
|
+
enumOf(raw, "onDirty", ["archive", "keep"], warnings, source, (v) => (target.onDirty = v));
|
|
119
|
+
enumOf(raw, "onClosedPr", ["archive", "keep"], warnings, source, (v) => (target.onClosedPr = v));
|
|
120
|
+
enumOf(raw, "onExtraCommits", ["archive", "keep"], warnings, source, (v) => (target.onExtraCommits = v));
|
|
121
|
+
strArray(raw, "protectBranches", warnings, source, (v) => (target.protectBranches = v));
|
|
122
|
+
strArray(raw, "protectPaths", warnings, source, (v) => (target.protectPaths = v));
|
|
123
|
+
bool(raw, "pruneBranches", warnings, source, (v) => (target.pruneBranches = v));
|
|
124
|
+
bool(raw, "pruneRemotes", warnings, source, (v) => (target.pruneRemotes = v));
|
|
125
|
+
enumOf(raw, "forge", ["github", "none"], warnings, source, (v) => (target.forge = v));
|
|
126
|
+
dur(raw, "forgeCacheTtl", warnings, source, (v) => (target.forgeCacheTtl = v));
|
|
127
|
+
dur(raw, "interval", warnings, source, (v) => (target.interval = v));
|
|
128
|
+
str(raw, "logFile", warnings, source, (v) => (target.logFile = v));
|
|
129
|
+
enumOf(raw, "logLevel", ["debug", "info", "warn", "error"], warnings, source, (v) => (target.logLevel = v));
|
|
130
|
+
bool(raw, "enabled", warnings, source, (v) => (target.enabled = v));
|
|
131
|
+
const sessions = raw["sessions"];
|
|
132
|
+
if (sessions !== undefined) {
|
|
133
|
+
if (isObject(sessions)) {
|
|
134
|
+
dur(sessions, "grace", warnings, source, (v) => (target.sessions.grace = v));
|
|
135
|
+
strArray(sessions, "detectors", warnings, source, (v) => (target.sessions.detectors = v));
|
|
136
|
+
strArray(sessions, "extraPaths", warnings, source, (v) => (target.sessions.extraPaths = v));
|
|
137
|
+
const cmds = sessions["commands"];
|
|
138
|
+
if (cmds !== undefined) {
|
|
139
|
+
if (Array.isArray(cmds)) {
|
|
140
|
+
const out = [];
|
|
141
|
+
for (const c of cmds) {
|
|
142
|
+
if (isObject(c) && typeof c["command"] === "string") {
|
|
143
|
+
out.push({
|
|
144
|
+
name: typeof c["name"] === "string" ? c["name"] : "custom",
|
|
145
|
+
command: c["command"],
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
warnings.push(`${source}: sessions.commands entries need a "command" string`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
target.sessions.commands = out;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
warnings.push(`${source}: sessions.commands must be an array`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
warnings.push(`${source}: sessions must be an object`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const archive = raw["archive"];
|
|
164
|
+
if (archive !== undefined) {
|
|
165
|
+
if (isObject(archive)) {
|
|
166
|
+
bool(archive, "enabled", warnings, source, (v) => (target.archive.enabled = v));
|
|
167
|
+
str(archive, "dir", warnings, source, (v) => (target.archive.dir = v));
|
|
168
|
+
dur(archive, "retention", warnings, source, (v) => (target.archive.retention = v));
|
|
169
|
+
num(archive, "maxUntrackedBytes", warnings, source, (v) => (target.archive.maxUntrackedBytes = v));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
warnings.push(`${source}: archive must be an object`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function normalize(cfg, warnings) {
|
|
177
|
+
cfg.roots = cfg.roots.map((r) => expandPath(r));
|
|
178
|
+
cfg.protectPaths = cfg.protectPaths.map((p) => (p.includes("*") ? expandPath0(p) : expandPath(p)));
|
|
179
|
+
cfg.archive.dir = expandPath(cfg.archive.dir);
|
|
180
|
+
cfg.logFile = expandPath(cfg.logFile);
|
|
181
|
+
if (cfg.maxDepth < 1) {
|
|
182
|
+
warnings.push("maxDepth must be at least 1, using 1");
|
|
183
|
+
cfg.maxDepth = 1;
|
|
184
|
+
}
|
|
185
|
+
const unknownDetectors = cfg.sessions.detectors.filter((d) => !["claude-code", "codex", "aider", "process", "mtime"].includes(d));
|
|
186
|
+
for (const d of unknownDetectors)
|
|
187
|
+
warnings.push(`unknown session detector "${d}"`);
|
|
188
|
+
}
|
|
189
|
+
/** Expand `~` in a glob without resolving the wildcards away. */
|
|
190
|
+
function expandPath0(pattern) {
|
|
191
|
+
if (pattern === "~" || pattern.startsWith("~/")) {
|
|
192
|
+
const home = expandPath("~");
|
|
193
|
+
return pattern === "~" ? home : `${home}/${pattern.slice(2)}`;
|
|
194
|
+
}
|
|
195
|
+
return pattern;
|
|
196
|
+
}
|
|
197
|
+
function isObject(v) {
|
|
198
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
199
|
+
}
|
|
200
|
+
function str(raw, key, w, src, set) {
|
|
201
|
+
const v = raw[key];
|
|
202
|
+
if (v === undefined)
|
|
203
|
+
return;
|
|
204
|
+
if (typeof v === "string")
|
|
205
|
+
set(v);
|
|
206
|
+
else
|
|
207
|
+
w.push(`${src}: ${key} must be a string`);
|
|
208
|
+
}
|
|
209
|
+
function num(raw, key, w, src, set) {
|
|
210
|
+
const v = raw[key];
|
|
211
|
+
if (v === undefined)
|
|
212
|
+
return;
|
|
213
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
214
|
+
set(v);
|
|
215
|
+
else
|
|
216
|
+
w.push(`${src}: ${key} must be a number`);
|
|
217
|
+
}
|
|
218
|
+
function bool(raw, key, w, src, set) {
|
|
219
|
+
const v = raw[key];
|
|
220
|
+
if (v === undefined)
|
|
221
|
+
return;
|
|
222
|
+
if (typeof v === "boolean")
|
|
223
|
+
set(v);
|
|
224
|
+
else
|
|
225
|
+
w.push(`${src}: ${key} must be true or false`);
|
|
226
|
+
}
|
|
227
|
+
function strArray(raw, key, w, src, set) {
|
|
228
|
+
const v = raw[key];
|
|
229
|
+
if (v === undefined)
|
|
230
|
+
return;
|
|
231
|
+
if (Array.isArray(v) && v.every((x) => typeof x === "string"))
|
|
232
|
+
set(v);
|
|
233
|
+
else
|
|
234
|
+
w.push(`${src}: ${key} must be an array of strings`);
|
|
235
|
+
}
|
|
236
|
+
function dur(raw, key, w, src, set) {
|
|
237
|
+
const v = raw[key];
|
|
238
|
+
if (v === undefined)
|
|
239
|
+
return;
|
|
240
|
+
if (typeof v !== "string" && typeof v !== "number") {
|
|
241
|
+
w.push(`${src}: ${key} must be a duration like "30m"`);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
parseDuration(v);
|
|
246
|
+
set(String(v));
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
w.push(`${src}: ${key} — ${err.message}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function enumOf(raw, key, allowed, w, src, set) {
|
|
253
|
+
const v = raw[key];
|
|
254
|
+
if (v === undefined)
|
|
255
|
+
return;
|
|
256
|
+
if (typeof v === "string" && allowed.includes(v))
|
|
257
|
+
set(v);
|
|
258
|
+
else
|
|
259
|
+
w.push(`${src}: ${key} must be one of ${allowed.join(", ")}`);
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { DirtyPolicy } from "./config.js";
|
|
2
|
+
import type { PrRef } from "./forge.js";
|
|
3
|
+
/** How the work on a branch relates to the default branch and its pull request. */
|
|
4
|
+
export type MergeStatus = {
|
|
5
|
+
kind: "merged-ancestor";
|
|
6
|
+
base: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "merged-pr";
|
|
9
|
+
pr: PrRef;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "merged-pr-extra";
|
|
12
|
+
pr: PrRef;
|
|
13
|
+
extra: number;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "closed-pr";
|
|
16
|
+
pr: PrRef;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "open-pr";
|
|
19
|
+
pr: PrRef;
|
|
20
|
+
} | {
|
|
21
|
+
kind: "unmerged";
|
|
22
|
+
forgeAvailable: boolean;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "no-branch";
|
|
25
|
+
};
|
|
26
|
+
export type Risk = "dirty" | "closed-pr" | "extra-commits";
|
|
27
|
+
export interface Verdict {
|
|
28
|
+
action: "reclaim" | "keep";
|
|
29
|
+
/** Human sentence shown in the plan and written to the log. */
|
|
30
|
+
reason: string;
|
|
31
|
+
/** Stable identifier for scripts reading `--json`. */
|
|
32
|
+
code: string;
|
|
33
|
+
/** Why this removal needs an archive first. Empty when the work is safely merged. */
|
|
34
|
+
risks: Risk[];
|
|
35
|
+
}
|
|
36
|
+
export interface Policy {
|
|
37
|
+
minAgeMs: number;
|
|
38
|
+
closedPrGraceMs: number;
|
|
39
|
+
onDirty: DirtyPolicy;
|
|
40
|
+
onClosedPr: DirtyPolicy;
|
|
41
|
+
onExtraCommits: DirtyPolicy;
|
|
42
|
+
/** Bypasses the age gate and the dirty / extra-commits / closed-PR holds. */
|
|
43
|
+
force: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface WorktreeFacts {
|
|
46
|
+
now: number;
|
|
47
|
+
isMain: boolean;
|
|
48
|
+
detached: boolean;
|
|
49
|
+
locked: boolean;
|
|
50
|
+
lockReason: string | null;
|
|
51
|
+
branch: string | null;
|
|
52
|
+
protectedBranch: boolean;
|
|
53
|
+
protectedPath: boolean;
|
|
54
|
+
/** The worktree contains the caller's working directory. */
|
|
55
|
+
isCwd: boolean;
|
|
56
|
+
merge: MergeStatus;
|
|
57
|
+
dirty: boolean;
|
|
58
|
+
dirtyCount: number;
|
|
59
|
+
/** Most recent agent/human activity, or null when nothing was detected. */
|
|
60
|
+
activity: {
|
|
61
|
+
detector: string;
|
|
62
|
+
lastActivity: number;
|
|
63
|
+
detail: string;
|
|
64
|
+
} | null;
|
|
65
|
+
activityIsRecent: boolean;
|
|
66
|
+
/** Newest mtime seen for this worktree, used for the age gate. */
|
|
67
|
+
lastTouched: number;
|
|
68
|
+
inUse: boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Decide the fate of one worktree.
|
|
72
|
+
*
|
|
73
|
+
* Pure on purpose: every signal is gathered elsewhere, so the rules that decide
|
|
74
|
+
* whether a developer's directory gets deleted are a single readable function
|
|
75
|
+
* with a truth table in the tests.
|
|
76
|
+
*
|
|
77
|
+
* Invariant: a worktree is only ever reclaimed when its commits are reachable
|
|
78
|
+
* from the default branch, or its pull request was merged or closed. `force`
|
|
79
|
+
* does not relax that.
|
|
80
|
+
*/
|
|
81
|
+
export declare function decideWorktree(f: WorktreeFacts, policy: Policy): Verdict;
|
|
82
|
+
export interface BranchFacts {
|
|
83
|
+
now: number;
|
|
84
|
+
name: string;
|
|
85
|
+
isDefault: boolean;
|
|
86
|
+
protectedBranch: boolean;
|
|
87
|
+
/** A worktree still has this branch checked out. */
|
|
88
|
+
hasWorktree: boolean;
|
|
89
|
+
/** This branch is the current HEAD of the main worktree. */
|
|
90
|
+
isCurrent: boolean;
|
|
91
|
+
merge: MergeStatus;
|
|
92
|
+
lastCommit: number | null;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Decide whether a local branch with no worktree should be deleted.
|
|
96
|
+
*
|
|
97
|
+
* Deleting a branch only drops a pointer, so this is cheaper to get wrong than
|
|
98
|
+
* a worktree — but it can still orphan commits, so unmerged branches are never
|
|
99
|
+
* touched and closed-PR branches get archived like worktrees do.
|
|
100
|
+
*/
|
|
101
|
+
export declare function decideBranch(f: BranchFacts, policy: Policy): Verdict;
|
|
102
|
+
//# sourceMappingURL=decide.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decide.d.ts","sourceRoot":"","sources":["../../src/core/decide.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,mFAAmF;AACnF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,KAAK,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,KAAK,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,KAAK,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAE1B,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,WAAW,GAAG,eAAe,CAAC;AAE3D,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,WAAW,CAAC;IACrB,UAAU,EAAE,WAAW,CAAC;IACxB,cAAc,EAAE,WAAW,CAAC;IAC5B,6EAA6E;IAC7E,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,4DAA4D;IAC5D,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CAChB;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAwGxE;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,oDAAoD;IACpD,WAAW,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAgCpE"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { formatAgo, formatDuration } from "../util/time.js";
|
|
2
|
+
const keep = (code, reason) => ({ action: "keep", reason, code, risks: [] });
|
|
3
|
+
/**
|
|
4
|
+
* Decide the fate of one worktree.
|
|
5
|
+
*
|
|
6
|
+
* Pure on purpose: every signal is gathered elsewhere, so the rules that decide
|
|
7
|
+
* whether a developer's directory gets deleted are a single readable function
|
|
8
|
+
* with a truth table in the tests.
|
|
9
|
+
*
|
|
10
|
+
* Invariant: a worktree is only ever reclaimed when its commits are reachable
|
|
11
|
+
* from the default branch, or its pull request was merged or closed. `force`
|
|
12
|
+
* does not relax that.
|
|
13
|
+
*/
|
|
14
|
+
export function decideWorktree(f, policy) {
|
|
15
|
+
if (f.isMain)
|
|
16
|
+
return keep("main-worktree", "the repo's main worktree");
|
|
17
|
+
if (f.protectedPath)
|
|
18
|
+
return keep("protected-path", "matches protectPaths");
|
|
19
|
+
if (f.isCwd)
|
|
20
|
+
return keep("cwd", "your current working directory");
|
|
21
|
+
if (f.locked) {
|
|
22
|
+
return keep("locked", `locked${f.lockReason ? `: ${f.lockReason}` : ""}`);
|
|
23
|
+
}
|
|
24
|
+
if (f.detached || !f.branch)
|
|
25
|
+
return keep("detached", "detached HEAD — no branch to check");
|
|
26
|
+
if (f.protectedBranch)
|
|
27
|
+
return keep("protected-branch", `${f.branch} matches protectBranches`);
|
|
28
|
+
const risks = [];
|
|
29
|
+
let mergedReason;
|
|
30
|
+
switch (f.merge.kind) {
|
|
31
|
+
case "merged-ancestor":
|
|
32
|
+
mergedReason = `merged into ${f.merge.base}`;
|
|
33
|
+
break;
|
|
34
|
+
case "merged-pr":
|
|
35
|
+
mergedReason = `PR #${f.merge.pr.number} merged`;
|
|
36
|
+
break;
|
|
37
|
+
case "merged-pr-extra": {
|
|
38
|
+
const n = f.merge.extra;
|
|
39
|
+
const detail = `PR #${f.merge.pr.number} merged, but the local branch has ${n} commit${n === 1 ? "" : "s"} the PR never had`;
|
|
40
|
+
if (policy.onExtraCommits === "keep" && !policy.force) {
|
|
41
|
+
return keep("extra-commits", detail);
|
|
42
|
+
}
|
|
43
|
+
risks.push("extra-commits");
|
|
44
|
+
mergedReason = detail;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case "closed-pr": {
|
|
48
|
+
const detail = `PR #${f.merge.pr.number} closed without merging`;
|
|
49
|
+
if (policy.onClosedPr === "keep" && !policy.force) {
|
|
50
|
+
return keep("closed-pr", `${detail} — onClosedPr is "keep"`);
|
|
51
|
+
}
|
|
52
|
+
const closedAt = f.merge.pr.closedAt;
|
|
53
|
+
if (!policy.force && closedAt !== null) {
|
|
54
|
+
const waited = f.now - closedAt;
|
|
55
|
+
if (waited < policy.closedPrGraceMs) {
|
|
56
|
+
return keep("closed-pr-grace", `${detail} ${formatAgo(closedAt, f.now)} — holding for ${formatDuration(policy.closedPrGraceMs - waited)} more`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
risks.push("closed-pr");
|
|
60
|
+
mergedReason = detail;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case "open-pr":
|
|
64
|
+
return keep("open-pr", `PR #${f.merge.pr.number} is still open`);
|
|
65
|
+
case "unmerged":
|
|
66
|
+
return keep("unmerged", f.merge.forgeAvailable
|
|
67
|
+
? "not merged and has no merged pull request"
|
|
68
|
+
: "not merged (no pull-request data available)");
|
|
69
|
+
case "no-branch":
|
|
70
|
+
return keep("no-branch", "no branch to check");
|
|
71
|
+
}
|
|
72
|
+
// Work is finished. Now the "is anyone still using it" gates.
|
|
73
|
+
// A live process is checked first because it is the least ambiguous signal
|
|
74
|
+
// and deserves the clearest message.
|
|
75
|
+
if (f.inUse) {
|
|
76
|
+
return keep("in-use", `${mergedReason}, but a running process is still in it`);
|
|
77
|
+
}
|
|
78
|
+
if (f.activityIsRecent && f.activity) {
|
|
79
|
+
return keep("session-active", `${mergedReason}, but ${f.activity.detector} activity ${formatAgo(f.activity.lastActivity, f.now)}`);
|
|
80
|
+
}
|
|
81
|
+
if (!policy.force) {
|
|
82
|
+
// Clamped: file mtimes carry sub-millisecond fractions while Date.now()
|
|
83
|
+
// truncates, so a worktree touched this instant can otherwise look like it
|
|
84
|
+
// was touched in the future.
|
|
85
|
+
const age = Math.max(0, f.now - f.lastTouched);
|
|
86
|
+
if (age < policy.minAgeMs) {
|
|
87
|
+
return keep("too-young", `${mergedReason}, but touched ${formatAgo(f.lastTouched, f.now)} (minAge ${formatDuration(policy.minAgeMs)})`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (f.dirty) {
|
|
91
|
+
if (policy.onDirty === "keep" && !policy.force) {
|
|
92
|
+
return keep("dirty", `${mergedReason}, but has ${f.dirtyCount} uncommitted change${f.dirtyCount === 1 ? "" : "s"}`);
|
|
93
|
+
}
|
|
94
|
+
risks.push("dirty");
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
action: "reclaim",
|
|
98
|
+
reason: mergedReason,
|
|
99
|
+
code: f.merge.kind,
|
|
100
|
+
risks,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Decide whether a local branch with no worktree should be deleted.
|
|
105
|
+
*
|
|
106
|
+
* Deleting a branch only drops a pointer, so this is cheaper to get wrong than
|
|
107
|
+
* a worktree — but it can still orphan commits, so unmerged branches are never
|
|
108
|
+
* touched and closed-PR branches get archived like worktrees do.
|
|
109
|
+
*/
|
|
110
|
+
export function decideBranch(f, policy) {
|
|
111
|
+
if (f.isDefault)
|
|
112
|
+
return keep("default-branch", "the default branch");
|
|
113
|
+
if (f.isCurrent)
|
|
114
|
+
return keep("current-branch", "currently checked out");
|
|
115
|
+
if (f.protectedBranch)
|
|
116
|
+
return keep("protected-branch", "matches protectBranches");
|
|
117
|
+
if (f.hasWorktree)
|
|
118
|
+
return keep("has-worktree", "still checked out in a worktree");
|
|
119
|
+
switch (f.merge.kind) {
|
|
120
|
+
case "merged-ancestor":
|
|
121
|
+
return { action: "reclaim", reason: `merged into ${f.merge.base}`, code: f.merge.kind, risks: [] };
|
|
122
|
+
case "merged-pr":
|
|
123
|
+
return { action: "reclaim", reason: `PR #${f.merge.pr.number} merged`, code: f.merge.kind, risks: [] };
|
|
124
|
+
case "merged-pr-extra": {
|
|
125
|
+
const detail = `PR #${f.merge.pr.number} merged, local tip has ${f.merge.extra} extra commit(s)`;
|
|
126
|
+
if (policy.onExtraCommits === "keep" && !policy.force)
|
|
127
|
+
return keep("extra-commits", detail);
|
|
128
|
+
return { action: "reclaim", reason: detail, code: f.merge.kind, risks: ["extra-commits"] };
|
|
129
|
+
}
|
|
130
|
+
case "closed-pr": {
|
|
131
|
+
const detail = `PR #${f.merge.pr.number} closed without merging`;
|
|
132
|
+
if (policy.onClosedPr === "keep" && !policy.force)
|
|
133
|
+
return keep("closed-pr", detail);
|
|
134
|
+
const closedAt = f.merge.pr.closedAt;
|
|
135
|
+
if (!policy.force && closedAt !== null && f.now - closedAt < policy.closedPrGraceMs) {
|
|
136
|
+
return keep("closed-pr-grace", `${detail} ${formatAgo(closedAt, f.now)} — still in the grace window`);
|
|
137
|
+
}
|
|
138
|
+
return { action: "reclaim", reason: detail, code: f.merge.kind, risks: ["closed-pr"] };
|
|
139
|
+
}
|
|
140
|
+
case "open-pr":
|
|
141
|
+
return keep("open-pr", `PR #${f.merge.pr.number} is still open`);
|
|
142
|
+
case "unmerged":
|
|
143
|
+
return keep("unmerged", "not merged");
|
|
144
|
+
case "no-branch":
|
|
145
|
+
return keep("no-branch", "no branch");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=decide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decide.js","sourceRoot":"","sources":["../../src/core/decide.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Logger } from "../util/log.js";
|
|
2
|
+
export type PrState = "OPEN" | "MERGED" | "CLOSED";
|
|
3
|
+
export interface PrRef {
|
|
4
|
+
number: number;
|
|
5
|
+
state: PrState;
|
|
6
|
+
headRefName: string;
|
|
7
|
+
headRefOid: string;
|
|
8
|
+
mergedAt: number | null;
|
|
9
|
+
closedAt: number | null;
|
|
10
|
+
url: string;
|
|
11
|
+
title: string;
|
|
12
|
+
}
|
|
13
|
+
/** Pull requests for a repo, keyed by head branch name. */
|
|
14
|
+
export type PrIndex = Map<string, PrRef[]>;
|
|
15
|
+
export interface Forge {
|
|
16
|
+
readonly kind: string;
|
|
17
|
+
/**
|
|
18
|
+
* `null` means "no information available" (no remote, no CLI, offline) which
|
|
19
|
+
* callers must treat as "unknown", never as "no PR exists".
|
|
20
|
+
*/
|
|
21
|
+
lookup(repo: string): Promise<PrIndex | null>;
|
|
22
|
+
readonly unavailableReason: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface ForgeOptions {
|
|
25
|
+
kind: "github" | "none";
|
|
26
|
+
cacheTtl: string;
|
|
27
|
+
logger?: Logger;
|
|
28
|
+
/** Ignore cached answers (used by `--refresh`). */
|
|
29
|
+
refresh?: boolean;
|
|
30
|
+
limit?: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function createForge(opts: ForgeOptions): Forge;
|
|
33
|
+
/**
|
|
34
|
+
* Pick the PR that decides a branch's fate. A branch name can be reused across
|
|
35
|
+
* several PRs, so prefer a merged PR whose head sha still matches the local tip,
|
|
36
|
+
* then any merged PR, then the newest.
|
|
37
|
+
*/
|
|
38
|
+
export declare function selectPr(prs: readonly PrRef[] | undefined, localTip: string | null): PrRef | null;
|
|
39
|
+
//# sourceMappingURL=forge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forge.d.ts","sourceRoot":"","sources":["../../src/core/forge.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAM7C,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnD,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,2DAA2D;AAC3D,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAE3C,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC9C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,KAAK,CAKrD;AAuHD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAWjG"}
|