cyber-agentkit 0.0.0-stage → 1.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.
@@ -0,0 +1,690 @@
1
+ import { t as HarnessId } from "./harness-id-BgKL-x6C.js";
2
+ //#region src/worktrees/exec.d.ts
3
+ /**
4
+ * Runs a command and resolves its trimmed stdout, or `null` on any failure. Every git and forge call
5
+ * in this folder goes through it, so a caller can drive the whole worktree layer with a fake or with
6
+ * its own environment (a pinned `GIT_CONFIG_GLOBAL`, a different `PATH`).
7
+ */
8
+ type Exec = (cmd: string, args: readonly string[]) => Promise<string | null>;
9
+ /** The default `Exec`: `execFile` with stderr captured, never inherited, because routine failures
10
+ * (no `origin/HEAD`, a branch with no upstream) would otherwise spam the caller's terminal. */
11
+ export declare const nodeExec: Exec;
12
+ //#endregion
13
+ //#region src/worktrees/landed.d.ts
14
+ /**
15
+ * Which signal established that a branch's work has landed on the default branch, in the cost order
16
+ * the signals run. Each is positive-only: a signal that cannot match never contributes a `false`, so
17
+ * two signals can never contradict each other.
18
+ *
19
+ * - `ancestor`: the branch tip is an ancestor of the default branch (`git branch --merged`).
20
+ * - `upstream-gone`: the branch's remote-tracking ref has disappeared (`[gone]`), meaning the forge
21
+ * merged the pull request and deleted its head branch. Only as fresh as the caller's last
22
+ * `git fetch --prune`; this module never fetches.
23
+ * - `squash-patch`: the branch, collapsed to one commit, is already applied on the default branch
24
+ * (`git cherry`). Matches a clean squash or rebase merge, not a hand-edited one.
25
+ * - `forge`: the forge reports a merged pull request for the branch. Needs network and auth, so it
26
+ * runs only when the caller passes a `ForgeMergedProbe`.
27
+ */
28
+ type LandedSignal = 'ancestor' | 'upstream-gone' | 'squash-patch' | 'forge';
29
+ /** Asks the forge whether `branch` is the head of a merged pull request. `undefined` means the forge
30
+ * could not say, which, like `false`, clears nothing. */
31
+ type ForgeMergedProbe = (branch: string) => Promise<boolean | undefined>;
32
+ /**
33
+ * A `ForgeMergedProbe` backed by the GitHub CLI: `gh pr list --head <branch> --state merged`. Every
34
+ * way it can fail (no `gh`, no auth, no network, a non-GitHub origin) resolves `undefined`.
35
+ */
36
+ export declare function ghForgeMergedProbe(exec: Exec, primaryRoot: string): ForgeMergedProbe;
37
+ //#endregion
38
+ //#region src/worktrees/lease.d.ts
39
+ /** A held worktree: what `acquire` hands out and `release` takes back. */
40
+ interface Lease {
41
+ /** The worktree root, as `WorktreeEntry.root` gives it. */
42
+ worktree: string;
43
+ leaseId: string;
44
+ holder: string;
45
+ /**
46
+ * The repo's git common dir, recorded at claim so `release` can still clear the lock after the
47
+ * worktree's directory is gone. Absent on a hand-built lease; then the checkout must exist.
48
+ */
49
+ commonDir?: string | undefined;
50
+ }
51
+ /**
52
+ * The file operations the lease store performs on git's `locked` file, injected so a caller can
53
+ * sandbox them or a test can stage the race with `git worktree lock` (E-GIT-L5). Paths are absolute.
54
+ */
55
+ interface LeaseFs {
56
+ /** Create the file only if nothing is there; `false` when something already is. */
57
+ createExclusive(path: string, text: string): Promise<boolean>;
58
+ /** The file's text, or `undefined` when it does not exist. */
59
+ readText(path: string): Promise<string | undefined>;
60
+ /** Delete the file; a no-op when it is already gone. */
61
+ remove(path: string): Promise<void>;
62
+ }
63
+ /** The default `LeaseFs`, on `node:fs/promises`. */
64
+ export declare const nodeLeaseFs: LeaseFs;
65
+ interface LeaseStoreOptions {
66
+ exec?: Exec | undefined;
67
+ /** Defaults to `nodeLeaseFs`. */
68
+ fs?: LeaseFs | undefined;
69
+ }
70
+ /**
71
+ * `$GIT_COMMON_DIR/worktrees/<id>/locked` for a linked worktree, or `undefined` when git cannot say.
72
+ * The `<id>` is git's admin folder name, which need not match the basename, so it is read from
73
+ * `--git-dir` rather than built. When the checkout is gone, `commonDir` finds the admin folder by the
74
+ * `gitdir` pointer it keeps, so a lease on a vanished worktree can still be cleared.
75
+ */
76
+ export declare function leaseFile(worktreeRoot: string, exec?: Exec, commonDir?: string | undefined): Promise<string | undefined>;
77
+ /**
78
+ * Claim a worktree: exclusive-create its `locked` file with the lease as a one-line JSON reason, which
79
+ * git then honours as a lock (E-GIT-L1, E-GIT-L2, E-GIT-L3), and read it back. `git worktree lock`
80
+ * checks then truncates, so it can overwrite a lease created inside its window (E-GIT-L5); the read
81
+ * back catches that. `undefined` when the worktree is already locked or the claim was lost.
82
+ */
83
+ export declare function claimLease(worktreeRoot: string, holder: string, options?: LeaseStoreOptions & {
84
+ leaseId?: string | undefined;
85
+ }): Promise<Lease | undefined>;
86
+ /** Whether the worktree's `locked` file still records this lease. Checked again before a destructive
87
+ * step, since a manual `git worktree unlock` or a racing `lock` can take it away (E-GIT-L4, E-GIT-L5). */
88
+ export declare function holdsLease(lease: Lease, options?: LeaseStoreOptions): Promise<boolean>;
89
+ type ReleaseResult = {
90
+ released: true;
91
+ } |
92
+ /** The `locked` file no longer records this lease: someone unlocked it, broke it with
93
+ * `remove -f -f` (E-GIT-L4), or locked over it. Reported, not thrown: that is the user's override. */
94
+ {
95
+ released: false;
96
+ reason: 'lost';
97
+ };
98
+ /**
99
+ * Give a lease back by deleting the `locked` file, only when it still records this `leaseId`. It does
100
+ * not recycle: an occupant such as a judge may still be working there, so the next `acquire` recycles
101
+ * after probing.
102
+ */
103
+ export declare function release(lease: Lease, options?: LeaseStoreOptions): Promise<ReleaseResult>;
104
+ //#endregion
105
+ //#region src/worktrees/list-worktrees.d.ts
106
+ /** A worktree as git reports it, plus the landed and dirty facts the reuse and cleanup checks read. */
107
+ interface WorktreeEntry {
108
+ /** Absolute checkout path, symlinks resolved. */
109
+ root: string;
110
+ /** The checked-out commit; absent for a bare entry. */
111
+ head?: string | undefined;
112
+ /** The checked-out branch, without `refs/heads/`; absent when detached or bare. */
113
+ branch?: string | undefined;
114
+ /** HEAD is detached. */
115
+ detached: boolean;
116
+ /** `false` for the primary checkout, `true` for a linked worktree. */
117
+ linked: boolean;
118
+ /** git considers the entry stale: its checkout is gone from disk. */
119
+ prunable: boolean;
120
+ /**
121
+ * The lock reason when the worktree is locked (`''` for a lock with no reason), absent when it is
122
+ * not. A lock may be a lease, a harness's own hold, or a user's.
123
+ */
124
+ locked?: string | undefined;
125
+ /**
126
+ * The branch's work has landed on the default branch. Absent when undeterminable (no branch, or no
127
+ * default branch to compare against), never `false` as a stand-in.
128
+ */
129
+ merged?: boolean | undefined;
130
+ /** Which signal established `merged: true`. */
131
+ mergedSignal?: LandedSignal | undefined;
132
+ /**
133
+ * The checkout has uncommitted changes, tracked or untracked. Absent for a prunable entry or when
134
+ * git could not answer.
135
+ */
136
+ dirty?: boolean | undefined;
137
+ }
138
+ interface PrimaryRootOptions {
139
+ /** Any directory inside the repository, the primary checkout or a linked worktree. Defaults to `.`. */
140
+ from?: string | undefined;
141
+ exec?: Exec | undefined;
142
+ }
143
+ /**
144
+ * The primary checkout's root, from the primary checkout or any linked worktree:
145
+ * `--git-common-dir` always points at the primary's `.git`.
146
+ */
147
+ export declare function primaryRoot(options?: PrimaryRootOptions): Promise<string>;
148
+ /**
149
+ * The single normalization for every path matched against another, so a symlinked repo or macOS's
150
+ * `/tmp` → `/private/tmp` still matches. Falls back to `resolve` for a path not on disk.
151
+ */
152
+ export declare function normalizeWorktreePath(path: string): Promise<string>;
153
+ interface ListWorktreesOptions {
154
+ /** The primary checkout's root; see `primaryRoot`. */
155
+ primaryRoot: string;
156
+ exec?: Exec | undefined;
157
+ /** Paths whose changes do not make a worktree dirty; see `DirtyOptions.ignore`. */
158
+ ignore?: readonly string[] | undefined;
159
+ /** The opt-in forge signal; the offline signals run either way. */
160
+ forge?: ForgeMergedProbe | undefined;
161
+ }
162
+ /** Every worktree of the repo, from `git worktree list --porcelain`, with landed and dirty facts. */
163
+ export declare function listWorktrees(options: ListWorktreesOptions): Promise<WorktreeEntry[]>;
164
+ //#endregion
165
+ //#region src/worktrees/process-source.d.ts
166
+ /**
167
+ * One process as the probe sees it. Every field but `pid` may be missing: a process can exit
168
+ * mid-read, and another user's process hides its `exe`, `cwd`, and `environ`.
169
+ */
170
+ interface ProcessInfo {
171
+ pid: number;
172
+ /** Parent pid; absent when unreadable. */
173
+ ppid?: number | undefined;
174
+ /** Resolved executable path, with any ` (deleted)` suffix removed. */
175
+ exe?: string | undefined;
176
+ /** The command line; empty for a kernel thread or an unreadable process. */
177
+ argv: readonly string[];
178
+ /** Resolved working directory, with any ` (deleted)` suffix removed. */
179
+ cwd?: string | undefined;
180
+ /** The process's environment; absent when unreadable. */
181
+ env?: Readonly<Record<string, string>> | undefined;
182
+ }
183
+ /**
184
+ * Lists every process the caller can see, or `null` when this platform has no supported way to read
185
+ * another process's executable and working directory. Inject one to run the probe on fixtures, or on
186
+ * a platform the default does not cover.
187
+ */
188
+ type ProcessSource = () => Promise<readonly ProcessInfo[] | null>;
189
+ /**
190
+ * Reads processes from a Linux `/proc` (or a mounted copy at `procRoot`). On any other platform the
191
+ * default root returns `null`: macOS would need `proc_pidinfo` (E-PROC-OS2), and Windows has no
192
+ * documented way to read another process's cwd (E-PROC-OS3).
193
+ */
194
+ export declare function procfsProcessSource(procRoot?: string): ProcessSource;
195
+ //#endregion
196
+ //#region src/worktrees/session-signatures.d.ts
197
+ /** A harness the process probe recognises: the detected harnesses plus two seen only as processes. */
198
+ type SessionHarnessId = HarnessId | 'goose' | 'antigravity-cli';
199
+ //#endregion
200
+ //#region src/worktrees/occupancy.d.ts
201
+ /** A live agent session working inside a worktree. A wrapper and its native or relaunched child are
202
+ * one session (E-PROC-KILO1, E-PROC-GEM1). */
203
+ interface Session {
204
+ harness: SessionHarnessId;
205
+ /** The session's top process: the wrapper when there is one. */
206
+ pid: number;
207
+ /** Every process of the session, the wrapper and its child; any one inside the worktree counts. */
208
+ pids: readonly number[];
209
+ /** The session id, when one of its tool processes carries it in the harness's link variable. */
210
+ sessionId?: string | undefined;
211
+ /** Evidence IDs the match rests on. */
212
+ research: readonly string[];
213
+ }
214
+ /**
215
+ * Why a process left in a worktree was reported:
216
+ * - `session-gone`: its link variable names no live session (E-PROC-CC2, E-PROC-CX2).
217
+ * - `helper-orphaned`: a per-session helper, such as Cursor's worker, outlived its session
218
+ * (E-PROC-CUR3).
219
+ * - `harness-idle`: a helper shared by every session of a harness, such as Cline's hub, with no
220
+ * session of that harness alive (E-PROC-CLINE1).
221
+ * - `no-link`: no live session above it and no link variable, so orphaned and user-started look the
222
+ * same (cline, OpenHands, crush tool processes, or a user's own terminal).
223
+ * - `unresolved-link`: its session id matches none known, but a live session of that harness has not
224
+ * revealed its id, so the process may still be that session's.
225
+ * - `env-unreadable`: no live session above it and its environment could not be read.
226
+ */
227
+ type LeftoverReason = 'session-gone' | 'helper-orphaned' | 'harness-idle' | 'no-link' | 'unresolved-link' | 'env-unreadable';
228
+ /** A non-session process inside a worktree with no live session above it. Reported, never killed. */
229
+ interface LeftoverProcess {
230
+ pid: number;
231
+ ppid?: number | undefined;
232
+ argv: readonly string[];
233
+ cwd: string;
234
+ /** The harness its link variable or helper signature names, when known. */
235
+ harness?: SessionHarnessId | undefined;
236
+ reason: LeftoverReason;
237
+ }
238
+ interface WorktreeOccupancy {
239
+ /**
240
+ * A live agent session works here, so the worktree must not be recycled or removed. Dev services
241
+ * do not count. When the probe is unverified this is `strict`.
242
+ */
243
+ busy: boolean;
244
+ /** `false` when the platform's processes could not be read; `occupants` is then empty, not proof. */
245
+ verified: boolean;
246
+ /** Every live session found inside; never limited in number or role. */
247
+ occupants: Session[];
248
+ /** Processes no live session launched, provably: safe for a caller to reclaim. */
249
+ lingering: LeftoverProcess[];
250
+ /** Processes with no live session above them whose launcher cannot be told; reported, not lingering. */
251
+ unlinked: LeftoverProcess[];
252
+ }
253
+ interface ProbeOptions {
254
+ /** Where processes come from; defaults to Linux `/proc`. */
255
+ source?: ProcessSource | undefined;
256
+ }
257
+ interface OccupancyOptions {
258
+ /** Treat an unverified probe as busy. Off by default: reuse proceeds, reported as unverified. */
259
+ strict?: boolean | undefined;
260
+ /**
261
+ * Roots of worktrees nested inside this one (Claude Code puts its worktrees under
262
+ * `<repo>/.claude/worktrees/`, E-PROC-CC5); processes there belong to them, not to this one.
263
+ */
264
+ nested?: readonly string[] | undefined;
265
+ }
266
+ /** One snapshot of the process table, answering for any number of worktrees. */
267
+ interface ProcessProbe {
268
+ verified: boolean;
269
+ /** @param worktreeRoot absolute, symlinks resolved, as `WorktreeEntry.root` gives it. */
270
+ occupancy(worktreeRoot: string, options?: OccupancyOptions): WorktreeOccupancy;
271
+ }
272
+ /**
273
+ * Snapshots processes once and classifies each against the session signature table. Read-only: the
274
+ * probe never signals or kills a process. A harness missing from the table is invisible to it.
275
+ */
276
+ export declare function probeProcesses(options?: ProbeOptions): Promise<ProcessProbe>;
277
+ /**
278
+ * The live agent sessions inside a worktree, or `undefined` when the probe could not read this
279
+ * platform's processes.
280
+ */
281
+ export declare function occupants(worktreeRoot: string, options?: ProbeOptions & Pick<OccupancyOptions, 'nested'>): Promise<Session[] | undefined>;
282
+ //#endregion
283
+ //#region src/worktrees/owner.d.ts
284
+ /**
285
+ * Who a worktree belongs to. Only `self`, a worktree this library leased, may be reused or removed;
286
+ * every other owner is foreign and left alone.
287
+ *
288
+ * - `self`: locked with this library's lease, or an idle slot the library created: unlocked, at a
289
+ * library-assigned path (`slotPath`). A lease is a lock that release deletes (E-GIT-L1), so the
290
+ * slot path is what still marks a released worktree as ours.
291
+ * - `claude-code`, `codex`: recognised by a researched marker.
292
+ * - `cursor`: not produced yet. Its worktree root rests on a forum post only (E-CUR-W1, Low), so a
293
+ * Cursor worktree reports `unknown` until that is verified.
294
+ * - `user`: the primary checkout.
295
+ * - `unknown`: anything else, including Copilot CLI and herdr worktrees, whose layouts are not
296
+ * documented (E-COP-W1, E-HERDR-W1), and a lock whose reason names no one we recognise.
297
+ */
298
+ type WorktreeOwnerKind = 'self' | 'claude-code' | 'cursor' | 'codex' | 'user' | 'unknown';
299
+ interface WorktreeOwner {
300
+ owner: WorktreeOwnerKind;
301
+ /** The `.research/worktree-management` evidence IDs the classification rests on; empty when none. */
302
+ research: readonly string[];
303
+ }
304
+ /** The `library` value a lease reason carries. */
305
+ export declare const LEASE_LIBRARY = "cyber-agentkit";
306
+ /** A lease as recorded in the `locked` file: one line of JSON (E-GIT-L1, E-GIT-L2). */
307
+ interface LeaseReason {
308
+ library: typeof LEASE_LIBRARY;
309
+ leaseId: string;
310
+ holder: string;
311
+ }
312
+ /** The lease a lock reason records, or `undefined` when the lock is not this library's. */
313
+ export declare function parseLeaseReason(reason: string | undefined): LeaseReason | undefined;
314
+ interface ClassifyOwnerOptions {
315
+ /** The primary checkout's root, normalized as `WorktreeEntry.root` is (`normalizeWorktreePath`). */
316
+ primaryRoot: string;
317
+ /**
318
+ * Codex's home (`$CODEX_HOME`), normalized. Without it no worktree is recognised as Codex's: the
319
+ * research records the `$CODEX_HOME/worktrees` root but not its default.
320
+ */
321
+ codexHome?: string | undefined;
322
+ }
323
+ /** Classify a worktree's owner from its lock reason and path. Pure: reads nothing from disk. */
324
+ export declare function classifyOwner(entry: WorktreeEntry, options: ClassifyOwnerOptions): WorktreeOwner;
325
+ //#endregion
326
+ //#region src/worktrees/acquire.d.ts
327
+ /**
328
+ * Why a worktree cannot be reused, in the order the checks run (E-TH-2). The first that applies wins.
329
+ *
330
+ * - `primary`: the primary checkout, never reused.
331
+ * - `foreign`: another tool or the user owns it; see `owner`.
332
+ * - `leased`: a holder has it; see `holder`. The lease protects it whatever the probe sees.
333
+ * - `prunable`: its checkout is gone from disk.
334
+ * - `busy`: a live agent session works inside.
335
+ * - `unverified`: the probe could not read processes and the caller asked for `strict`.
336
+ * - `dirty`: uncommitted changes, or git could not say (fail closed).
337
+ * - `unmerged`: HEAD has not landed on the reset target, or that could not be told.
338
+ * - `rejected`: the caller's `available` predicate said no.
339
+ */
340
+ type SkipReason = 'primary' | 'foreign' | 'leased' | 'prunable' | 'busy' | 'unverified' | 'dirty' | 'unmerged' | 'rejected';
341
+ /** One worktree's standing for reuse. */
342
+ interface WorktreeVerdict {
343
+ worktree: WorktreeEntry;
344
+ owner: WorktreeOwner;
345
+ /** Absent when the worktree can be reused. */
346
+ skip?: SkipReason | undefined;
347
+ /** The lease holder, when `skip` is `leased`. */
348
+ holder?: string | undefined;
349
+ /** What the probe saw, when the checks reached it. */
350
+ occupancy?: WorktreeOccupancy | undefined;
351
+ /**
352
+ * `false` when the probe could not read processes, so a reusable verdict is not proof that no
353
+ * session works there. `true` when the probe answered or was never needed.
354
+ */
355
+ verified: boolean;
356
+ }
357
+ interface ExplainOptions {
358
+ /** Any directory inside the repository; ignored when `primaryRoot` is given. Defaults to `.`. */
359
+ from?: string | undefined;
360
+ /** The primary checkout's root; resolved from `from` when absent. */
361
+ primaryRoot?: string | undefined;
362
+ /** The ref a recycle resets to. Defaults to `origin/HEAD`, then the primary checkout's branch. */
363
+ base?: string | undefined;
364
+ exec?: Exec | undefined;
365
+ /** Paths whose changes do not make a worktree dirty; see `DirtyOptions.ignore`. */
366
+ ignore?: readonly string[] | undefined;
367
+ /** The opt-in forge signal for "landed"; see `ListWorktreesOptions.forge`. */
368
+ forge?: ForgeMergedProbe | undefined;
369
+ /** A process snapshot; one is taken when absent. */
370
+ probe?: ProcessProbe | undefined;
371
+ /** Treat a probe that could not read processes as busy. Off by default: reuse proceeds, unverified. */
372
+ strict?: boolean | undefined;
373
+ /** `$CODEX_HOME`, so Codex worktrees classify as `codex`; see `ClassifyOwnerOptions`. */
374
+ codexHome?: string | undefined;
375
+ /** An extra condition, checked after every safety check; it cannot make a skipped worktree reusable. */
376
+ available?: ((worktree: WorktreeEntry) => boolean | Promise<boolean>) | undefined;
377
+ }
378
+ /** Every worktree of the repo with the reason it cannot be reused, or none when it can. */
379
+ export declare function explain(options?: ExplainOptions): Promise<WorktreeVerdict[]>;
380
+ /** What a `WorktreeCreator` is asked to make. */
381
+ interface CreateWorktreeRequest {
382
+ primaryRoot: string;
383
+ /** The library-chosen path, `<parent>/<repo>.worktrees/<repo>-<n>`; the creator must use it. */
384
+ path: string;
385
+ /** The ref to start from. */
386
+ base: string;
387
+ /** The branch to check out: an existing one, or a new one at `base`. Detached at `base` when absent. */
388
+ branch?: string | undefined;
389
+ }
390
+ /**
391
+ * Makes the worktree at the library-chosen path, so a caller can create it through another tool,
392
+ * such as herdr, which binds only worktrees it created itself (E-MUX-7). Throw on failure.
393
+ */
394
+ type WorktreeCreator = (request: CreateWorktreeRequest) => Promise<void>;
395
+ /**
396
+ * Undoes what a `WorktreeCreator` did besides the checkout itself, such as a herdr workspace bound to
397
+ * the path. `acquire` calls it when the slot it just created lost its lease claim: the checkout may
398
+ * now belong to whoever won the claim (E-GIT-L5), so this must leave the worktree and its directory
399
+ * alone. Failures are swallowed so the retry still runs.
400
+ */
401
+ type WorktreeCreatorUndo = (request: CreateWorktreeRequest) => Promise<void>;
402
+ /** The default `WorktreeCreator`: `git worktree add`. */
403
+ export declare function gitWorktreeCreator(exec?: Exec): WorktreeCreator;
404
+ interface AcquireOptions extends ExplainOptions {
405
+ /** Who holds the lease, such as a Captain or Pod; recorded in the lock reason. */
406
+ holder: string;
407
+ /** The branch to work on: an existing one, or a new one at `base`. Detached at `base` when absent. */
408
+ branch?: string | undefined;
409
+ /** The most slots the repo may have; a new one is created only below it. Unlimited when absent. */
410
+ max?: number | undefined;
411
+ /** Defaults to `gitWorktreeCreator(exec)`. */
412
+ create?: WorktreeCreator | undefined;
413
+ /** Called when a slot `create` made lost its lease claim; see `WorktreeCreatorUndo`. */
414
+ undoCreate?: WorktreeCreatorUndo | undefined;
415
+ /** The lease store's file operations; see `LeaseFs`. */
416
+ fs?: LeaseFs | undefined;
417
+ /** Makes lease ids; defaults to a random UUID. */
418
+ newLeaseId?: (() => string) | undefined;
419
+ }
420
+ interface AcquireResult extends Lease {
421
+ /** `true` when an idle worktree was recycled, `false` when a new one was created. A reused path
422
+ * carries path-keyed harness state, so a "continue" there resumes the previous task (E-PROC-CC6). */
423
+ reused: boolean;
424
+ /** The branch now checked out; absent when detached. */
425
+ branch?: string | undefined;
426
+ /** The branch a reused worktree had before the recycle. */
427
+ previousBranch?: string | undefined;
428
+ /** That branch was merged and has been deleted. */
429
+ previousBranchDeleted?: boolean | undefined;
430
+ /** `false` when the reused worktree was not checked for live sessions because the probe could not
431
+ * read processes. */
432
+ verified: boolean;
433
+ /** Dev services left running in a reused worktree with no live session behind them. Never killed. */
434
+ lingering: LeftoverProcess[];
435
+ }
436
+ type AcquireErrorCode = 'pool-full' | 'no-base' | 'contended';
437
+ export declare class AcquireError extends Error {
438
+ readonly code: AcquireErrorCode;
439
+ /** The skip reason for every worktree, from the last look. */
440
+ readonly verdicts: readonly WorktreeVerdict[];
441
+ constructor(code: AcquireErrorCode, message: string,
442
+ /** The skip reason for every worktree, from the last look. */
443
+ verdicts: readonly WorktreeVerdict[]);
444
+ }
445
+ /**
446
+ * Lease a worktree: recycle an idle one of ours when there is one, otherwise create one at the next
447
+ * free slot if under `max`. Never fetches and never kills a process.
448
+ */
449
+ export declare function acquire(options: AcquireOptions): Promise<AcquireResult>;
450
+ //#endregion
451
+ //#region src/worktrees/dirty.d.ts
452
+ interface DirtyOptions {
453
+ exec: Exec;
454
+ /**
455
+ * Paths, relative to the worktree root, whose changes do not count — a tool's own marker file, such
456
+ * as cyberlegion's `.agents/cyberlegion/config.json`. Passed to git as `:(exclude)` pathspecs.
457
+ */
458
+ ignore?: readonly string[] | undefined;
459
+ }
460
+ /**
461
+ * Whether a checkout has uncommitted changes, tracked or untracked, or `undefined` when git could not
462
+ * say. `undefined` is not `false`: a caller deciding whether a worktree is safe to reuse must not read
463
+ * an unanswered question as a clean tree.
464
+ *
465
+ * `--untracked-files=all` is explicit because a repo's `status.showUntrackedFiles=no` would otherwise
466
+ * hide untracked work.
467
+ */
468
+ export declare function readDirty(worktreeRoot: string, options: DirtyOptions): Promise<boolean | undefined>;
469
+ //#endregion
470
+ //#region src/worktrees/naming.d.ts
471
+ /**
472
+ * Where the library puts a repo's worktrees: `<parent>/<repo>.worktrees`, a sibling of the primary
473
+ * checkout (E-MUX-2, E-LEG-1). Every worktree the library creates is a slot in this folder.
474
+ */
475
+ export declare function worktreesDir(primaryRoot: string): string;
476
+ /**
477
+ * The path of slot `n`: `<parent>/<repo>.worktrees/<repo>-<n>`. The library assigns `n` and the
478
+ * caller cannot, so the name stays meaningless and true for the worktree's whole life; what it is
479
+ * for lives in its branch and lease holder, which change on reuse (decision 2026-10-05, E-TH-7).
480
+ */
481
+ export declare function slotPath(primaryRoot: string, n: number): string;
482
+ /**
483
+ * The slot number of a worktree root, or `undefined` when the root is not one of the library's slots.
484
+ * Both paths are normalized (`normalizeWorktreePath`). `n` is a positive integer with no leading
485
+ * zero, so `repo-01` is not slot 1.
486
+ */
487
+ export declare function slotNumber(primaryRoot: string, worktreeRoot: string): number | undefined;
488
+ //#endregion
489
+ //#region src/worktrees/prune-worktrees.d.ts
490
+ /**
491
+ * Why a worktree was left in place, in the fail-closed order the checks run (E-MUX-5, E-TH-2):
492
+ *
493
+ * - `primary`: the primary checkout. Never removed, with no override.
494
+ * - `foreign`: owned by another tool or person (`classifyOwner`), including a worktree off this library's slot paths.
495
+ * - `leased`: held by this library's lease. git itself refuses to remove it (E-GIT-L3); `release`
496
+ * it first.
497
+ * - `prunable`: its checkout is already gone; `git worktree prune` collects the entry.
498
+ * - `busy`: a live agent session works inside.
499
+ * - `unverified`: the process probe could not read this platform, and the caller kept the strict
500
+ * rule.
501
+ * - `dirty`: uncommitted changes, tracked or untracked.
502
+ * - `dirty-unknown`: git could not say whether it is clean.
503
+ * - `unmerged`: its branch has not landed on the default branch.
504
+ * - `merge-unknown`: whether it landed cannot be told (detached HEAD, or no default branch).
505
+ * - `unlisted`: only `removeWorktree` reports it: the named path is no worktree of this repository.
506
+ */
507
+ type PruneSkipReason = 'primary' | 'foreign' | 'leased' | 'prunable' | 'busy' | 'unverified' | 'dirty' | 'dirty-unknown' | 'unmerged' | 'merge-unknown' | 'unlisted';
508
+ interface PruneOutcome {
509
+ root: string;
510
+ branch?: string | undefined;
511
+ owner: WorktreeOwnerKind;
512
+ /**
513
+ * - `candidate`: passed every check; a dry run stops here.
514
+ * - `removed`: `git worktree remove` succeeded.
515
+ * - `failed`: passed every check, but git refused, or the tree changed before removal.
516
+ * - `skipped`: see `reason`.
517
+ */
518
+ status: 'candidate' | 'removed' | 'failed' | 'skipped';
519
+ reason?: PruneSkipReason | undefined;
520
+ /** The probe could not read this platform, and the caller opted out of the strict rule. */
521
+ unverified?: true | undefined;
522
+ /** Live agent sessions found inside. */
523
+ occupants: Session[];
524
+ /** Dev services no live session launched: the caller may reclaim them. Never killed. */
525
+ lingering: LeftoverProcess[];
526
+ /** Processes whose launcher cannot be told. Reported, never killed. */
527
+ unlinked: LeftoverProcess[];
528
+ }
529
+ interface PruneReport {
530
+ /** `false` for a dry run. */
531
+ applied: boolean;
532
+ /** One outcome per considered worktree, in `git worktree list` order. */
533
+ worktrees: PruneOutcome[];
534
+ /** `git worktree prune` succeeded; absent on a dry run. */
535
+ pruned?: boolean | undefined;
536
+ }
537
+ interface PruneWorktreesOptions {
538
+ /** The primary checkout's root; see `primaryRoot`. */
539
+ primaryRoot: string;
540
+ /** Remove the candidates and run `git worktree prune`. Off by default: a dry run. */
541
+ apply?: boolean | undefined;
542
+ /** Consider only these worktree roots; every worktree when absent. */
543
+ roots?: readonly string[] | undefined;
544
+ /**
545
+ * Skip every worktree when the process probe cannot read this platform. On by default, since
546
+ * removal cannot be undone; `false` proceeds and marks each outcome `unverified`.
547
+ */
548
+ strict?: boolean | undefined;
549
+ exec?: Exec | undefined;
550
+ /** Paths whose changes do not make a worktree dirty; see `DirtyOptions.ignore`. */
551
+ ignore?: readonly string[] | undefined;
552
+ /** The opt-in forge signal for landed detection. */
553
+ forge?: ForgeMergedProbe | undefined;
554
+ /** Where processes come from; defaults to Linux `/proc`. */
555
+ source?: ProcessSource | undefined;
556
+ /** Codex's home, normalized; see `ClassifyOwnerOptions.codexHome`. */
557
+ codexHome?: string | undefined;
558
+ }
559
+ /**
560
+ * Removes the worktrees this library owns that nothing needs any more: unleased, idle, clean, and
561
+ * landed. A dry run unless `apply` is set. Never touches the primary checkout, a foreign worktree, a
562
+ * leased one, or a busy one, and never kills a process: lingering services are reported so the caller
563
+ * can reclaim them (E-TH-5 is the counterexample).
564
+ *
565
+ * An unleased worktree carries no record of its owner, since the lease is the only one this library
566
+ * writes; `classifyOwner` recognises it as this library's by its slot path (`slotPath`).
567
+ */
568
+ export declare function pruneWorktrees(options: PruneWorktreesOptions): Promise<PruneReport>;
569
+ //#endregion
570
+ //#region src/worktrees/remove-worktree.d.ts
571
+ interface RemoveWorktreeOptions {
572
+ /** The primary checkout's root; see `primaryRoot`. */
573
+ primaryRoot: string;
574
+ /** The worktree to remove, by path. Symlinks and trailing separators are normalized. */
575
+ root: string;
576
+ /**
577
+ * Remove it with `git worktree remove --force`. `true` waives foreign, `prunable`, dirty, and unmerged,
578
+ * but still skips a busy or `unverified` worktree. `'in-use'` waives those two as well, reporting the
579
+ * occupants and never killing them. Off by default: the same fail-closed checks `pruneWorktrees` runs.
580
+ * The primary checkout and a leased worktree are never removed, in any mode.
581
+ */
582
+ force?: boolean | 'in-use' | undefined;
583
+ /**
584
+ * Skip a busy worktree when the process probe cannot read this platform. On by default; `false`
585
+ * proceeds and marks the outcome `unverified`. Moot under `force: 'in-use'`, which does not consult it.
586
+ */
587
+ strict?: boolean | undefined;
588
+ exec?: Exec | undefined;
589
+ /** Paths whose changes do not make a worktree dirty; see `DirtyOptions.ignore`. */
590
+ ignore?: readonly string[] | undefined;
591
+ /** The opt-in forge signal for landed detection. */
592
+ forge?: ForgeMergedProbe | undefined;
593
+ /** Where processes come from; defaults to Linux `/proc`. */
594
+ source?: ProcessSource | undefined;
595
+ /** Codex's home, normalized; see `ClassifyOwnerOptions.codexHome`. */
596
+ codexHome?: string | undefined;
597
+ }
598
+ /**
599
+ * Removes one worktree the caller names, the single-target counterpart of `pruneWorktrees`, and
600
+ * reports the same `PruneOutcome` with a skip `reason`. The caller naming it is what a prune lacks, so
601
+ * the landed check can be waived with `force`, and the idle check with `force: 'in-use'`; ownership cannot:
602
+ *
603
+ * | worktree | without `force` | `force: true` | `force: 'in-use'` |
604
+ * | --- | --- | --- | --- |
605
+ * | the primary checkout | `primary` | `primary` | `primary` |
606
+ * | held by this library's lease | `leased`; `release` it first | `leased` | `leased`; the lease is never broken |
607
+ * | foreign (another tool, person, or lock) | `foreign` | removed, unless git refuses a locked one: `failed` | same |
608
+ * | a live agent session inside | `busy` (or `unverified`) | `busy` (or `unverified`) | removed; the sessions are reported, never killed |
609
+ * | checkout already gone | `prunable` | `git worktree remove --force` is tried | same |
610
+ * | dirty or unmerged | the matching reason | removed | removed |
611
+ * | a path that is no worktree of this repository | `unlisted` | `unlisted` | `unlisted` |
612
+ *
613
+ * `--force` is passed once and `-f -f` never: one refuses a locked worktree, so a lease taken after the
614
+ * listing holds (E-GIT-L3, E-GIT-L4). Never kills a process; lingering services are reported so the
615
+ * caller can reclaim them. Always applies: there is no dry run, since the caller named the target.
616
+ */
617
+ export declare function removeWorktree(options: RemoveWorktreeOptions): Promise<PruneOutcome>;
618
+ //#endregion
619
+ //#region src/worktrees/seed-worktree.d.ts
620
+ /**
621
+ * The file operations `seedWorktree` performs, injected so a caller can dry-run, sandbox, or log
622
+ * them. Paths are absolute. Nothing here runs a command: the include file is data, never a script
623
+ * (research: 'E-TH-4').
624
+ */
625
+ interface SeedFs {
626
+ /** The file's text, or `undefined` when it does not exist. */
627
+ readText(path: string): Promise<string | undefined>;
628
+ /** Whether anything — file, directory, or link — is at the path. */
629
+ exists(path: string): Promise<boolean>;
630
+ /** Create a directory and its parents; a no-op when it exists. */
631
+ mkdirp(path: string): Promise<void>;
632
+ copyFile(from: string, to: string): Promise<void>;
633
+ }
634
+ /** The default `SeedFs`, on `node:fs/promises`. */
635
+ export declare const nodeSeedFs: SeedFs;
636
+ interface SeedWorktreeOptions {
637
+ exec: Exec;
638
+ /** Defaults to `nodeSeedFs`. */
639
+ fs?: SeedFs | undefined;
640
+ /**
641
+ * Replace a file the worktree already has. Off by default: a recycled worktree keeps its ignored
642
+ * files (a recycle runs `clean -fd` without `-x`, research: 'E-TH-3'), and its own `.env` may have
643
+ * been edited on purpose.
644
+ */
645
+ overwrite?: boolean | undefined;
646
+ }
647
+ type SeedSkipReason =
648
+ /** Matches the include file but is not gitignored, so a checkout already carries it or it is
649
+ * untracked work that belongs to the source checkout (research: 'E-CC-W2'). */
650
+ 'not-ignored' |
651
+ /** The worktree already has something at that path, and `overwrite` is off. */
652
+ 'exists' |
653
+ /** The copy threw; `error` holds the message. */
654
+ 'failed';
655
+ interface SeedSkip {
656
+ /** Relative to the checkout root, with `/` separators, as git prints it. */
657
+ path: string;
658
+ reason: SeedSkipReason;
659
+ error?: string | undefined;
660
+ }
661
+ interface SeedInventory {
662
+ /**
663
+ * `absent` when the source has no `.worktreeinclude`, so nothing was attempted; `unknown` when git
664
+ * could not list the candidates, so nothing was copied and nothing is known to be missing.
665
+ */
666
+ include: 'present' | 'absent' | 'unknown';
667
+ /** Paths copied, relative to the checkout root. */
668
+ copied: string[];
669
+ skipped: SeedSkip[];
670
+ }
671
+ /** The include file's name and place: the project root, `.gitignore` syntax (research: 'E-CC-W2'). */
672
+ export declare const WORKTREE_INCLUDE = ".worktreeinclude";
673
+ /**
674
+ * Copies the gitignored files a `.worktreeinclude` names from a source checkout (normally the primary)
675
+ * into a new or recycled worktree, and reports what it copied and what it skipped.
676
+ *
677
+ * Claude Code's semantics (research: 'E-CC-W2'): the file sits at the project root and uses
678
+ * `.gitignore` syntax, and only a file that matches a pattern *and* is gitignored is copied, so
679
+ * tracked files are never duplicated. Git does the matching here, so negation, anchoring, and
680
+ * directory patterns behave exactly as they do in `.gitignore`. Inside a wholly ignored directory, a
681
+ * pattern that starts with `**` and a slash matches every file below it here, while Claude Code reaches
682
+ * in only when the directory's path holds the pattern's first name (research: 'E-CC-W6'), so this can
683
+ * copy a superset of what Claude Code would.
684
+ *
685
+ * The include file is read from the source's working tree, as Claude Code does, not from its
686
+ * committed HEAD as Treehouse does (research: 'E-TH-4'), so an uncommitted edit takes effect.
687
+ */
688
+ export declare function seedWorktree(sourceRoot: string, worktreeRoot: string, options: SeedWorktreeOptions): Promise<SeedInventory>;
689
+ //#endregion
690
+ export type { AcquireErrorCode, AcquireOptions, AcquireResult, ClassifyOwnerOptions, CreateWorktreeRequest, DirtyOptions, Exec, ExplainOptions, ForgeMergedProbe, LandedSignal, Lease, LeaseFs, LeaseReason, LeaseStoreOptions, LeftoverProcess, LeftoverReason, ListWorktreesOptions, OccupancyOptions, PrimaryRootOptions, ProbeOptions, ProcessInfo, ProcessProbe, ProcessSource, PruneOutcome, PruneReport, PruneSkipReason, PruneWorktreesOptions, ReleaseResult, RemoveWorktreeOptions, SeedFs, SeedInventory, SeedSkip, SeedSkipReason, SeedWorktreeOptions, Session, SessionHarnessId, SkipReason, WorktreeCreator, WorktreeCreatorUndo, WorktreeEntry, WorktreeOccupancy, WorktreeOwner, WorktreeOwnerKind, WorktreeVerdict };