@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.
- package/dist/capability/schema.d.ts +2 -2
- package/dist/estate-scan.d.ts +215 -0
- package/dist/estate-scan.d.ts.map +1 -0
- package/dist/estate-scan.js +792 -0
- package/dist/estate-scan.js.map +1 -0
- package/dist/estate-scan.test.d.ts +20 -0
- package/dist/estate-scan.test.d.ts.map +1 -0
- package/dist/estate-scan.test.js +1309 -0
- package/dist/estate-scan.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/spine/ledgers.d.ts +18 -18
- package/package.json +1 -1
|
@@ -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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"}
|