@agentproto/worktree 0.8.1 → 0.9.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/dist/bin/worktree-agent.mjs +2 -2
- package/dist/{chunk-AGIUUFLI.mjs → chunk-6EV7WP2U.mjs} +3 -3
- package/dist/{chunk-AGIUUFLI.mjs.map → chunk-6EV7WP2U.mjs.map} +1 -1
- package/dist/{chunk-AFS6W62Z.mjs → chunk-KRQFVJPK.mjs} +46 -13
- package/dist/chunk-KRQFVJPK.mjs.map +1 -0
- package/dist/index.d.ts +564 -4
- package/dist/index.mjs +791 -17
- package/dist/index.mjs.map +1 -1
- package/dist/provider/index.mjs +1 -1
- package/package.json +6 -6
- package/dist/chunk-AFS6W62Z.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -731,6 +731,25 @@ interface ForgeClient {
|
|
|
731
731
|
* (PLAN.md §1.3 step 2, verified for #273/#312/#325/#271).
|
|
732
732
|
*/
|
|
733
733
|
ensurePullHeadFetched(prNumber: number, oid: string): Promise<void>;
|
|
734
|
+
/**
|
|
735
|
+
* Every OPEN PR/MR in the repo, in one round-trip — the bulk twin of
|
|
736
|
+
* `pullRequestsForBranch` for callers that must protect hundreds of refs at
|
|
737
|
+
* once (`branch-gc.ts`: one call per ref would be a forge request per
|
|
738
|
+
* branch). Optional so existing test doubles keep compiling; a client that
|
|
739
|
+
* doesn't implement it is treated as "open-PR detection unavailable" by
|
|
740
|
+
* those callers, never as "no open PRs".
|
|
741
|
+
*/
|
|
742
|
+
listOpenPullRequests?(): Promise<ForgePullRequestRef[]>;
|
|
743
|
+
/**
|
|
744
|
+
* Every MERGED PR/MR in the repo, in one round-trip — the bulk twin of
|
|
745
|
+
* `listOpenPullRequests` for the merged-head shortcut (`branch-gc.ts`): a
|
|
746
|
+
* branch whose tip is EXACTLY a merged PR's head commit lost nothing (that
|
|
747
|
+
* commit was reviewed and merged), so it is reclaimable without an LLM
|
|
748
|
+
* review. Optional so existing test doubles keep compiling; a client that
|
|
749
|
+
* doesn't implement it is treated as "merged-PR detection unavailable" by
|
|
750
|
+
* those callers, never as "no merged PRs".
|
|
751
|
+
*/
|
|
752
|
+
listMergedPullRequests?(): Promise<ForgePullRequestRef[]>;
|
|
734
753
|
}
|
|
735
754
|
/** A client that always reports itself unreachable — the "no gh, no token" case. */
|
|
736
755
|
declare class UnreachableForgeClient implements ForgeClient {
|
|
@@ -739,6 +758,8 @@ declare class UnreachableForgeClient implements ForgeClient {
|
|
|
739
758
|
pullRequestsForBranch(): Promise<ForgePullRequestRef[]>;
|
|
740
759
|
pullRequestsForCommit(): Promise<ForgePullRequestRef[]>;
|
|
741
760
|
ensurePullHeadFetched(): Promise<void>;
|
|
761
|
+
listOpenPullRequests(): Promise<ForgePullRequestRef[]>;
|
|
762
|
+
listMergedPullRequests(): Promise<ForgePullRequestRef[]>;
|
|
742
763
|
}
|
|
743
764
|
/** Runs `gh` in `repoRoot` so it auto-detects owner/repo from the `origin` remote there. */
|
|
744
765
|
declare class GhCliForgeClient implements ForgeClient {
|
|
@@ -749,9 +770,17 @@ declare class GhCliForgeClient implements ForgeClient {
|
|
|
749
770
|
private parseOutput;
|
|
750
771
|
pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]>;
|
|
751
772
|
pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]>;
|
|
773
|
+
listOpenPullRequests(): Promise<ForgePullRequestRef[]>;
|
|
774
|
+
listMergedPullRequests(): Promise<ForgePullRequestRef[]>;
|
|
752
775
|
ensurePullHeadFetched(prNumber: number, oid: string): Promise<void>;
|
|
753
776
|
}
|
|
754
|
-
/**
|
|
777
|
+
/**
|
|
778
|
+
* Parse `owner/repo` out of a `git remote get-url origin` value (ssh or https
|
|
779
|
+
* form). The ssh form also accepts the multi-account `~/.ssh/config` alias
|
|
780
|
+
* convention, `git@github.com-<alias>:owner/repo` (a `Host github.com-work`
|
|
781
|
+
* entry that picks a key but still points at github.com), which is what a
|
|
782
|
+
* machine juggling two GitHub identities has as its origin.
|
|
783
|
+
*/
|
|
755
784
|
declare function parseGithubOwnerRepo(remoteUrl: string): {
|
|
756
785
|
owner: string;
|
|
757
786
|
repo: string;
|
|
@@ -768,6 +797,8 @@ declare class RestForgeClient implements ForgeClient {
|
|
|
768
797
|
private pullRequestList;
|
|
769
798
|
pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]>;
|
|
770
799
|
pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]>;
|
|
800
|
+
listOpenPullRequests(): Promise<ForgePullRequestRef[]>;
|
|
801
|
+
listMergedPullRequests(): Promise<ForgePullRequestRef[]>;
|
|
771
802
|
ensurePullHeadFetched(prNumber: number, oid: string): Promise<void>;
|
|
772
803
|
}
|
|
773
804
|
/**
|
|
@@ -799,6 +830,13 @@ declare function createForgeClient(repoRoot: string): Promise<ForgeClient>;
|
|
|
799
830
|
|
|
800
831
|
type TreeState = {
|
|
801
832
|
state: "clean";
|
|
833
|
+
/**
|
|
834
|
+
* Set only when the tree is clean BECAUSE every dirty path was on the
|
|
835
|
+
* caller's noise allowlist (`ComputeTreeStateOptions.noisePaths`) — the
|
|
836
|
+
* paths a removal must restore/delete first, since git's own
|
|
837
|
+
* non-`--force` `worktree remove` still sees them as dirt.
|
|
838
|
+
*/
|
|
839
|
+
noise?: string[];
|
|
802
840
|
} | {
|
|
803
841
|
state: "dirty";
|
|
804
842
|
modified: number;
|
|
@@ -812,6 +850,15 @@ type TreeState = {
|
|
|
812
850
|
*/
|
|
813
851
|
newestMtimeMs: number | null;
|
|
814
852
|
};
|
|
853
|
+
interface ComputeTreeStateOptions {
|
|
854
|
+
/**
|
|
855
|
+
* Worktree-relative paths whose dirt is known noise (e.g. a tool's lockfile
|
|
856
|
+
* churn that shows up in every agent worktree). A tree whose ONLY dirt is
|
|
857
|
+
* on this list reads `clean` (with `noise` set). Default none — callers
|
|
858
|
+
* opt in; see `DEFAULT_GC_NOISE_PATHS` in `gc.ts` for gc's default.
|
|
859
|
+
*/
|
|
860
|
+
noisePaths?: readonly string[];
|
|
861
|
+
}
|
|
815
862
|
/**
|
|
816
863
|
* `git status --porcelain=v2` in the worktree itself, via `-C worktreePath`
|
|
817
864
|
* (tree state is per-worktree, not `repoRoot`'s). The spawn's own `cwd`,
|
|
@@ -826,7 +873,7 @@ type TreeState = {
|
|
|
826
873
|
* `worktree remove` tolerance for them (PLAN.md §0.5) — the two notions of
|
|
827
874
|
* "clean" agree by construction.
|
|
828
875
|
*/
|
|
829
|
-
declare function computeTreeState(repoRoot: string, worktreePath: string): Promise<TreeState>;
|
|
876
|
+
declare function computeTreeState(repoRoot: string, worktreePath: string, options?: ComputeTreeStateOptions): Promise<TreeState>;
|
|
830
877
|
declare const integrationStateSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
831
878
|
state: z.ZodLiteral<"fresh">;
|
|
832
879
|
checkedAt: z.ZodString;
|
|
@@ -1056,10 +1103,29 @@ interface Classification {
|
|
|
1056
1103
|
* `hold`.
|
|
1057
1104
|
*/
|
|
1058
1105
|
declare function classify(tree: TreeState, integration: IntegrationState, liveness: LivenessState, nowMs?: number): Classification;
|
|
1106
|
+
/** How far a worktree's tip has moved from the base it is compared against. */
|
|
1107
|
+
interface BaseDivergence {
|
|
1108
|
+
/** The ref the tip is compared against (`defaultBranchRef`, e.g. `origin/main`). */
|
|
1109
|
+
ref: string;
|
|
1110
|
+
/** Commits on the tip that the base doesn't have. */
|
|
1111
|
+
ahead: number;
|
|
1112
|
+
/** Commits on the base that the tip doesn't have. */
|
|
1113
|
+
behind: number;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* `git rev-list --left-right --count <base>...<head>`: one read, both sides
|
|
1117
|
+
* of the symmetric difference. `null` for a detached/unborn tip, or when git
|
|
1118
|
+
* can't resolve either side (base ref never fetched, object gone) — a
|
|
1119
|
+
* best-effort display fact, never a reason to fail a status sweep. Spawn
|
|
1120
|
+
* `cwd` is `repoRoot`, like every other read here (see `computeTreeState`).
|
|
1121
|
+
*/
|
|
1122
|
+
declare function computeBaseDivergence(repoRoot: string, head: string, baseRef: string): Promise<BaseDivergence | null>;
|
|
1059
1123
|
interface WorktreeStatusEntry {
|
|
1060
1124
|
path: string;
|
|
1061
1125
|
branch: string | null;
|
|
1062
1126
|
head: string;
|
|
1127
|
+
/** Ahead/behind vs `defaultBranchRef` — see `computeBaseDivergence`. */
|
|
1128
|
+
base: BaseDivergence | null;
|
|
1063
1129
|
tree: TreeState;
|
|
1064
1130
|
integration: IntegrationState;
|
|
1065
1131
|
liveness: LivenessState;
|
|
@@ -1086,6 +1152,8 @@ interface ComputeWorktreeStatusInput {
|
|
|
1086
1152
|
* and therefore always-"recent", delta). Defaults to `Date.now()`.
|
|
1087
1153
|
*/
|
|
1088
1154
|
nowMs?: number;
|
|
1155
|
+
/** See `ComputeTreeStateOptions.noisePaths`. Default none. */
|
|
1156
|
+
noisePaths?: readonly string[];
|
|
1089
1157
|
}
|
|
1090
1158
|
/** Computes all three axes + provenance + classification for one worktree. */
|
|
1091
1159
|
declare function computeWorktreeStatus(input: ComputeWorktreeStatusInput): Promise<WorktreeStatusEntry>;
|
|
@@ -1097,6 +1165,12 @@ interface ListWorktreeStatusesInput {
|
|
|
1097
1165
|
defaultBranchRef?: string;
|
|
1098
1166
|
sessionsPath?: string;
|
|
1099
1167
|
now?: () => string;
|
|
1168
|
+
/**
|
|
1169
|
+
* Compute only the worktrees at these paths (compared resolved) — a
|
|
1170
|
+
* single-worktree read (the per-session `worktree_status` lookup) costs one
|
|
1171
|
+
* forge round-trip instead of one per worktree in the repo. Omitted = all.
|
|
1172
|
+
*/
|
|
1173
|
+
paths?: readonly string[];
|
|
1100
1174
|
}
|
|
1101
1175
|
/** Enumerates every linked worktree of `repoRoot` (`git worktree list`) and computes its status. */
|
|
1102
1176
|
declare function listWorktreeStatuses(input: ListWorktreeStatusesInput): Promise<WorktreeStatusEntry[]>;
|
|
@@ -1231,7 +1305,17 @@ declare function classifyForGc(tree: TreeState, integration: IntegrationState, l
|
|
|
1231
1305
|
* only irreversible thing history nearly did to it (deleting the branch)
|
|
1232
1306
|
* must not happen either. See "prunable reclaim" below.
|
|
1233
1307
|
*/
|
|
1234
|
-
type GcReclaimReason = "dep-bump" | "orphan" | "prunable";
|
|
1308
|
+
type GcReclaimReason = "dep-bump" | "orphan" | "prunable" | InBaseReclaimReason;
|
|
1309
|
+
/**
|
|
1310
|
+
* `branch gc`'s proof tiers (`classifyTip`, branch-gc.ts) that promote a
|
|
1311
|
+
* clean, idle worktree out of `hold` when the forge can't: its branch's
|
|
1312
|
+
* CONTENT is provably in base even though no merged PR contains its tip (a
|
|
1313
|
+
* squash that went through another PR, a cherry-pick, a later reorg). See
|
|
1314
|
+
* "in-base promotion" below.
|
|
1315
|
+
*/
|
|
1316
|
+
type InBaseReclaimReason = "squash-merged" | "patch-merged" | "content-merged";
|
|
1317
|
+
/** gc's default noise allowlist — overridable per call via `noisePaths` (`[]` disables it). */
|
|
1318
|
+
declare const DEFAULT_GC_NOISE_PATHS: readonly string[];
|
|
1235
1319
|
/** The hold reasons this module can attach, distinct from `classify`'s snapshot-based holds. */
|
|
1236
1320
|
type GcHoldReason = "live-session-cwd";
|
|
1237
1321
|
/**
|
|
@@ -1250,6 +1334,11 @@ type GcHoldReason = "live-session-cwd";
|
|
|
1250
1334
|
declare function isMechanicalDepBumpRange(repoRoot: string, baseRef: string, tipSha: string): Promise<boolean>;
|
|
1251
1335
|
interface ResolveGcClassOptions extends ClassifyForGcOptions {
|
|
1252
1336
|
repoRoot: string;
|
|
1337
|
+
/**
|
|
1338
|
+
* Run `branch gc`'s content ladder for a clean, idle worktree still in
|
|
1339
|
+
* `hold` (see "in-base promotion"). Default true.
|
|
1340
|
+
*/
|
|
1341
|
+
inBaseCheck?: boolean;
|
|
1253
1342
|
/** The tip commit of the worktree being classified — `worktree.head`. */
|
|
1254
1343
|
tipSha: string;
|
|
1255
1344
|
/** Default `"origin/main"` — matches `reconcileIntegration`'s own default. */
|
|
@@ -1336,6 +1425,8 @@ interface PlanGcInput {
|
|
|
1336
1425
|
* protection beyond `classify`'s own snapshot-based liveness axis.
|
|
1337
1426
|
*/
|
|
1338
1427
|
protectedPaths?: string[];
|
|
1428
|
+
/** Noise allowlist (see "noise allowlist" above). Default `DEFAULT_GC_NOISE_PATHS`; `[]` disables it. */
|
|
1429
|
+
noisePaths?: readonly string[];
|
|
1339
1430
|
}
|
|
1340
1431
|
/**
|
|
1341
1432
|
* The dry-run plan (PLAN.md §5.2 layer 1): classify every linked worktree,
|
|
@@ -1360,6 +1451,8 @@ interface ApplyGcOptions {
|
|
|
1360
1451
|
salvageRoot?: string;
|
|
1361
1452
|
/** See `PlanGcInput.protectedPaths` — re-checked here at apply time (layer 2), independent of what the plan entry says, so a stale plan can never remove a now-protected path. */
|
|
1362
1453
|
protectedPaths?: string[];
|
|
1454
|
+
/** See `PlanGcInput.noisePaths`. */
|
|
1455
|
+
noisePaths?: readonly string[];
|
|
1363
1456
|
}
|
|
1364
1457
|
type GcApplyOutcome = {
|
|
1365
1458
|
path: string;
|
|
@@ -1429,4 +1522,471 @@ declare function reclaimOneWorktree(worktreePath: string, options: ApplyGcOption
|
|
|
1429
1522
|
includeDetached?: boolean;
|
|
1430
1523
|
}): Promise<GcApplyOutcome | null>;
|
|
1431
1524
|
|
|
1432
|
-
|
|
1525
|
+
/**
|
|
1526
|
+
* `branch gc`: the sibling of worktree `gc` (`gc.ts`) for refs instead of
|
|
1527
|
+
* worktrees — local branches (`refs/heads`), the base remote's tracking
|
|
1528
|
+
* branches (`refs/remotes/<remote>`), and ORPHAN tracking refs
|
|
1529
|
+
* (`refs/remotes/<ns>/*` whose `<ns>` is no longer a configured remote, which
|
|
1530
|
+
* nothing — not even `fetch --prune` — ever cleans up). Same contract as
|
|
1531
|
+
* worktree `gc`:
|
|
1532
|
+
*
|
|
1533
|
+
* 1. `planBranchGc` is pure read: every ref is classified `reclaim` /
|
|
1534
|
+
* `review` / `hold` and nothing is mutated. A dry run IS "call this,
|
|
1535
|
+
* print it, stop."
|
|
1536
|
+
* 2. `applyBranchGc` re-lists the refs and re-classifies every entry from
|
|
1537
|
+
* scratch immediately before touching it; a tip that moved, vanished or
|
|
1538
|
+
* now classifies differently is refused, never acted on.
|
|
1539
|
+
* 3. `hold` is never touched and `review` is never touched — only
|
|
1540
|
+
* `reclaim`. A reviewed-unmerged ref only becomes `reclaim` via
|
|
1541
|
+
* `includeReviewed` + a stored gate verdict that agreed for the SAME tip
|
|
1542
|
+
* sha; this module stores and reads verdicts, it never decides them.
|
|
1543
|
+
* 4. Every deletion is written to a restore log (sha + exact re-create
|
|
1544
|
+
* command) BEFORE the delete runs, so every apply is undoable.
|
|
1545
|
+
*
|
|
1546
|
+
* `reclaim` means "the work is provably in base", by a ladder of increasingly
|
|
1547
|
+
* expensive checks (`classifyTip`), ported from the audited
|
|
1548
|
+
* `branch-hygiene.mjs` maintenance script that first cleaned a 460-ref repo:
|
|
1549
|
+
*
|
|
1550
|
+
* pr-merged the tip IS the head commit (`headRefOid`) of a MERGED PR
|
|
1551
|
+
* — that exact commit was reviewed and merged, so nothing
|
|
1552
|
+
* was lost (forge shortcut in `classifyRef`: the ladder
|
|
1553
|
+
* still runs, but an "unmerged" verdict is overridden
|
|
1554
|
+
* before any reclaim/hold decision, skipping the
|
|
1555
|
+
* push-state/verdict lookups below it)
|
|
1556
|
+
* merged tip is an ancestor of base
|
|
1557
|
+
* squash-merged `git merge-tree --write-tree base tip` == base's tree
|
|
1558
|
+
* (merging it changes nothing)
|
|
1559
|
+
* patch-merged `git cherry` reports every commit as already applied —
|
|
1560
|
+
* ONLY tried when merge-tree conflicts (cherry patch-ids
|
|
1561
|
+
* every base commit since the merge-base: seconds per
|
|
1562
|
+
* branch on a busy base, and a clean merge with a
|
|
1563
|
+
* non-empty residual is unmerged regardless)
|
|
1564
|
+
* content-merged every path the branch changed is, BY BLOB, somewhere in
|
|
1565
|
+
* base's tree (any path — survives moves/reorgs) or
|
|
1566
|
+
* gitignored there, with zero `evolved` (same basename in
|
|
1567
|
+
* base, other content), zero `unique`, zero `deletes`
|
|
1568
|
+
*
|
|
1569
|
+
* Anything else is `unmerged` and — once older than `minAgeDays` and not
|
|
1570
|
+
* protected — becomes `review`, carrying everything a reviewer needs (coverage
|
|
1571
|
+
* summary, the files NOT provably in base, push state).
|
|
1572
|
+
*/
|
|
1573
|
+
|
|
1574
|
+
declare const BRANCH_GC_SCOPES: readonly ["local", "remote", "orphan"];
|
|
1575
|
+
/** `local` = refs/heads, `remote` = the base remote's tracking refs, `orphan` = refs/remotes/<ns>/* of a remote that no longer exists. */
|
|
1576
|
+
type BranchRefKind = (typeof BRANCH_GC_SCOPES)[number];
|
|
1577
|
+
/** The verdict for one tip, in order of increasing cost (`pr-merged` is the forge shortcut that overrides an "unmerged" ladder verdict, not a check that skips the ladder). */
|
|
1578
|
+
type BranchStatus = "pr-merged" | "merged" | "squash-merged" | "patch-merged" | "content-merged" | "unmerged";
|
|
1579
|
+
/**
|
|
1580
|
+
* `current`: the tip shares history with base. `pre-rewrite`: it doesn't, but
|
|
1581
|
+
* base was re-rooted and an anchor (the old-history twin of base's root)
|
|
1582
|
+
* answers for it. `unrelated`: no shared history and no anchor — unmerged by
|
|
1583
|
+
* definition, since nothing can prove it landed.
|
|
1584
|
+
*/
|
|
1585
|
+
type BranchHistory = "current" | "pre-rewrite" | "unrelated";
|
|
1586
|
+
type BranchGcClass = "reclaim" | "review" | "hold";
|
|
1587
|
+
/** Why a `reclaim` entry is reclaimable: one of the ladder's proven tiers, or a stored gate verdict (`includeReviewed`). */
|
|
1588
|
+
type BranchGcReclaimReason = Exclude<BranchStatus, "unmerged"> | "reviewed";
|
|
1589
|
+
/**
|
|
1590
|
+
* Why an entry is `hold`:
|
|
1591
|
+
* - `protected`: base or a well-known protected name (main, master, …)
|
|
1592
|
+
* - `worktree`: checked out in a worktree — the local branch AND its remote
|
|
1593
|
+
* twin (a live worktree may still push to it)
|
|
1594
|
+
* - `open-pr`: the head of an open PR
|
|
1595
|
+
* - `pr-check-unavailable`: open-PR detection could not run, so every
|
|
1596
|
+
* local/remote ref is held rather than silently losing that protection
|
|
1597
|
+
* - `young`: unmerged and younger than `minAgeDays`
|
|
1598
|
+
*/
|
|
1599
|
+
type BranchGcHoldReason = "protected" | "worktree" | "open-pr" | "pr-check-unavailable" | "young";
|
|
1600
|
+
/**
|
|
1601
|
+
* Where else an unmerged tip lives — matters because deleting the only copy
|
|
1602
|
+
* lets `git gc` destroy the commits. Local refs: `same-tip-on-remote` /
|
|
1603
|
+
* `contained-in-remote` / `diverged-from-remote` / `local-only`. Orphan refs:
|
|
1604
|
+
* `contained-elsewhere` / `only-copy`.
|
|
1605
|
+
*/
|
|
1606
|
+
type BranchPushState = "same-tip-on-remote" | "contained-in-remote" | "diverged-from-remote" | "local-only" | "contained-elsewhere" | "only-copy";
|
|
1607
|
+
/**
|
|
1608
|
+
* Content coverage of everything the branch changed (merge-base..tip), file
|
|
1609
|
+
* by file, against base's CONTENT rather than its history:
|
|
1610
|
+
* covered the exact blob exists somewhere in base (moved or copied)
|
|
1611
|
+
* ignored gitignored in the repo (generated output)
|
|
1612
|
+
* evolved a same-named file exists in base with other content
|
|
1613
|
+
* unique no trace in base
|
|
1614
|
+
* deletes the branch deletes a path base still has (an unlanded intent)
|
|
1615
|
+
* evolved + unique + deletes == 0 → nothing but history is lost by deleting.
|
|
1616
|
+
*/
|
|
1617
|
+
interface BranchCoverage {
|
|
1618
|
+
residual: number;
|
|
1619
|
+
covered: number;
|
|
1620
|
+
ignored: number;
|
|
1621
|
+
evolved: number;
|
|
1622
|
+
unique: number;
|
|
1623
|
+
deletes: number;
|
|
1624
|
+
}
|
|
1625
|
+
interface TipClassification {
|
|
1626
|
+
status: BranchStatus;
|
|
1627
|
+
history: BranchHistory;
|
|
1628
|
+
/** Commits on the tip not in the compare base; `null` for an unrelated tip. */
|
|
1629
|
+
ahead: number | null;
|
|
1630
|
+
/** Commits in the compare base not on the tip; `null` when not computed. */
|
|
1631
|
+
behind: number | null;
|
|
1632
|
+
/** Set once merge-tree ran: `true` when merging into base conflicts. */
|
|
1633
|
+
conflicts?: boolean;
|
|
1634
|
+
/** Base, or the anchor for a pre-rewrite tip — what ancestry/cherry ran against. Set for `unmerged`. */
|
|
1635
|
+
compareBase?: string;
|
|
1636
|
+
mergeBase?: string;
|
|
1637
|
+
/** Tree of base-with-the-branch-merged, `null` when the merge conflicts. Set for `unmerged`. */
|
|
1638
|
+
mergedTree?: string | null;
|
|
1639
|
+
coverage?: BranchCoverage;
|
|
1640
|
+
/** The files a reviewer must look at: unique, then evolved, then deletes. Capped at 200. */
|
|
1641
|
+
residualFiles?: string[];
|
|
1642
|
+
residualFileCount?: number;
|
|
1643
|
+
}
|
|
1644
|
+
interface BranchRef {
|
|
1645
|
+
kind: BranchRefKind;
|
|
1646
|
+
/** Short name: `feat/x` for local/remote, `<ns>/feat/x` for an orphan. */
|
|
1647
|
+
name: string;
|
|
1648
|
+
/** Full ref, e.g. `refs/remotes/origin/feat/x`. */
|
|
1649
|
+
ref: string;
|
|
1650
|
+
sha: string;
|
|
1651
|
+
/** Committer date of the tip, ISO-8601. */
|
|
1652
|
+
date: string;
|
|
1653
|
+
author: string;
|
|
1654
|
+
subject: string;
|
|
1655
|
+
/** The remote a `remote`-kind ref belongs to. */
|
|
1656
|
+
remote?: string;
|
|
1657
|
+
}
|
|
1658
|
+
/** Summary of a stored verdict for this exact tip, when one exists. */
|
|
1659
|
+
interface BranchVerdictSummary {
|
|
1660
|
+
triage: BranchTriageVerdict;
|
|
1661
|
+
agree: boolean | null;
|
|
1662
|
+
reviewer: string;
|
|
1663
|
+
}
|
|
1664
|
+
interface BranchGcPlanEntry extends BranchRef, TipClassification {
|
|
1665
|
+
ageDays: number;
|
|
1666
|
+
class: BranchGcClass;
|
|
1667
|
+
reclaimReason?: BranchGcReclaimReason;
|
|
1668
|
+
holdReason?: BranchGcHoldReason;
|
|
1669
|
+
/** Human detail for a hold: the worktree path, `PR #n`, or why the PR check failed. */
|
|
1670
|
+
holdDetail?: string;
|
|
1671
|
+
/** Set when the status is `pr-merged`: the number of the merged PR whose head commit IS this tip. */
|
|
1672
|
+
mergedPr?: number;
|
|
1673
|
+
/** Set for unmerged local and orphan refs. */
|
|
1674
|
+
pushed?: BranchPushState;
|
|
1675
|
+
verdict?: BranchVerdictSummary;
|
|
1676
|
+
}
|
|
1677
|
+
interface BranchGcPlan {
|
|
1678
|
+
repoRoot: string;
|
|
1679
|
+
repoName: string;
|
|
1680
|
+
base: string;
|
|
1681
|
+
baseSha: string;
|
|
1682
|
+
baseTree: string;
|
|
1683
|
+
/** The remote whose tracking refs are `remote`-kind — the base's own remote. `null` when base isn't a remote ref and there is no `origin`. */
|
|
1684
|
+
remote: string | null;
|
|
1685
|
+
/** Old-history twin of base's root for a re-rooted base, else `null`. */
|
|
1686
|
+
anchor: string | null;
|
|
1687
|
+
prCheck: {
|
|
1688
|
+
available: boolean;
|
|
1689
|
+
reason?: string;
|
|
1690
|
+
};
|
|
1691
|
+
scopes: BranchRefKind[];
|
|
1692
|
+
minAgeDays: number;
|
|
1693
|
+
includeReviewed: boolean;
|
|
1694
|
+
generatedAt: string;
|
|
1695
|
+
/** Refs of OTHER configured remotes: never classified, never touched. */
|
|
1696
|
+
otherRemoteRefs: number;
|
|
1697
|
+
entries: BranchGcPlanEntry[];
|
|
1698
|
+
}
|
|
1699
|
+
/** Base content index, built once per base: path→blob, every blob, every basename. */
|
|
1700
|
+
interface TreeIndex {
|
|
1701
|
+
byPath: Map<string, string>;
|
|
1702
|
+
blobs: Set<string>;
|
|
1703
|
+
names: Set<string>;
|
|
1704
|
+
}
|
|
1705
|
+
interface LadderContext {
|
|
1706
|
+
repoRoot: string;
|
|
1707
|
+
baseSha: string;
|
|
1708
|
+
baseTree: string;
|
|
1709
|
+
anchor: string | null;
|
|
1710
|
+
/** Built lazily: only content coverage needs it. */
|
|
1711
|
+
index: () => Promise<TreeIndex>;
|
|
1712
|
+
/** Tip sha → "shares history with `baseSha`", when already known (the
|
|
1713
|
+
* plan's anchor detection asks the same question of every tip) — saves
|
|
1714
|
+
* the ladder's first `merge-base` per tip. */
|
|
1715
|
+
related?: ReadonlyMap<string, boolean>;
|
|
1716
|
+
}
|
|
1717
|
+
declare function createLadderContext(repoRoot: string, baseRef: string, anchor: string | null, related?: ReadonlyMap<string, boolean>): Promise<LadderContext>;
|
|
1718
|
+
/**
|
|
1719
|
+
* Run the ladder for one tip against `ctx`'s base. Pure read. A tip with no
|
|
1720
|
+
* history in common with base is checked against the anchor when there is one
|
|
1721
|
+
* (ancestry/cherry against the anchor; merge-tree with
|
|
1722
|
+
* `--merge-base=merge-base(anchor, tip)`), else it is `unmerged`/`unrelated`.
|
|
1723
|
+
*/
|
|
1724
|
+
declare function classifyTip(ctx: LadderContext, tip: string): Promise<TipClassification>;
|
|
1725
|
+
/**
|
|
1726
|
+
* One-shot ladder for a caller that has a single tip and no plan (worktree
|
|
1727
|
+
* `gc`'s content-merged promotion). No anchor: a pre-rewrite tip reads
|
|
1728
|
+
* `unrelated`/`unmerged` here, which only ever errs toward keeping.
|
|
1729
|
+
*/
|
|
1730
|
+
declare function classifyTipAgainstBase(repoRoot: string, baseRef: string, tip: string): Promise<TipClassification>;
|
|
1731
|
+
/**
|
|
1732
|
+
* A re-rooted base (history rewritten into a fresh snapshot commit) shares no
|
|
1733
|
+
* ancestor with branches cut before the rewrite. The ANCHOR is the
|
|
1734
|
+
* old-history commit whose tree the snapshot was taken from: searched in the
|
|
1735
|
+
* unrelated tips' history within 3 days before the root's date, closest tree
|
|
1736
|
+
* to the root wins, accepted only when fewer than 200 files apart.
|
|
1737
|
+
*/
|
|
1738
|
+
declare function detectAnchor(repoRoot: string, baseSha: string, tips: readonly string[],
|
|
1739
|
+
/** Filled with every tip's answer (`true` = shares history with base) for
|
|
1740
|
+
* the ladder to reuse — see {@link LadderContext.related}. */
|
|
1741
|
+
related?: Map<string, boolean>): Promise<string | null>;
|
|
1742
|
+
declare const DEFAULT_BRANCH_GC_MIN_AGE_DAYS = 3;
|
|
1743
|
+
interface PlanBranchGcInput {
|
|
1744
|
+
repoRoot: string;
|
|
1745
|
+
repoName: string;
|
|
1746
|
+
/** Default `origin/main`. */
|
|
1747
|
+
base?: string;
|
|
1748
|
+
/** Subset of kinds to classify. Default all three. */
|
|
1749
|
+
scopes?: readonly BranchRefKind[];
|
|
1750
|
+
/** Unmerged refs younger than this are `hold`. Default 3. */
|
|
1751
|
+
minAgeDays?: number;
|
|
1752
|
+
/** Promote a `review` ref whose stored verdict agreed for the same tip sha to `reclaim` (`reviewed`). Default false. */
|
|
1753
|
+
includeReviewed?: boolean;
|
|
1754
|
+
/** Explicit anchor for a re-rooted base. Omitted → auto-detected. */
|
|
1755
|
+
anchor?: string;
|
|
1756
|
+
/** Open-PR detection (`listOpenPullRequests`). Omitted or unable → every local/remote ref is `hold` (`pr-check-unavailable`). */
|
|
1757
|
+
forge?: ForgeClient;
|
|
1758
|
+
verdicts?: BranchVerdictStore;
|
|
1759
|
+
/** Clock for `ageDays`. Default `Date.now()`. */
|
|
1760
|
+
nowMs?: number;
|
|
1761
|
+
/** Parallel ladder runs. Default 8. */
|
|
1762
|
+
concurrency?: number;
|
|
1763
|
+
}
|
|
1764
|
+
/** The dry-run plan: classify every ref in `scopes`, mutate nothing. */
|
|
1765
|
+
declare function planBranchGc(input: PlanBranchGcInput): Promise<BranchGcPlan>;
|
|
1766
|
+
interface BranchGcSummary {
|
|
1767
|
+
/** kind → class → count. */
|
|
1768
|
+
byClass: Record<BranchRefKind, Record<BranchGcClass, number>>;
|
|
1769
|
+
/**
|
|
1770
|
+
* kind → (status | "protected") → count, where "protected" = held for
|
|
1771
|
+
* base/protected, worktree, or open PR. Same buckets as the reference
|
|
1772
|
+
* script's audit summary, so the two can be compared line for line.
|
|
1773
|
+
*/
|
|
1774
|
+
byStatus: Record<BranchRefKind, Record<string, number>>;
|
|
1775
|
+
}
|
|
1776
|
+
declare function summarizeBranchGcPlan(plan: BranchGcPlan): BranchGcSummary;
|
|
1777
|
+
interface BranchReviewCandidate {
|
|
1778
|
+
name: string;
|
|
1779
|
+
kind: BranchRefKind;
|
|
1780
|
+
sha: string;
|
|
1781
|
+
ageDays: number;
|
|
1782
|
+
author: string;
|
|
1783
|
+
subject: string;
|
|
1784
|
+
history: BranchHistory;
|
|
1785
|
+
/** Base sha. */
|
|
1786
|
+
base: string;
|
|
1787
|
+
compareBase?: string;
|
|
1788
|
+
mergeBase?: string;
|
|
1789
|
+
mergedTree?: string | null;
|
|
1790
|
+
conflicts?: boolean;
|
|
1791
|
+
ahead: number | null;
|
|
1792
|
+
behind: number | null;
|
|
1793
|
+
pushed?: BranchPushState;
|
|
1794
|
+
coverage?: BranchCoverage;
|
|
1795
|
+
residualFiles?: string[];
|
|
1796
|
+
residualFileCount?: number;
|
|
1797
|
+
/** Every ref sharing this tip (a local branch and its remote twin share one review). */
|
|
1798
|
+
refs: string[];
|
|
1799
|
+
verdict?: BranchVerdictSummary;
|
|
1800
|
+
}
|
|
1801
|
+
interface BranchReviewQueue {
|
|
1802
|
+
base: string;
|
|
1803
|
+
baseSha: string;
|
|
1804
|
+
anchor: string | null;
|
|
1805
|
+
candidates: BranchReviewCandidate[];
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* The `review` entries of a plan, one per unique tip sha, with everything a
|
|
1809
|
+
* reviewer needs. Tips that already carry a stored verdict are skipped unless
|
|
1810
|
+
* `all` — verdicts are keyed by sha, so only tips that moved get re-reviewed.
|
|
1811
|
+
*/
|
|
1812
|
+
declare function branchReviewQueue(plan: BranchGcPlan, options?: {
|
|
1813
|
+
all?: boolean;
|
|
1814
|
+
}): BranchReviewQueue;
|
|
1815
|
+
type BranchGcApplyOutcome = {
|
|
1816
|
+
kind: BranchRefKind;
|
|
1817
|
+
name: string;
|
|
1818
|
+
sha: string;
|
|
1819
|
+
result: "deleted";
|
|
1820
|
+
reclaimReason: BranchGcReclaimReason;
|
|
1821
|
+
} | {
|
|
1822
|
+
kind: BranchRefKind;
|
|
1823
|
+
name: string;
|
|
1824
|
+
sha: string;
|
|
1825
|
+
result: "held";
|
|
1826
|
+
holdReason?: BranchGcHoldReason;
|
|
1827
|
+
}
|
|
1828
|
+
/** `review` class: never touched by apply — the review/approval path decides these. */
|
|
1829
|
+
| {
|
|
1830
|
+
kind: BranchRefKind;
|
|
1831
|
+
name: string;
|
|
1832
|
+
sha: string;
|
|
1833
|
+
result: "skipped-review";
|
|
1834
|
+
}
|
|
1835
|
+
/** The ref now points somewhere else than the plan saw — never delete what wasn't classified. */
|
|
1836
|
+
| {
|
|
1837
|
+
kind: BranchRefKind;
|
|
1838
|
+
name: string;
|
|
1839
|
+
sha: string;
|
|
1840
|
+
result: "aborted-moved";
|
|
1841
|
+
currentSha: string;
|
|
1842
|
+
}
|
|
1843
|
+
/** The ref no longer exists. */
|
|
1844
|
+
| {
|
|
1845
|
+
kind: BranchRefKind;
|
|
1846
|
+
name: string;
|
|
1847
|
+
sha: string;
|
|
1848
|
+
result: "aborted-vanished";
|
|
1849
|
+
}
|
|
1850
|
+
/** Re-classified from scratch and no longer `reclaim`. */
|
|
1851
|
+
| {
|
|
1852
|
+
kind: BranchRefKind;
|
|
1853
|
+
name: string;
|
|
1854
|
+
sha: string;
|
|
1855
|
+
result: "aborted-reclassified";
|
|
1856
|
+
from: BranchGcClass;
|
|
1857
|
+
to: BranchGcClass;
|
|
1858
|
+
holdReason?: BranchGcHoldReason;
|
|
1859
|
+
} | {
|
|
1860
|
+
kind: BranchRefKind;
|
|
1861
|
+
name: string;
|
|
1862
|
+
sha: string;
|
|
1863
|
+
result: "failed";
|
|
1864
|
+
message: string;
|
|
1865
|
+
};
|
|
1866
|
+
interface ApplyBranchGcOptions {
|
|
1867
|
+
/** REQUIRED and non-empty: which kinds apply may delete. Entries of other kinds are left out of the outcomes. */
|
|
1868
|
+
scopes: readonly BranchRefKind[];
|
|
1869
|
+
forge?: ForgeClient;
|
|
1870
|
+
verdicts?: BranchVerdictStore;
|
|
1871
|
+
/** Where restore logs go. Default `~/.agentproto/branch-gc`. */
|
|
1872
|
+
stateDir?: string;
|
|
1873
|
+
nowMs?: number;
|
|
1874
|
+
/** Remote refs per `git push --delete`. Default 50. */
|
|
1875
|
+
remoteBatchSize?: number;
|
|
1876
|
+
}
|
|
1877
|
+
interface BranchGcApplyResult {
|
|
1878
|
+
outcomes: BranchGcApplyOutcome[];
|
|
1879
|
+
/** Restore log for this run, `null` when nothing was deleted. */
|
|
1880
|
+
restoreLog: string | null;
|
|
1881
|
+
}
|
|
1882
|
+
declare const BRANCH_GC_STATE_DIR: () => string;
|
|
1883
|
+
interface BranchGcRestoreEntry {
|
|
1884
|
+
kind: BranchRefKind;
|
|
1885
|
+
name: string;
|
|
1886
|
+
ref: string;
|
|
1887
|
+
sha: string;
|
|
1888
|
+
remote?: string;
|
|
1889
|
+
/** git arguments (no leading `git`) that re-create the ref, run with `-C repoRoot`. */
|
|
1890
|
+
argv: string[];
|
|
1891
|
+
/** The same, as a copy-pasteable shell command. */
|
|
1892
|
+
command: string;
|
|
1893
|
+
/** Set once the delete ran. */
|
|
1894
|
+
deleted?: boolean;
|
|
1895
|
+
}
|
|
1896
|
+
interface BranchGcRestoreLog {
|
|
1897
|
+
schema: "branch-gc-restore/v1";
|
|
1898
|
+
repoRoot: string;
|
|
1899
|
+
base: string;
|
|
1900
|
+
baseSha: string;
|
|
1901
|
+
createdAt: string;
|
|
1902
|
+
entries: BranchGcRestoreEntry[];
|
|
1903
|
+
}
|
|
1904
|
+
/**
|
|
1905
|
+
* Execute a plan. Only `reclaim` entries whose kind is in `options.scopes`
|
|
1906
|
+
* are touched, and each is first re-derived from scratch: the ref is
|
|
1907
|
+
* re-listed (moved → `aborted-moved`, gone → `aborted-vanished`) and fully
|
|
1908
|
+
* re-classified against fresh worktree / open-PR / verdict state (anything but
|
|
1909
|
+
* `reclaim` → `aborted-reclassified`). The restore log is written before the
|
|
1910
|
+
* first delete runs.
|
|
1911
|
+
*/
|
|
1912
|
+
declare function applyBranchGc(plan: BranchGcPlan, options: ApplyBranchGcOptions): Promise<BranchGcApplyResult>;
|
|
1913
|
+
/** Read a restore log written by `applyBranchGc`. */
|
|
1914
|
+
declare function readBranchGcRestoreLog(path: string): Promise<BranchGcRestoreLog>;
|
|
1915
|
+
declare const BRANCH_TRIAGE_VERDICTS: readonly ["obsolete", "superseded", "salvage", "in-progress", "unclear"];
|
|
1916
|
+
type BranchTriageVerdict = (typeof BRANCH_TRIAGE_VERDICTS)[number];
|
|
1917
|
+
/**
|
|
1918
|
+
* One reviewer verdict for one branch tip. `gate` is the second opinion that
|
|
1919
|
+
* actually licenses deletion (`agree: true`); a triage-only verdict (no
|
|
1920
|
+
* `gate`) records the review but never makes a ref reclaimable. An agreeing
|
|
1921
|
+
* gate must cite evidence.
|
|
1922
|
+
*/
|
|
1923
|
+
declare const branchVerdictSchema: z.ZodObject<{
|
|
1924
|
+
name: z.ZodString;
|
|
1925
|
+
sha: z.ZodString;
|
|
1926
|
+
triage: z.ZodObject<{
|
|
1927
|
+
verdict: z.ZodEnum<{
|
|
1928
|
+
salvage: "salvage";
|
|
1929
|
+
obsolete: "obsolete";
|
|
1930
|
+
superseded: "superseded";
|
|
1931
|
+
"in-progress": "in-progress";
|
|
1932
|
+
unclear: "unclear";
|
|
1933
|
+
}>;
|
|
1934
|
+
confidence: z.ZodNumber;
|
|
1935
|
+
reason: z.ZodString;
|
|
1936
|
+
salvage: z.ZodOptional<z.ZodString>;
|
|
1937
|
+
}, z.core.$strip>;
|
|
1938
|
+
gate: z.ZodOptional<z.ZodObject<{
|
|
1939
|
+
agree: z.ZodBoolean;
|
|
1940
|
+
verdict: z.ZodEnum<{
|
|
1941
|
+
salvage: "salvage";
|
|
1942
|
+
obsolete: "obsolete";
|
|
1943
|
+
superseded: "superseded";
|
|
1944
|
+
"in-progress": "in-progress";
|
|
1945
|
+
unclear: "unclear";
|
|
1946
|
+
}>;
|
|
1947
|
+
reason: z.ZodString;
|
|
1948
|
+
evidence: z.ZodArray<z.ZodString>;
|
|
1949
|
+
}, z.core.$strip>>;
|
|
1950
|
+
reviewer: z.ZodString;
|
|
1951
|
+
}, z.core.$strip>;
|
|
1952
|
+
type BranchVerdict = z.infer<typeof branchVerdictSchema>;
|
|
1953
|
+
interface BranchVerdictRecord extends BranchVerdict {
|
|
1954
|
+
repo: string;
|
|
1955
|
+
recordedAt: string;
|
|
1956
|
+
}
|
|
1957
|
+
interface BranchVerdictStore {
|
|
1958
|
+
/** The verdict for this exact tip, or `null`. A ref whose tip moved simply finds nothing. */
|
|
1959
|
+
get(repo: string, sha: string): Promise<BranchVerdictRecord | null>;
|
|
1960
|
+
set(record: BranchVerdictRecord): Promise<void>;
|
|
1961
|
+
}
|
|
1962
|
+
declare const BRANCH_VERDICTS_PATH: () => string;
|
|
1963
|
+
/** `~/.agentproto/branch-gc-verdicts.json`, keyed by (repo, tip sha). */
|
|
1964
|
+
declare class FileBranchVerdictStore implements BranchVerdictStore {
|
|
1965
|
+
private readonly path;
|
|
1966
|
+
private cache;
|
|
1967
|
+
constructor(path?: string);
|
|
1968
|
+
private load;
|
|
1969
|
+
get(repo: string, sha: string): Promise<BranchVerdictRecord | null>;
|
|
1970
|
+
set(record: BranchVerdictRecord): Promise<void>;
|
|
1971
|
+
}
|
|
1972
|
+
declare class InMemoryBranchVerdictStore implements BranchVerdictStore {
|
|
1973
|
+
private readonly map;
|
|
1974
|
+
get(repo: string, sha: string): Promise<BranchVerdictRecord | null>;
|
|
1975
|
+
set(record: BranchVerdictRecord): Promise<void>;
|
|
1976
|
+
}
|
|
1977
|
+
declare class BranchVerdictError extends Error {
|
|
1978
|
+
constructor(message: string);
|
|
1979
|
+
}
|
|
1980
|
+
/**
|
|
1981
|
+
* Validate and store one verdict. Rejects a malformed verdict, an agreeing
|
|
1982
|
+
* gate with no evidence, and a sha that isn't a commit in this repo.
|
|
1983
|
+
*/
|
|
1984
|
+
declare function recordBranchVerdict(input: {
|
|
1985
|
+
repoRoot: string;
|
|
1986
|
+
repoName: string;
|
|
1987
|
+
verdict: unknown;
|
|
1988
|
+
store: BranchVerdictStore;
|
|
1989
|
+
now?: () => string;
|
|
1990
|
+
}): Promise<BranchVerdictRecord>;
|
|
1991
|
+
|
|
1992
|
+
export { type AgentprotoConfig, type ApplyBranchGcOptions, type ApplyGcOptions, BRANCH_GC_SCOPES, BRANCH_GC_STATE_DIR, BRANCH_TRIAGE_VERDICTS, BRANCH_VERDICTS_PATH, type BaseDivergence, type BranchCoverage, type BranchGcApplyOutcome, type BranchGcApplyResult, type BranchGcClass, type BranchGcHoldReason, type BranchGcPlan, type BranchGcPlanEntry, type BranchGcReclaimReason, type BranchGcRestoreEntry, type BranchGcRestoreLog, type BranchGcSummary, type BranchHistory, type BranchPushState, type BranchRef, type BranchRefKind, type BranchReviewCandidate, type BranchReviewQueue, type BranchStatus, type BranchTriageVerdict, type BranchVerdict, BranchVerdictError, type BranchVerdictRecord, type BranchVerdictStore, type BranchVerdictSummary, CONFIG_FILENAME, type Classification, type ClassifyForGcOptions, type ComputeProvenanceOptions, type ComputeTreeStateOptions, type ComputeWorktreeStatusInput, ConfigError, DEFAULT_BRANCH_GC_MIN_AGE_DAYS, DEFAULT_GC_NOISE_PATHS, DEFAULT_PROXY_PORT, type DaemonAgentSessionHost, type DaemonClient, ENV_VARS, type ExecOptions, type ExecResult, FileBranchVerdictStore, FileVerdictMemoStore, type ForgeClient, type ForgePullRequestRef, ForgeUnavailableError, type GateState, type GcApplyOutcome, type GcClass, type GcHoldReason, type GcPlanEntry, type GcReclaimReason, GhCliForgeClient, type GitWorktreeRef, HookError, type HookRun, type HostnameParts, type InBaseReclaimReason, InMemoryBranchVerdictStore, InMemoryVerdictMemoStore, type IntegrationState, type LadderContext, type ListWorktreeStatusesInput, type LivenessState, type NamedScript, type PeerService, type PlanBranchGcInput, type PlanGcInput, type ProvenanceConfidence, type ProvenanceInfo, ProxyTable, type ReconcileIntegrationInput, type ResolveGcClassOptions, type ResolveSupervisorInput, type ResolvedGcClass, type ResolvedWorktreeRuntime, RestForgeClient, type RunningProxy, SALVAGE_ROOT, SESSIONS_BUCKETS_ROOT, SESSIONS_FILE_PATH, type SalvageManifest, type SalvageResult, type SalvageWorktreeInput, type ScriptConfig, type ServiceRuntime, type ServiceStatus, ServiceSupervisor, type SessionRef, type SupervisorOptions, type TipClassification, type TreeIndex, type TreeState, UnreachableForgeClient, VERDICT_MEMO_PATH, type VerdictMemoRecord, type VerdictMemoStore, WORKTREES_TURBO_CACHE_DIR_ENV, type WorktreeAgentInput, type WorktreeClass, type WorktreeEnvContext, type WorktreeMarker, WorktreeNotRemovableError, type WorktreeStatusEntry, allocatePort, applyBranchGc, applyGc, branchReviewQueue, branchVerdictSchema, classify, classifyForGc, classifyTip, classifyTipAgainstBase, computeBaseDivergence, computeLiveness, computeProvenance, computeTreeState, computeWorktreeStatus, connectDaemonAgentSessionHost, createForgeClient, createLadderContext, createProxyServer, detectAnchor, detectDefaultBranch, disposeSupervisor, ephemeralPort, execArgv, execGit, execShell, expandGlob, getScript, getSupervisor, globToRegExp, hookEnv, isMechanicalDepBumpRange, isPortFree, listGitWorktrees, listScripts, listServices, listWorktreeStatuses, loadConfigFromBase, makeDaemonAgentSessionHost, normalizeHook, parseConfig, parseGithubOwnerRepo, peerEnv, peerEnvKey, planBranchGc, planGc, readBranchGcRestoreLog, readSessionsRegistry, readWorktreeMarker, reclaimOneWorktree, reconcileIntegration, recordBranchVerdict, repoLabel, resolveGcClass, resolveSupervisor, resolveWorktreesTurboCacheDir, runSetup, runTeardown, salvageWorktree, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, startProxy, stripPort, summarizeBranchGcPlan, worktreeAgentInputSchema, worktreeAgentWorkflow, writeWorktreeMarker };
|