@mmnto/totem 1.111.0 → 1.112.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.
@@ -201,7 +201,6 @@ export declare const CapabilityLedgerSchema: z.ZodObject<{
201
201
  lastResolved: string | null;
202
202
  }>, "many">;
203
203
  }, "strip", z.ZodTypeAny, {
204
- resolutionHorizon: string;
205
204
  rows: {
206
205
  agentSource: string;
207
206
  taskType: "review-catch" | "bug-localization" | "diagnostic-harness" | "diagnostic-screenshot" | "layout-design" | "code-impl";
@@ -213,8 +212,8 @@ export declare const CapabilityLedgerSchema: z.ZodObject<{
213
212
  hitRate: number | null;
214
213
  lastResolved: string | null;
215
214
  }[];
216
- }, {
217
215
  resolutionHorizon: string;
216
+ }, {
218
217
  rows: {
219
218
  agentSource: string;
220
219
  taskType: "review-catch" | "bug-localization" | "diagnostic-harness" | "diagnostic-screenshot" | "layout-design" | "code-impl";
@@ -226,6 +225,7 @@ export declare const CapabilityLedgerSchema: z.ZodObject<{
226
225
  hitRate: number | null;
227
226
  lastResolved: string | null;
228
227
  }[];
228
+ resolutionHorizon: string;
229
229
  }>;
230
230
  export type CapabilityLedger = z.infer<typeof CapabilityLedgerSchema>;
231
231
  /**
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Worktree-estate sensor (mmnto-ai/totem#2580 slice-1) — the read-only scan
3
+ * behind `totem doctor --estate`.
4
+ *
5
+ * Two arms, both local-git + local-fs only:
6
+ * - **registered**: for every repo in the user-level registry, enumerate the
7
+ * LINKED worktrees (`git worktree list --porcelain`) and classify each one
8
+ * from evidence — dirty tree → active; clean + ancestry-merged into the
9
+ * default branch → stale; clean + NOT ancestry-merged → `indeterminate`,
10
+ * never stale. That last state is the squash-merge gap stated honestly: a
11
+ * squash-merged branch leaves no ancestry edge, and this sensor has no
12
+ * merged-facts source (the status-lane snapshot extension is a later
13
+ * slice), so it declines to claim either way.
14
+ * - **husk sweep**: candidate roots are swept one level for worktree-shaped
15
+ * residue. Roots come in two kinds, and the kind decides what counts as
16
+ * evidence. A CONTAINER root exists solely to hold worktrees
17
+ * (`<repo>/.claude/worktrees`, or any `--root` the operator names), so an
18
+ * untracked directory there is residue BY LOCATION. A STANDARD root (the
19
+ * parent of a registry path or of a listed worktree) is an ordinary
20
+ * working directory, so residue there needs the older positive evidence —
21
+ * a dangling `.git` pointer, or a repo-name prefix plus a leftover
22
+ * `node_modules`. Either way an unclassifiable directory is not reported
23
+ * at all rather than guessed at.
24
+ *
25
+ * Registry membership is NOT protection from candidacy. Git's own worktree
26
+ * list is what protects a path (cohort-overlay §2), and a genuine repo
27
+ * checkout is already protected by the `.git`-DIRECTORY rule; a registry entry
28
+ * only records that something was synced from a path once. Registry accounting
29
+ * and disk residue are different axes — the same path can carry both a repo
30
+ * row and a husk row.
31
+ *
32
+ * Sensor, never actuator: the only git verbs invoked are `worktree list`,
33
+ * `status`, `merge-base --is-ancestor`, `log -1`, and `rev-parse`, and every
34
+ * invocation carries `--no-optional-locks`. That flag is what makes the
35
+ * read-only claim true rather than aspirational: `git status` otherwise
36
+ * refreshes and WRITES the index, taking `index.lock` (git-status(1) §
37
+ * BACKGROUND REFRESH), which in a cohort's shared worktrees would collide with
38
+ * a seat's live `git add`. No registry entry is mutated and nothing is cached
39
+ * across calls. Every probe failure lands as an `unscannable` row (or a
40
+ * class-`unscannable` worktree row naming the failed step) so a degraded scan
41
+ * can never read as a clean one.
42
+ *
43
+ * `safeExec` is injected rather than imported so the scan stays testable
44
+ * without a real git tree (the author-sandbox.ts:21 idiom).
45
+ */
46
+ import type { SafeExecOptions } from './sys/exec.js';
47
+ /** The compatibility contract with the status-lane consumer of `--estate --json`. */
48
+ export declare const ESTATE_SCHEMA_VERSION = 1;
49
+ /**
50
+ * The injected exec seam. Structurally identical to `safeExec`, so production
51
+ * callers pass it directly and tests pass a spy.
52
+ */
53
+ export type EstateExecFn = (command: string, args?: string[], options?: SafeExecOptions) => string;
54
+ /** One entry of `git worktree list --porcelain`. */
55
+ export interface WorktreeListEntry {
56
+ path: string;
57
+ /** Commit at the worktree's HEAD, when git reported one. */
58
+ head?: string;
59
+ /** Full ref (`refs/heads/<name>`) — absent for a detached or bare entry. */
60
+ branch?: string;
61
+ bare: boolean;
62
+ detached: boolean;
63
+ locked: boolean;
64
+ lockedReason?: string;
65
+ prunable: boolean;
66
+ prunableReason?: string;
67
+ }
68
+ export type WorktreeClass = 'registered-active' | 'registered-stale' | 'registered-indeterminate' | 'registered-detached' | 'unscannable';
69
+ export type HuskEvidence = 'dangling-gitdir-pointer' | 'residue-shape' | 'deregistered-intact'
70
+ /** Untracked directory under a CONTAINER root — the location is the evidence. */
71
+ | 'container-residue';
72
+ export interface EstateWorktreeRow {
73
+ path: string;
74
+ /** The registry repo whose worktree list produced this row. */
75
+ repoPath: string;
76
+ /** Short branch name (`refs/heads/` stripped) for display. */
77
+ branch?: string;
78
+ head?: string;
79
+ class: WorktreeClass;
80
+ dirty?: boolean;
81
+ /**
82
+ * `true`/`false` only when the ancestry probe actually ran and answered;
83
+ * `'unknown'` whenever it could not (detached, dirty, no default branch).
84
+ */
85
+ ancestryMerged: boolean | 'unknown';
86
+ /** Days since the worktree's last commit. Absent when `log -1` did not answer. */
87
+ ageDays?: number;
88
+ locked?: boolean;
89
+ prunable?: boolean;
90
+ /** What the classification was read from, in the scan's own words. */
91
+ evidence: string;
92
+ }
93
+ export interface EstateHuskRow {
94
+ path: string;
95
+ sweptRoot: string;
96
+ evidence: HuskEvidence;
97
+ /** The registry repo (residue-shape) or home repo (deregistered-intact) this matched. */
98
+ matchedRepo?: string;
99
+ /** Days since the directory's mtime — a husk has no commit to date from. */
100
+ ageDays?: number;
101
+ }
102
+ /**
103
+ * Which AXIS a probe failure belongs to. The sweep axis is the one the
104
+ * candidate partition is defined over; `registry` and `worktree` rows are
105
+ * accounting for the registered arm and may legitimately share a path with a
106
+ * husk row (the two-axes rule — a directory can be both a stale registry entry
107
+ * and disk residue).
108
+ */
109
+ export type EstateUnscannableSource = 'registry' | 'worktree' | 'sweep';
110
+ export interface EstateUnscannableRow {
111
+ path: string;
112
+ reason: string;
113
+ source: EstateUnscannableSource;
114
+ }
115
+ export interface EstateRepoRow {
116
+ path: string;
117
+ lastSync?: string;
118
+ /** Registry entry whose path no longer exists — reported, never probed. */
119
+ missing?: boolean;
120
+ /**
121
+ * Registry entry that exists but is NOT a git toplevel: git discovered an
122
+ * ANCESTOR repo from it. Such an entry is never enumerated as a repo (its
123
+ * worktree list would be the ancestor's), and nothing is derived from it.
124
+ */
125
+ notGitRoot?: boolean;
126
+ /** The ancestor repo git discovered — set with `notGitRoot`. */
127
+ enclosingRepo?: string;
128
+ /** Short default-branch name in remote-tracking form (`origin/<name>`), absent when underivable (never guessed). */
129
+ defaultBranch?: string;
130
+ /** Count of LINKED worktrees (the main worktree is the repo itself). */
131
+ worktrees: number;
132
+ }
133
+ export interface EstateSummary {
134
+ repos: number;
135
+ reposMissing: number;
136
+ /** Registry entries that exist but are not a git toplevel. */
137
+ reposNotGitRoot: number;
138
+ /** Registry entries whose own probes failed (registry-source ledger rows). */
139
+ reposUnscannable: number;
140
+ worktrees: number;
141
+ active: number;
142
+ stale: number;
143
+ indeterminate: number;
144
+ detached: number;
145
+ unscannableWorktrees: number;
146
+ huskCandidates: number;
147
+ /**
148
+ * EVERY `unscannable` ledger row, across all three axes — `reposUnscannable`
149
+ * and `unscannableWorktrees` are subsets of this total, not addends beside
150
+ * it. The sweep-axis count is the remainder.
151
+ */
152
+ unscannable: number;
153
+ }
154
+ /** A root the derivation declined to sweep, with the reason it was declined. */
155
+ export interface EstateExcludedRoot {
156
+ path: string;
157
+ reason: string;
158
+ }
159
+ /**
160
+ * A swept root and its KIND, which is what decides the evidence bar inside it:
161
+ * a `container` root is a declared worktree location (location is evidence), a
162
+ * `standard` root is an ordinary working directory (shape is evidence).
163
+ * Disclosed so a consumer can tell which bar produced a given husk row.
164
+ */
165
+ export interface EstateSweptRoot {
166
+ path: string;
167
+ kind: 'container' | 'standard';
168
+ }
169
+ export interface EstateScanResult {
170
+ schemaVersion: typeof ESTATE_SCHEMA_VERSION;
171
+ derivedAt: string;
172
+ /**
173
+ * Every root actually swept, with its kind — disclosed so no cap, omission,
174
+ * or evidence-bar difference is silent.
175
+ */
176
+ sweptRoots: EstateSweptRoot[];
177
+ /**
178
+ * Roots the derivation suppressed, so the narrowing is visible rather than
179
+ * silent. A root that any other derivation path also produced is SWEPT and
180
+ * never appears here.
181
+ */
182
+ excludedRoots: EstateExcludedRoot[];
183
+ repos: EstateRepoRow[];
184
+ worktrees: EstateWorktreeRow[];
185
+ huskCandidates: EstateHuskRow[];
186
+ unscannable: EstateUnscannableRow[];
187
+ summary: EstateSummary;
188
+ }
189
+ /** The registry projection the scan needs — nothing else is read from it. */
190
+ export interface EstateRegistryEntry {
191
+ path: string;
192
+ lastSync?: string;
193
+ }
194
+ export interface EstateScanInputs {
195
+ registry: EstateRegistryEntry[];
196
+ safeExec: EstateExecFn;
197
+ /** Epoch ms, injected so `ageDays` is deterministic under test. */
198
+ now: number;
199
+ /** Extra sweep roots (`--root`, repeatable), unioned with the derived ones. */
200
+ extraRoots?: string[];
201
+ }
202
+ /**
203
+ * Parse `git worktree list --porcelain`: one `worktree <path>` header per
204
+ * entry, attribute lines until a blank line. Unknown attributes are ignored so
205
+ * a newer git cannot break the parse. Git lists the MAIN worktree first,
206
+ * followed by the linked ones — callers depend on that order.
207
+ */
208
+ export declare function parseWorktreeListPorcelain(raw: string): WorktreeListEntry[];
209
+ /**
210
+ * Scan the worktree estate. Pure per invocation: nothing persists, nothing is
211
+ * written, and the result is the complete accounting — every enumerated
212
+ * candidate is either classified, a husk candidate, or `unscannable`.
213
+ */
214
+ export declare function scanEstate(inputs: EstateScanInputs): EstateScanResult;
215
+ //# sourceMappingURL=estate-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estate-scan.d.ts","sourceRoot":"","sources":["../src/estate-scan.ts"],"names":[],"mappings":"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"}