@titan-design/worktree 0.0.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/LICENSE +21 -0
- package/README.md +13 -0
- package/dist/index.d.ts +359 -0
- package/dist/index.js +877 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Henry Jewkes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @titan-design/worktree
|
|
2
|
+
|
|
3
|
+
Git worktree mechanics for headless agents: allocate one branch and one directory per agent
|
|
4
|
+
under a per-repository budget, release or park them without losing work, re-create a removed
|
|
5
|
+
tree at its recorded path, and sweep for trees nobody released.
|
|
6
|
+
|
|
7
|
+
Tier 1 of the titan-platform DAG. May import only packages in the same tier or
|
|
8
|
+
below; the `package-layers` rule in `.codewatch/check.json` enforces this in CI.
|
|
9
|
+
|
|
10
|
+
See [the reference page](../../site/reference/worktree.md) for the API and its gotchas.
|
|
11
|
+
|
|
12
|
+
Tests that create real repositories are named `*.repo.test.ts`. `pnpm test` runs them;
|
|
13
|
+
`pnpm test:watch` leaves them out.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/** Runs one `git worktree add`, resolving to its output and rejecting on failure. */
|
|
2
|
+
type WorktreeAddRunner = (args: readonly string[], cwd: string) => Promise<string>;
|
|
3
|
+
/** Five minutes: a cold checkout of a multi-gigabyte repo takes tens of seconds, so only a hang reaches it. */
|
|
4
|
+
declare const WORKTREE_ADD_TIMEOUT_MS = 300000;
|
|
5
|
+
|
|
6
|
+
/** A path inside a commit: the declaration is read from git, never from a working tree. */
|
|
7
|
+
declare const SETUP_FILE = ".agent-chat/worktree.json";
|
|
8
|
+
/** Kept in the worktree's git dir, so it is neither tracked nor counted as dirt, and goes with the worktree. */
|
|
9
|
+
declare const SETUP_LOG = "agent-chat-setup.log";
|
|
10
|
+
/** Five minutes: a cold `npm ci` takes well under that, so only a hang reaches it. */
|
|
11
|
+
declare const DEFAULT_SETUP_TIMEOUT_MS = 300000;
|
|
12
|
+
interface SetupStep {
|
|
13
|
+
command: string[];
|
|
14
|
+
timeoutMs: number;
|
|
15
|
+
}
|
|
16
|
+
interface SetupResult {
|
|
17
|
+
/** Null when the process never started or was killed by a signal. */
|
|
18
|
+
exitCode: number | null;
|
|
19
|
+
timedOut: boolean;
|
|
20
|
+
output: string;
|
|
21
|
+
}
|
|
22
|
+
type SetupRunner = (command: readonly string[], cwd: string, timeoutMs: number) => Promise<SetupResult>;
|
|
23
|
+
interface SetupTarget {
|
|
24
|
+
gitRoot: string;
|
|
25
|
+
worktree: string;
|
|
26
|
+
/** The commit the branch base resolved to; the only place a declaration is read from. */
|
|
27
|
+
baseSha: string;
|
|
28
|
+
/** False when that commit is a local HEAD rather than origin's default branch as fetched. */
|
|
29
|
+
fetched: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** An allowlist of what an install needs: the step runs with the host's authority, outside any permission profile. */
|
|
32
|
+
declare function setupEnv(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
33
|
+
/** Keys it does not know are ignored, so a newer declaration still runs on an older host. */
|
|
34
|
+
declare function parseSetupStep(text: string): SetupStep | null | string;
|
|
35
|
+
/** Its own process group, so a timeout also kills what the step spawned (npm runs scripts in children). */
|
|
36
|
+
declare const runSetupCommand: SetupRunner;
|
|
37
|
+
/**
|
|
38
|
+
* Run the repository's declared setup step in a fresh worktree, before the agent launches.
|
|
39
|
+
*
|
|
40
|
+
* The step runs with the host's authority, so its declaration comes only from origin's default
|
|
41
|
+
* branch as fetched: a branch that edits the file changes nothing until it lands.
|
|
42
|
+
*
|
|
43
|
+
* Never throws: a failed step is a warning and the spawn proceeds, since whatever
|
|
44
|
+
* depended on it (the egress pre-push hook) fails closed on its own.
|
|
45
|
+
*/
|
|
46
|
+
declare function runWorktreeSetup(target: SetupTarget, run?: SetupRunner): Promise<string[]>;
|
|
47
|
+
|
|
48
|
+
declare const DEFAULT_WORKTREE_BUDGET = 3;
|
|
49
|
+
declare const DEFAULT_BASE_PATH = ".worktrees";
|
|
50
|
+
/** Ownership marker: the sweep treats only branches carrying this prefix as its own. */
|
|
51
|
+
declare const BRANCH_PREFIX = "agent-chat/";
|
|
52
|
+
declare const DEFAULT_FETCH_TIMEOUT_MS = 15000;
|
|
53
|
+
/**
|
|
54
|
+
* Grace window between an agent exiting and its worktree becoming reclaimable.
|
|
55
|
+
*
|
|
56
|
+
* It guards the window between an agent exiting and a human noticing the
|
|
57
|
+
* unpushed commits it left behind. Release does `git branch -D`, so reclaiming
|
|
58
|
+
* inside that window turns "I'll look at it in a minute" into a dangling commit.
|
|
59
|
+
* Anchored on the exit timestamp, not on wall clock since allocation.
|
|
60
|
+
*
|
|
61
|
+
* This window and the dirty/unmerged refusal are the two things most likely to
|
|
62
|
+
* be dropped as incidental. They are not: both exist because work was lost.
|
|
63
|
+
*/
|
|
64
|
+
declare const RECLAIM_GRACE_MS = 120000;
|
|
65
|
+
interface WorktreeOptions {
|
|
66
|
+
/** Relative to the git root. */
|
|
67
|
+
basePath?: string;
|
|
68
|
+
/** Per-repository cap on allocated worktrees. A function is read on every allocation. */
|
|
69
|
+
budget?: number | (() => number);
|
|
70
|
+
branchPrefix?: string;
|
|
71
|
+
/** Bound on fetching origin's default branch before cutting a new one. */
|
|
72
|
+
fetchTimeoutMs?: number;
|
|
73
|
+
/** Bound on one `git worktree add`; the add is killed and the repo's queue moves on when it passes. */
|
|
74
|
+
addTimeoutMs?: number;
|
|
75
|
+
/** Runs each `git worktree add`; tests inject one to observe how adds interleave. */
|
|
76
|
+
runWorktreeAdd?: WorktreeAddRunner;
|
|
77
|
+
/** Runs the repository's declared setup step; tests inject one so no real install runs. */
|
|
78
|
+
runSetup?: SetupRunner;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The commit a new branch is cut from, the ref it was read from, and a warning when that ref is not origin's. */
|
|
82
|
+
interface BranchBase {
|
|
83
|
+
sha: string;
|
|
84
|
+
ref: string;
|
|
85
|
+
warning?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The main checkout's HEAD may lag origin or hold another session's unpushed
|
|
89
|
+
* commits, and a branch cut from it ships both. So cut from a fresh fetch of
|
|
90
|
+
* origin's default branch, and say so loudly when that is impossible.
|
|
91
|
+
*/
|
|
92
|
+
declare function resolveBranchBase(gitRoot: string, timeoutMs: number): Promise<BranchBase>;
|
|
93
|
+
|
|
94
|
+
/** Where a worktree an allocator created sat, as its caller recorded it. */
|
|
95
|
+
interface WorktreeRecord {
|
|
96
|
+
gitRoot: string;
|
|
97
|
+
worktree: string;
|
|
98
|
+
branch: string;
|
|
99
|
+
/** An agent adopted this tree from the allocator the record came from, so it is not that agent's to remove. */
|
|
100
|
+
adopted?: boolean;
|
|
101
|
+
}
|
|
102
|
+
/** What an allocation hands back: where the agent works, one line for its brief, and a handle for release. */
|
|
103
|
+
interface WorktreeAllocation {
|
|
104
|
+
cwd: string;
|
|
105
|
+
note: string;
|
|
106
|
+
/** Branch, worktree, gitRoot and base; flags are the string 'true'. Persist it to release later. */
|
|
107
|
+
ref: Record<string, string>;
|
|
108
|
+
/** Advisory lines for the requester. */
|
|
109
|
+
warnings?: string[];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Put a removed worktree back at its recorded path, under the allocator's budget.
|
|
113
|
+
*
|
|
114
|
+
* `claude --resume` finds a transcript only under the project dir of the cwd it
|
|
115
|
+
* starts in, and that dir is derived from the worktree path, so the path must be
|
|
116
|
+
* the original one. Every file path in the conversation points there too.
|
|
117
|
+
*/
|
|
118
|
+
declare function reattachWorktree(record: WorktreeRecord, opts?: WorktreeOptions, requireBranch?: boolean): Promise<WorktreeAllocation>;
|
|
119
|
+
/** Re-create a removed tree from its record, keeping an adopted one adopted. */
|
|
120
|
+
declare function recreateWorktree(record: WorktreeRecord, opts?: WorktreeOptions): Promise<WorktreeAllocation>;
|
|
121
|
+
|
|
122
|
+
/** One agent's request for a worktree. A caller's richer context record satisfies it structurally. */
|
|
123
|
+
interface WorktreeRequest {
|
|
124
|
+
agentName: string;
|
|
125
|
+
baseCwd: string;
|
|
126
|
+
/**
|
|
127
|
+
* A worktree the caller assigned. It is ADOPTED instead of allocated: no
|
|
128
|
+
* branch is created, no budget slot is taken, and release leaves it alone.
|
|
129
|
+
*/
|
|
130
|
+
assignedWorktree?: string;
|
|
131
|
+
/** The caller's record of allocating `assignedWorktree`, which re-creates it if it was removed. */
|
|
132
|
+
assignedRecord?: WorktreeRecord;
|
|
133
|
+
/** When the agent exited; anchors the reclaim grace window. */
|
|
134
|
+
exitedAt?: number;
|
|
135
|
+
/** Discard a leftover branch instead of adopting it. Allocation can destroy commits as release can. */
|
|
136
|
+
forceReset?: boolean;
|
|
137
|
+
}
|
|
138
|
+
interface WorktreeCheck {
|
|
139
|
+
/** Reasons the allocation would fail. */
|
|
140
|
+
refusals: string[];
|
|
141
|
+
/** Advisory lines; allocation proceeds. */
|
|
142
|
+
warnings: string[];
|
|
143
|
+
}
|
|
144
|
+
type WorktreeReleaseOutcome = {
|
|
145
|
+
released: true;
|
|
146
|
+
} | {
|
|
147
|
+
released: false;
|
|
148
|
+
refusal: string;
|
|
149
|
+
};
|
|
150
|
+
interface WorktreeAllocator {
|
|
151
|
+
check(req: WorktreeRequest): Promise<WorktreeCheck>;
|
|
152
|
+
allocate(req: WorktreeRequest): Promise<WorktreeAllocation>;
|
|
153
|
+
/** A refusal (dirty, unmerged, inside the grace window) leaves everything on disk. */
|
|
154
|
+
release(req: Pick<WorktreeRequest, "exitedAt">, alloc: {
|
|
155
|
+
ref?: Record<string, string>;
|
|
156
|
+
}, opts?: {
|
|
157
|
+
force?: boolean;
|
|
158
|
+
}): Promise<WorktreeReleaseOutcome>;
|
|
159
|
+
}
|
|
160
|
+
/** Worktree isolation for agents: one branch and one directory per agent name, under a per-repo budget. */
|
|
161
|
+
declare function createWorktreeAllocator(opts?: WorktreeOptions): WorktreeAllocator;
|
|
162
|
+
|
|
163
|
+
declare class WorktreeBudgetExhaustedError extends Error {
|
|
164
|
+
readonly allocated: number;
|
|
165
|
+
readonly budget: number;
|
|
166
|
+
constructor(allocated: number, budget: number);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Adoption is impossible: something is still holding the branch or the path.
|
|
170
|
+
*
|
|
171
|
+
* Distinct from "the branch holds work", which is recoverable by adopting it.
|
|
172
|
+
* This one means a live agent of the same name already has the worktree, or a
|
|
173
|
+
* directory is sitting in the way: cases where proceeding would clobber files
|
|
174
|
+
* nobody has agreed to lose.
|
|
175
|
+
*/
|
|
176
|
+
declare class WorktreeInUseError extends Error {
|
|
177
|
+
readonly branch: string;
|
|
178
|
+
readonly worktreePath: string;
|
|
179
|
+
constructor(branch: string, worktreePath: string);
|
|
180
|
+
}
|
|
181
|
+
/** Origin could not answer whether it holds the branch, so a fresh fork might discard real work. */
|
|
182
|
+
declare class OriginUnreachableError extends Error {
|
|
183
|
+
readonly branch: string;
|
|
184
|
+
constructor(branch: string, detail: string);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* One `git` invocation, returning null rather than throwing.
|
|
189
|
+
*
|
|
190
|
+
* git failures are routine control flow here: "is this a repository at all" is
|
|
191
|
+
* a failing command, and every caller treats a miss as an answer. Injectable so
|
|
192
|
+
* tests of callers never shell out.
|
|
193
|
+
*/
|
|
194
|
+
type GitRunner = (args: readonly string[], cwd: string) => Promise<string | null>;
|
|
195
|
+
/** A git child that inherits a dispatcher's identity variables can register as the agent that spawned it. */
|
|
196
|
+
declare const DEFAULT_STRIPPED_ENV_PREFIXES: readonly string[];
|
|
197
|
+
declare function gitChildEnv(env?: NodeJS.ProcessEnv, stripPrefixes?: readonly string[]): NodeJS.ProcessEnv;
|
|
198
|
+
declare const runGit: GitRunner;
|
|
199
|
+
/**
|
|
200
|
+
* The true repository root, resolved through worktrees.
|
|
201
|
+
*
|
|
202
|
+
* `--git-common-dir` rather than `--show-toplevel`: from inside a worktree the
|
|
203
|
+
* toplevel is that worktree, and allocating from it would nest worktrees.
|
|
204
|
+
*/
|
|
205
|
+
declare function findGitRoot(cwd: string, git?: GitRunner): Promise<string | null>;
|
|
206
|
+
/** Where a process is observably running, as git sees it, as opposed to what it says about itself. */
|
|
207
|
+
interface GitPresence {
|
|
208
|
+
gitBranch?: string;
|
|
209
|
+
/** The checkout this process's files live in. */
|
|
210
|
+
worktreePath?: string;
|
|
211
|
+
/** The repository behind the checkout; two worktrees of one repo share it. */
|
|
212
|
+
repoPath?: string;
|
|
213
|
+
isLinkedWorktree?: boolean;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Undefined outside a git repository. The toplevel and the common dir answer
|
|
217
|
+
* different questions: when they disagree, this is a linked worktree.
|
|
218
|
+
*/
|
|
219
|
+
declare function observedPresence(cwd: string, git?: GitRunner): Promise<GitPresence | undefined>;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Drop registrations whose directory is gone from disk, so a machine that was
|
|
223
|
+
* rebooted mid-run does not permanently hold budget it is not using.
|
|
224
|
+
*/
|
|
225
|
+
declare function pruneStaleWorktrees(gitRoot: string): Promise<void>;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Refuse a tree that would lose anything; otherwise remove it without --force and keep the branch.
|
|
229
|
+
* `recheck` runs after the git checks and right before the removal, so a spawn or resume that
|
|
230
|
+
* started meanwhile is caught. Returns the parked head.
|
|
231
|
+
*/
|
|
232
|
+
declare function parkWorktree(target: WorktreeRecord, recheck?: () => string | undefined): Promise<{
|
|
233
|
+
ok: true;
|
|
234
|
+
head: string;
|
|
235
|
+
} | {
|
|
236
|
+
ok: false;
|
|
237
|
+
reason: string;
|
|
238
|
+
}>;
|
|
239
|
+
|
|
240
|
+
interface ReleaseCheck {
|
|
241
|
+
name: "dirty" | "pushed" | "landed" | "gh";
|
|
242
|
+
ok: boolean;
|
|
243
|
+
detail: string;
|
|
244
|
+
}
|
|
245
|
+
interface WorktreeReleaseSafety {
|
|
246
|
+
dirty: boolean;
|
|
247
|
+
/** Commits that exist nowhere else: not on the remote, not in the base ref, and not landed. */
|
|
248
|
+
unmerged: boolean;
|
|
249
|
+
/** Every file the branch changed already matches the current base: a squash or rebase merge. */
|
|
250
|
+
landed: boolean;
|
|
251
|
+
/** Commits on the branch but not on `compareTo`; null when the range could not be counted. */
|
|
252
|
+
ahead: number | null;
|
|
253
|
+
checked: ReleaseCheck[];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Is it safe to destroy this worktree and its branch?
|
|
257
|
+
*
|
|
258
|
+
* With no remote the comparison falls back to the commit the branch forked
|
|
259
|
+
* from, since treating "no remote" as safe would silently delete every commit
|
|
260
|
+
* the agent made. Over-refusal is the failure mode we accept: `force` is one
|
|
261
|
+
* flag away.
|
|
262
|
+
*
|
|
263
|
+
* Commits that fail that count are still safe when their content has landed on
|
|
264
|
+
* the checkout's current branch (or `origin/HEAD`), which is how a squash-merged
|
|
265
|
+
* PR looks once the host deletes the remote branch. Nothing is fetched: a stale
|
|
266
|
+
* local main makes this refuse until someone pulls.
|
|
267
|
+
*/
|
|
268
|
+
declare function inspectForRelease(gitRoot: string, worktreePath: string, branch: string, baseRef: string): Promise<WorktreeReleaseSafety>;
|
|
269
|
+
/** The failed checks, as one line a coordinator can act on. */
|
|
270
|
+
declare function describeRefusal(safety: WorktreeReleaseSafety): string;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Find the worktrees an allocator is holding, and say which ones nobody is using.
|
|
274
|
+
*
|
|
275
|
+
* Release is driven by a person deciding they are done. The leak is the case
|
|
276
|
+
* where nobody decides: an agent exits, is never released, and holds its
|
|
277
|
+
* worktree and branch indefinitely.
|
|
278
|
+
*
|
|
279
|
+
* Ownership is the branch prefix, not the path: the prefix is what the allocator
|
|
280
|
+
* writes and nothing else creates. That keeps the sweep off other tools' agent
|
|
281
|
+
* worktrees, which sit on ordinary branch names and are usually locked.
|
|
282
|
+
*/
|
|
283
|
+
/** Where a worktree sits in the lifecycle, and therefore what may be done to it. */
|
|
284
|
+
type SweepStatus =
|
|
285
|
+
/** Its agent is still running. Nothing to do, and nothing safe to do. */
|
|
286
|
+
"held"
|
|
287
|
+
/** Its agent has exited, but inside the window that protects unnoticed work. */
|
|
288
|
+
| "in-grace"
|
|
289
|
+
/** Uncommitted changes, or commits that exist nowhere else. Needs a person. */
|
|
290
|
+
| "holds-work"
|
|
291
|
+
/** Nobody is using it and nothing would be lost. `reclaimWorktree` takes these. */
|
|
292
|
+
| "reclaimable";
|
|
293
|
+
/** The agent a caller says owns a found worktree. */
|
|
294
|
+
interface SweepOwner {
|
|
295
|
+
agentId: string;
|
|
296
|
+
name: string;
|
|
297
|
+
state: string;
|
|
298
|
+
lastEventAt: number;
|
|
299
|
+
exitedAt?: number;
|
|
300
|
+
}
|
|
301
|
+
/** An allocation the caller believes it still holds. */
|
|
302
|
+
interface HeldWorktree {
|
|
303
|
+
gitRoot: string;
|
|
304
|
+
branch: string;
|
|
305
|
+
/** The commit the branch was cut from; release safety compares against it when there is no remote. */
|
|
306
|
+
base?: string;
|
|
307
|
+
}
|
|
308
|
+
interface FoundWorktree {
|
|
309
|
+
gitRoot: string;
|
|
310
|
+
worktree: string;
|
|
311
|
+
branch: string;
|
|
312
|
+
}
|
|
313
|
+
interface SweptWorktree extends FoundWorktree {
|
|
314
|
+
status: SweepStatus;
|
|
315
|
+
/** Absent when no owner was found for the worktree. */
|
|
316
|
+
agent?: {
|
|
317
|
+
agentId: string;
|
|
318
|
+
name: string;
|
|
319
|
+
state: string;
|
|
320
|
+
lastEventAt: number;
|
|
321
|
+
};
|
|
322
|
+
/** One line of why it is in this state, for a human reading the report. */
|
|
323
|
+
detail: string;
|
|
324
|
+
}
|
|
325
|
+
type GitLister = (gitRoot: string) => Promise<string>;
|
|
326
|
+
interface SweepOptions {
|
|
327
|
+
/** Repositories to scan beyond the ones `held` names, which catches a tree no record points at. */
|
|
328
|
+
roots?: readonly string[];
|
|
329
|
+
held?: readonly HeldWorktree[];
|
|
330
|
+
/** Joins a found worktree to its agent; the caller owns the roster. */
|
|
331
|
+
ownerOf?: (found: FoundWorktree) => SweepOwner | undefined;
|
|
332
|
+
branchPrefix?: string;
|
|
333
|
+
list?: GitLister;
|
|
334
|
+
now?: () => number;
|
|
335
|
+
}
|
|
336
|
+
/** Every unlocked worktree in `gitRoot` whose branch carries `branchPrefix`, from git itself. */
|
|
337
|
+
declare function agentWorktreesIn(gitRoot: string, list?: GitLister, branchPrefix?: string): Promise<{
|
|
338
|
+
worktree: string;
|
|
339
|
+
branch: string;
|
|
340
|
+
}[]>;
|
|
341
|
+
/** Live means someone is in it; anything else has stopped and may be reclaimable. */
|
|
342
|
+
declare const isLive: (state: string) => boolean;
|
|
343
|
+
/** Every allocator worktree in the named and held repositories, classified. */
|
|
344
|
+
declare function sweepWorktrees(options?: SweepOptions): Promise<SweptWorktree[]>;
|
|
345
|
+
/**
|
|
346
|
+
* Destroy one swept worktree and its branch.
|
|
347
|
+
*
|
|
348
|
+
* Refuses anything not `reclaimable` unless forced, so the classification is the
|
|
349
|
+
* guard rather than advice. The grace window and the safety check already ran in
|
|
350
|
+
* the sweep, against the report the caller read, so they are not re-derived here.
|
|
351
|
+
*/
|
|
352
|
+
declare function reclaimWorktree(entry: SweptWorktree, options?: {
|
|
353
|
+
force?: boolean;
|
|
354
|
+
}): Promise<{
|
|
355
|
+
ok: boolean;
|
|
356
|
+
reason?: string;
|
|
357
|
+
}>;
|
|
358
|
+
|
|
359
|
+
export { BRANCH_PREFIX, type BranchBase, DEFAULT_BASE_PATH, DEFAULT_FETCH_TIMEOUT_MS, DEFAULT_SETUP_TIMEOUT_MS, DEFAULT_STRIPPED_ENV_PREFIXES, DEFAULT_WORKTREE_BUDGET, type FoundWorktree, type GitLister, type GitPresence, type GitRunner, type HeldWorktree, OriginUnreachableError, RECLAIM_GRACE_MS, type ReleaseCheck, SETUP_FILE, SETUP_LOG, type SetupResult, type SetupRunner, type SetupStep, type SetupTarget, type SweepOptions, type SweepOwner, type SweepStatus, type SweptWorktree, WORKTREE_ADD_TIMEOUT_MS, type WorktreeAddRunner, type WorktreeAllocation, type WorktreeAllocator, WorktreeBudgetExhaustedError, type WorktreeCheck, WorktreeInUseError, type WorktreeOptions, type WorktreeRecord, type WorktreeReleaseOutcome, type WorktreeReleaseSafety, type WorktreeRequest, agentWorktreesIn, createWorktreeAllocator, describeRefusal, findGitRoot, gitChildEnv, inspectForRelease, isLive, observedPresence, parkWorktree, parseSetupStep, pruneStaleWorktrees, reattachWorktree, reclaimWorktree, recreateWorktree, resolveBranchBase, runGit, runSetupCommand, runWorktreeSetup, setupEnv, sweepWorktrees };
|