majordomus_cli/worktree/mod.rs
1//! The branch-to-worktree topology: where every linked worktree of a repository belongs,
2//! derived from git and from nothing else, and everything that follows from it.
3//!
4//! # The invariant
5//!
6//! ```text
7//! <parent>/<repo> the primary checkout, which hosts the trunk
8//! <parent>/<repo>-wt/ the container, derived: parent + name + "-wt"
9//! <parent>/<repo>-wt/<branch name> the one worktree of every non-trunk branch
10//! ```
11//!
12//! The branch name *is* the relative path: `feature/providers/openai-streaming` lives at
13//! `<repo>-wt/feature/providers/openai-streaming`, hierarchy preserved, nothing flattened,
14//! nothing hashed, nothing registered. Git is the registry: the identity comes from the
15//! common git directory, the worktrees from `git worktree list --porcelain`, the branches
16//! from `for-each-ref`, and this module interprets them into one typed
17//! [`RepositoryTopology`] that every surface renders.
18//!
19//! # The architecture
20//!
21//! ```text
22//! git (common dir, worktree list, for-each-ref, status)
23//! ↓
24//! RepositoryIdentity primary, current, container, trunk — from anywhere inside
25//! ↓
26//! path::expected_path() container / branch name, proved to stay inside the container
27//! ↓
28//! WorktreeService topology, status, guard, inspect, create, migrate, repair
29//! ↙ ↓ ↘
30//! CLI capability git hooks → MCP, HTTP, OpenAPI, Swagger, the Cockpit, docs
31//! ```
32//!
33//! Every surface is an adapter. Nothing outside this module derives a path, decides a
34//! standing, or judges whether a move is safe; a second implementation of any of those is
35//! the defect this module exists to prevent.
36//!
37//! # Safety
38//!
39//! Nothing here deletes a directory because its name looks right, and nothing here resets,
40//! stashes, cleans or checks out anything. A migration moves a worktree with `git worktree
41//! move`, dirty state included, and proves with a [`fingerprint::WorktreeFingerprint`]
42//! taken before and after that the branch, the commit, the index, the staged and unstaged
43//! changes and the untracked files are the same on the other side. Every mutation holds one
44//! repository-scoped [`lock::WorktreeLock`], so two agents cannot half-register one path.
45
46pub(crate) mod direnv;
47pub(crate) mod error;
48pub mod fingerprint;
49pub(crate) mod git;
50pub(crate) mod hooks;
51pub(crate) mod identity;
52pub(crate) mod lock;
53pub(crate) mod migrate;
54pub(crate) mod model;
55pub(crate) mod path;
56pub(crate) mod service;
57pub mod state;
58pub(crate) mod topology;
59pub(crate) mod trace;
60pub mod uncommitted;
61
62pub use direnv::EnvrcApproval;
63pub use error::{Result, WorktreeError, EXIT_INTERNAL, EXIT_MISSING, EXIT_REFUSED};
64pub use fingerprint::WorktreeFingerprint;
65pub use hooks::{carry_hooks_path, HooksPath};
66pub use identity::{RepositoryIdentity, ResolvedPath, Trunk, TrunkSource};
67pub use lock::WorktreeLock;
68pub use migrate::{MigrationAction, MigrationOptions, MigrationPlan, MigrationStep, StepOutcome};
69pub use model::{
70 BranchState, ContainerView, DiagnosticCode, DirtyState, GuardVerdict, InspectReport,
71 RepairReport, RepositoryTopology, RepositoryView, Severity, Standing, StatusReport,
72 TopologyDiagnostic, TopologyTallies, TrunkView, UpstreamState, WorktreeKind, WorktreeState,
73 SCHEMA,
74};
75pub use path::{container_root, detached_label, expected_path, BranchName, CONTAINER_SUFFIX};
76pub use service::{CreateReport, CreateRequest, Detail, RemoveReport, StartPoint, WorktreeService};
77pub use topology::{parse_porcelain, parse_porcelain_nul, WorktreeRecord};
78pub use trace::{
79 first_merge, parse_commit, parse_issue_refs, Attribution, BranchTrace, CommitAttribution,
80 CommitRef, Integration, IssueTrace, TraceReport, TraceTallies, Tracer,
81};
82pub use uncommitted::{
83 OpenEpisode, Threshold, UncommittedReport, UncommittedTallies, UncommittedWorktree,
84 WorkStanding,
85};