@mmnto/cli 1.111.1 → 1.113.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,43 @@
1
+ /**
2
+ * `totem doctor --estate` — the worktree-estate sensor's surface
3
+ * (mmnto-ai/totem#2580 slice-1).
4
+ *
5
+ * Report-only by construction: the scan reads, this file renders, and neither
6
+ * removes anything (removal verbs are a later slice). Exit stays 0 in every
7
+ * sensor outcome — a husk, a stale worktree, and a failed probe are all
8
+ * findings to show, not gate failures.
9
+ *
10
+ * Two surfaces, never both: the human render goes to stderr via the shared ui
11
+ * log helpers, and `--json` replaces it wholesale with a diffable artifact that
12
+ * owns stdout (the doctor-parity.ts:1507 verdict-artifact discipline —
13
+ * kebab-case keys, no `json-output.ts` envelope, `estate-schema-version` as the
14
+ * compatibility contract with the status lane).
15
+ *
16
+ * Core is dynamic-imported so `@mmnto/totem` stays off the CLI cold-start
17
+ * graph, matching every other doctor check.
18
+ */
19
+ import type { EstateExecFn, TotemRegistry } from '@mmnto/totem';
20
+ export interface EstateCliOptions {
21
+ /**
22
+ * Emit the scan as the JSON artifact on stdout INSTEAD of the human render.
23
+ * The artifact is diffable, so nothing else may share stdout.
24
+ */
25
+ json?: boolean;
26
+ /** Extra sweep roots (`--root`, repeatable), resolved against the cwd. */
27
+ roots?: string[];
28
+ /** Test seam — production callers omit and the command uses `process.cwd()`. */
29
+ cwdForTest?: string;
30
+ /** Test seam — bypasses the user-level `~/.totem/registry.json` read. */
31
+ registryForTest?: TotemRegistry;
32
+ /** Test seam — canned git, so the render is testable without a real estate. */
33
+ execForTest?: EstateExecFn;
34
+ /** Test seam — pins `derivedAt` and every `age-days` value. */
35
+ nowForTest?: number;
36
+ /**
37
+ * Test seam — bypasses the user-level `~/.totem/worktrees.json` read that
38
+ * supplies the wt-registry's recorded container roots.
39
+ */
40
+ wtRootsForTest?: string[];
41
+ }
42
+ export declare function doctorEstateCliCommand(options?: EstateCliOptions): Promise<void>;
43
+ //# sourceMappingURL=doctor-estate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-estate.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-estate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,aAAa,EAAE,MAAM,cAAc,CAAC;AAYlF,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AA6HD,wBAAsB,sBAAsB,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyM1F"}
@@ -0,0 +1,262 @@
1
+ /**
2
+ * `totem doctor --estate` — the worktree-estate sensor's surface
3
+ * (mmnto-ai/totem#2580 slice-1).
4
+ *
5
+ * Report-only by construction: the scan reads, this file renders, and neither
6
+ * removes anything (removal verbs are a later slice). Exit stays 0 in every
7
+ * sensor outcome — a husk, a stale worktree, and a failed probe are all
8
+ * findings to show, not gate failures.
9
+ *
10
+ * Two surfaces, never both: the human render goes to stderr via the shared ui
11
+ * log helpers, and `--json` replaces it wholesale with a diffable artifact that
12
+ * owns stdout (the doctor-parity.ts:1507 verdict-artifact discipline —
13
+ * kebab-case keys, no `json-output.ts` envelope, `estate-schema-version` as the
14
+ * compatibility contract with the status lane).
15
+ *
16
+ * Core is dynamic-imported so `@mmnto/totem` stays off the CLI cold-start
17
+ * graph, matching every other doctor check.
18
+ */
19
+ const TAG = 'Estate';
20
+ /** Gutter width for row labels, so every row family aligns on one column. */
21
+ const LABEL_WIDTH = 13;
22
+ /** Row labels are the class names with the `registered-` scope prefix dropped. */
23
+ function classLabel(cls) {
24
+ return cls.startsWith('registered-') ? cls.slice('registered-'.length) : cls;
25
+ }
26
+ /**
27
+ * The `--json` artifact. Optional keys are PRESENCE-ONLY (emitted or absent,
28
+ * never `false`/`null`) so a consumer cannot mistake "not probed" for "probed
29
+ * and negative" — the same convention as the parity readout's `last-attested`.
30
+ */
31
+ function estateJsonArtifact(result, registryStatus) {
32
+ return {
33
+ 'estate-schema-version': result.schemaVersion,
34
+ 'registry-status': registryStatus,
35
+ 'derived-at': result.derivedAt,
36
+ // Each root carries its KIND: the kind is what decided the evidence bar
37
+ // inside it, so a consumer reading a husk row can tell which bar produced
38
+ // it without re-deriving the roots.
39
+ 'swept-roots': result.sweptRoots.map((r) => ({ path: r.path, kind: r.kind })),
40
+ // Additive under schema-version 1: the contract has no consumer yet, and a
41
+ // narrowed sweep that nothing discloses is the silent degradation the
42
+ // swept-roots disclosure exists to prevent.
43
+ 'excluded-roots': result.excludedRoots.map((r) => ({ path: r.path, reason: r.reason })),
44
+ repos: result.repos.map((r) => ({
45
+ path: r.path,
46
+ ...(r.lastSync !== undefined ? { 'last-sync': r.lastSync } : {}),
47
+ ...(r.missing === true ? { missing: true } : {}),
48
+ ...(r.notGitRoot === true ? { 'not-git-root': true } : {}),
49
+ ...(r.enclosingRepo !== undefined ? { 'enclosing-repo': r.enclosingRepo } : {}),
50
+ ...(r.defaultBranch !== undefined ? { 'default-branch': r.defaultBranch } : {}),
51
+ worktrees: r.worktrees,
52
+ })),
53
+ worktrees: result.worktrees.map((w) => ({
54
+ path: w.path,
55
+ 'repo-path': w.repoPath,
56
+ ...(w.branch !== undefined ? { branch: w.branch } : {}),
57
+ ...(w.head !== undefined ? { head: w.head } : {}),
58
+ class: w.class,
59
+ ...(w.dirty === true ? { dirty: true } : {}),
60
+ 'ancestry-merged': w.ancestryMerged,
61
+ ...(w.ageDays !== undefined ? { 'age-days': w.ageDays } : {}),
62
+ ...(w.locked === true ? { locked: true } : {}),
63
+ ...(w.prunable === true ? { prunable: true } : {}),
64
+ evidence: w.evidence,
65
+ })),
66
+ 'husk-candidates': result.huskCandidates.map((h) => ({
67
+ path: h.path,
68
+ 'swept-root': h.sweptRoot,
69
+ evidence: h.evidence,
70
+ ...(h.matchedRepo !== undefined ? { 'matched-repo': h.matchedRepo } : {}),
71
+ ...(h.ageDays !== undefined ? { 'age-days': h.ageDays } : {}),
72
+ })),
73
+ unscannable: result.unscannable.map((u) => ({
74
+ path: u.path,
75
+ reason: u.reason,
76
+ source: u.source,
77
+ })),
78
+ summary: {
79
+ repos: result.summary.repos,
80
+ 'repos-missing': result.summary.reposMissing,
81
+ 'repos-not-git-root': result.summary.reposNotGitRoot,
82
+ 'repos-unscannable': result.summary.reposUnscannable,
83
+ worktrees: result.summary.worktrees,
84
+ active: result.summary.active,
85
+ stale: result.summary.stale,
86
+ indeterminate: result.summary.indeterminate,
87
+ detached: result.summary.detached,
88
+ 'unscannable-worktrees': result.summary.unscannableWorktrees,
89
+ 'husk-candidates': result.summary.huskCandidates,
90
+ unscannable: result.summary.unscannable,
91
+ },
92
+ };
93
+ }
94
+ /**
95
+ * The degenerate artifact for an empty or unreadable registry: the same shape
96
+ * carrying the computed `registry-status`, so a consumer can tell "nothing
97
+ * registered" from "registry unreadable" from "scanned and found nothing"
98
+ * (doctor-parity.ts:1528 precedent).
99
+ */
100
+ function degenerateArtifact(now, registryStatus,
101
+ // The core constant, passed in from the command's dynamic import so this
102
+ // helper stays synchronous and the literal has one source of truth.
103
+ schemaVersion) {
104
+ return estateJsonArtifact({
105
+ schemaVersion,
106
+ derivedAt: new Date(now).toISOString(),
107
+ sweptRoots: [],
108
+ excludedRoots: [],
109
+ repos: [],
110
+ worktrees: [],
111
+ huskCandidates: [],
112
+ unscannable: [],
113
+ summary: {
114
+ repos: 0,
115
+ reposMissing: 0,
116
+ reposNotGitRoot: 0,
117
+ reposUnscannable: 0,
118
+ worktrees: 0,
119
+ active: 0,
120
+ stale: 0,
121
+ indeterminate: 0,
122
+ detached: 0,
123
+ unscannableWorktrees: 0,
124
+ huskCandidates: 0,
125
+ unscannable: 0,
126
+ },
127
+ }, registryStatus);
128
+ }
129
+ export async function doctorEstateCliCommand(options = {}) {
130
+ const path = await import('node:path');
131
+ const { ESTATE_SCHEMA_VERSION, existingWorktreeRoots, partitionWorktreeRoots, readRegistry, readWorktreeRegistry, safeExec, sanitizeForTerminal, scanEstate, } = await import('@mmnto/totem');
132
+ const { bold, dim: dimColor, log, success: successColor, warn: warnColor, } = await import('../ui.js');
133
+ // Paths, branch names, and git error text all originate outside this process;
134
+ // sanitize + flatten before logging so embedded ANSI / newlines cannot forge
135
+ // extra doctor lines (matches doctorParityCliCommand and checkStrategyRoot).
136
+ const render = (text) => sanitizeForTerminal(text)
137
+ .replace(/[\t\n]+/g, ' ')
138
+ .replace(/ {2,}/g, ' ')
139
+ .trim();
140
+ const cwd = options.cwdForTest ?? process.cwd();
141
+ const now = options.nowForTest ?? Date.now();
142
+ const registryWarnings = [];
143
+ const registry = options.registryForTest ?? readRegistry((msg) => registryWarnings.push(msg));
144
+ const entries = Object.values(registry).map((entry) => ({
145
+ path: entry.path,
146
+ lastSync: entry.lastSync,
147
+ }));
148
+ // `readRegistry` warns only when it swallowed a non-ENOENT read/parse failure
149
+ // and returned `{}`, so a warning always implies zero entries — and means
150
+ // "unreadable", not "empty".
151
+ const registryStatus = registryWarnings.length > 0 ? 'unreadable' : entries.length === 0 ? 'empty' : 'ok';
152
+ // Warnings ride stderr in EVERY mode, ahead of the artifact write: stderr is
153
+ // not the artifact, and dropping the one signal that the registry is broken
154
+ // would be exactly the silent degradation this sensor exists to surface.
155
+ for (const warning of registryWarnings)
156
+ log.warn(TAG, render(warning));
157
+ // The wt-registry's recorded roots (mmnto-ai/totem#2580 slice 2, round-3
158
+ // MINOR-3): every root `totem wt create` has ever minted under. This is what
159
+ // keeps a recorded location reachable once the last live entry under it is
160
+ // gone — with only the derived roots, an emptied location is invisible to
161
+ // the sweep and every husk in it goes unreported. Only the DEFAULT
162
+ // `~/.totem/worktrees` location carries the CONTAINER semantics an
163
+ // operator's per-invocation `--root` confers; every other recorded root
164
+ // sweeps as a STANDARD root, where husk-ness needs shape evidence — a
165
+ // recorded scratch root must never permanently arm by-location residue rows
166
+ // for the unrelated directories beside its worktrees (#2580 slice-2
167
+ // falsification, finding 11).
168
+ //
169
+ // Unreadable file: warn and proceed with the derived roots (the
170
+ // container-withdrawal precedent — a degraded scan may report LESS, never
171
+ // more). Recorded roots that no longer exist are filtered out inside
172
+ // `existingWorktreeRoots`: an absent root is an empty sweep, not a hole.
173
+ const wtWarnings = [];
174
+ const wtRoots = options.wtRootsForTest ??
175
+ existingWorktreeRoots(readWorktreeRegistry((msg) => wtWarnings.push(msg)));
176
+ for (const warning of wtWarnings)
177
+ log.warn(TAG, render(warning));
178
+ const wtPartition = partitionWorktreeRoots(wtRoots);
179
+ const extraRoots = [
180
+ ...(options.roots ?? []).map((root) => path.resolve(cwd, root)),
181
+ ...wtPartition.container,
182
+ ];
183
+ const extraStandardRoots = wtPartition.standard;
184
+ // The empty-registry short-circuit yields ONLY when there is also nothing to
185
+ // sweep: `--root` declares a worktree location independently of the registry,
186
+ // the wt-registry's recorded roots do the same, and `scanEstate` sweeps
187
+ // `extraRoots` with `registry: []` — dropping them here would kill both
188
+ // exactly when the registry is useless.
189
+ if (entries.length === 0 && extraRoots.length === 0 && extraStandardRoots.length === 0) {
190
+ if (options.json) {
191
+ process.stdout.write(JSON.stringify(degenerateArtifact(now, registryStatus, ESTATE_SCHEMA_VERSION), null, 2) +
192
+ '\n');
193
+ return;
194
+ }
195
+ log.dim(TAG, registryStatus === 'unreadable'
196
+ ? 'SKIP — ~/.totem/registry.json could not be read; no repos to scan'
197
+ : 'SKIP — no registered repos in ~/.totem/registry.json; run `totem sync` in a repo to register it');
198
+ return;
199
+ }
200
+ const result = scanEstate({
201
+ registry: entries,
202
+ safeExec: options.execForTest ?? safeExec,
203
+ now,
204
+ extraRoots,
205
+ extraStandardRoots,
206
+ });
207
+ if (options.json) {
208
+ process.stdout.write(JSON.stringify(estateJsonArtifact(result, registryStatus), null, 2) + '\n');
209
+ return;
210
+ }
211
+ const s = result.summary;
212
+ log.info(TAG, bold('── worktree estate ──'));
213
+ log.info(TAG, `${s.repos} registered repo(s) · ${s.worktrees} linked worktree(s) · swept ${result.sweptRoots.length} root(s): ${result.sweptRoots
214
+ .map((r) => `${render(r.path)} (${r.kind})`)
215
+ .join(', ')}`);
216
+ for (const excluded of result.excludedRoots) {
217
+ log.dim(TAG, `not swept: ${render(excluded.path)} — ${render(excluded.reason)}`);
218
+ }
219
+ for (const repo of result.repos) {
220
+ if (repo.missing === true) {
221
+ log.info(TAG, `${warnColor(bold('[MISSING] '))} ${render(repo.path)} — registry path does not exist`);
222
+ continue;
223
+ }
224
+ if (repo.notGitRoot === true) {
225
+ log.info(TAG, `${warnColor(bold('[NOT GIT ROOT]'))} ${render(repo.path)} — inside ${render(repo.enclosingRepo ?? 'an enclosing repo')}, not a git toplevel; not enumerated`);
226
+ continue;
227
+ }
228
+ const branch = repo.defaultBranch === undefined
229
+ ? 'default branch underivable'
230
+ : `default ${render(repo.defaultBranch)}`;
231
+ log.dim(TAG, `repo ${render(repo.path)} — ${branch} · ${repo.worktrees} worktree(s)`);
232
+ }
233
+ for (const row of result.worktrees) {
234
+ const label = classLabel(row.class).padEnd(LABEL_WIDTH);
235
+ const color = row.class === 'registered-active'
236
+ ? successColor
237
+ : row.class === 'registered-stale' || row.class === 'unscannable'
238
+ ? warnColor
239
+ : dimColor;
240
+ const branch = row.branch === undefined ? '(detached)' : `[${render(row.branch)}]`;
241
+ const flags = [row.locked === true ? 'locked' : '', row.prunable === true ? 'prunable' : '']
242
+ .filter((f) => f.length > 0)
243
+ .join(' · ');
244
+ const flagSuffix = flags.length > 0 ? ` · ${flags}` : '';
245
+ log.info(TAG, `${color(bold(label))} ${render(row.path)} ${branch} — ${render(row.evidence)}${flagSuffix}`);
246
+ }
247
+ for (const husk of result.huskCandidates) {
248
+ const age = husk.ageDays === undefined ? '' : ` · mtime ${husk.ageDays}d ago`;
249
+ const matched = husk.matchedRepo === undefined ? '' : ` · matches ${render(husk.matchedRepo)}`;
250
+ log.info(TAG, `${warnColor(bold('husk'.padEnd(LABEL_WIDTH)))} ${render(husk.path)} [${husk.evidence}] under ${render(husk.sweptRoot)}${matched}${age}`);
251
+ }
252
+ for (const row of result.unscannable) {
253
+ // The axis is printed: a registry-source row is registered-arm accounting
254
+ // and may share a path with a husk row, while a sweep-source row is a hole
255
+ // in the candidate scan. Collapsing them would hide which is which.
256
+ log.info(TAG, `${warnColor(bold('unscannable'.padEnd(LABEL_WIDTH)))} [${row.source}] ${render(row.path)} — ${render(row.reason)}`);
257
+ }
258
+ log.info(TAG, `${s.worktrees} worktree(s): ${s.active} active · ${s.stale} stale · ${s.indeterminate} indeterminate · ${s.detached} detached · ${s.unscannableWorktrees} unscannable — plus ${s.huskCandidates} husk candidate(s) · ${s.unscannable} unscannable probe(s)`);
259
+ log.dim(TAG, 'indeterminate = clean but not ancestry-merged: a squash-merged branch is indistinguishable from an unmerged one without a merged-facts source, so this sensor declines to claim either.');
260
+ log.dim(TAG, 'husk criteria by root kind — container roots (`<repo>/.claude/worktrees` and any --root) use LOCATION as evidence: ANY directory git tracks no worktree for and that has no `.git` directory is reported there, typed as dangling-gitdir-pointer or deregistered-intact when a `.git` pointer supplies stronger evidence and container-residue otherwise. Standard roots (parents of registry paths and of listed worktrees) require SHAPE evidence: a dangling `.git` pointer · no `.git` + verified-repo name prefix + node_modules · an intact pointer absent from its home repo worktree list. Report-only — nothing is removed.');
261
+ }
262
+ //# sourceMappingURL=doctor-estate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-estate.js","sourceRoot":"","sources":["../../src/commands/doctor-estate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,GAAG,GAAG,QAAQ,CAAC;AAiCrB,6EAA6E;AAC7E,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,kFAAkF;AAClF,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/E,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CACzB,MAAwB,EACxB,cAA8B;IAE9B,OAAO;QACL,uBAAuB,EAAE,MAAM,CAAC,aAAa;QAC7C,iBAAiB,EAAE,cAAc;QACjC,YAAY,EAAE,MAAM,CAAC,SAAS;QAC9B,wEAAwE;QACxE,0EAA0E;QAC1E,oCAAoC;QACpC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7E,2EAA2E;QAC3E,sEAAsE;QACtE,4CAA4C;QAC5C,gBAAgB,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACvF,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChD,GAAG,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,CAAC,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/E,GAAG,CAAC,CAAC,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/E,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC,CAAC;QACH,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,QAAQ;YACvB,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,iBAAiB,EAAE,CAAC,CAAC,cAAc;YACnC,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC;QACH,iBAAiB,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnD,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,YAAY,EAAE,CAAC,CAAC,SAAS;YACzB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,GAAG,CAAC,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,MAAM,EAAE,CAAC,CAAC,MAAM;SACjB,CAAC,CAAC;QACH,OAAO,EAAE;YACP,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK;YAC3B,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY;YAC5C,oBAAoB,EAAE,MAAM,CAAC,OAAO,CAAC,eAAe;YACpD,mBAAmB,EAAE,MAAM,CAAC,OAAO,CAAC,gBAAgB;YACpD,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS;YACnC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;YAC7B,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK;YAC3B,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa;YAC3C,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ;YACjC,uBAAuB,EAAE,MAAM,CAAC,OAAO,CAAC,oBAAoB;YAC5D,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,cAAc;YAChD,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW;SACxC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB,CACzB,GAAW,EACX,cAA8B;AAC9B,yEAAyE;AACzE,oEAAoE;AACpE,aAAgD;IAEhD,OAAO,kBAAkB,CACvB;QACE,aAAa;QACb,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;QACtC,UAAU,EAAE,EAAE;QACd,aAAa,EAAE,EAAE;QACjB,KAAK,EAAE,EAAE;QAET,SAAS,EAAE,EAAE;QACb,cAAc,EAAE,EAAE;QAClB,WAAW,EAAE,EAAE;QACf,OAAO,EAAE;YACP,KAAK,EAAE,CAAC;YACR,YAAY,EAAE,CAAC;YACf,eAAe,EAAE,CAAC;YAClB,gBAAgB,EAAE,CAAC;YACnB,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,CAAC;YACR,aAAa,EAAE,CAAC;YAChB,QAAQ,EAAE,CAAC;YACX,oBAAoB,EAAE,CAAC;YACvB,cAAc,EAAE,CAAC;YACjB,WAAW,EAAE,CAAC;SACf;KACF,EACD,cAAc,CACf,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,UAA4B,EAAE;IACzE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,EACJ,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,mBAAmB,EACnB,UAAU,GACX,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IACjC,MAAM,EACJ,IAAI,EACJ,GAAG,EAAE,QAAQ,EACb,GAAG,EACH,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,SAAS,GAChB,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAE7B,8EAA8E;IAC9E,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,MAAM,GAAG,CAAC,IAAY,EAAU,EAAE,CACtC,mBAAmB,CAAC,IAAI,CAAC;SACtB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,IAAI,EAAE,CAAC;IAEZ,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7C,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,MAAM,QAAQ,GACZ,OAAO,CAAC,eAAe,IAAI,YAAY,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACvF,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACtD,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAC,CAAC;IAEJ,8EAA8E;IAC9E,0EAA0E;IAC1E,6BAA6B;IAC7B,MAAM,cAAc,GAClB,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAErF,6EAA6E;IAC7E,4EAA4E;IAC5E,yEAAyE;IACzE,KAAK,MAAM,OAAO,IAAI,gBAAgB;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvE,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,mEAAmE;IACnE,mEAAmE;IACnE,wEAAwE;IACxE,sEAAsE;IACtE,4EAA4E;IAC5E,oEAAoE;IACpE,8BAA8B;IAC9B,EAAE;IACF,gEAAgE;IAChE,0EAA0E;IAC1E,qEAAqE;IACrE,yEAAyE;IACzE,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,OAAO,GACX,OAAO,CAAC,cAAc;QACtB,qBAAqB,CAAC,oBAAoB,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrF,KAAK,MAAM,OAAO,IAAI,UAAU;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACjE,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEpD,MAAM,UAAU,GAAG;QACjB,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/D,GAAG,WAAW,CAAC,SAAS;KACzB,CAAC;IACF,MAAM,kBAAkB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAEhD,6EAA6E;IAC7E,8EAA8E;IAC9E,wEAAwE;IACxE,wEAAwE;IACxE,wCAAwC;IACxC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,qBAAqB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrF,IAAI,CACP,CAAC;YACF,OAAO;QACT,CAAC;QACD,GAAG,CAAC,GAAG,CACL,GAAG,EACH,cAAc,KAAK,YAAY;YAC7B,CAAC,CAAC,mEAAmE;YACrE,CAAC,CAAC,iGAAiG,CACtG,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC;QACxB,QAAQ,EAAE,OAAO;QACjB,QAAQ,EAAE,OAAO,CAAC,WAAW,IAAI,QAAQ;QACzC,GAAG;QACH,UAAU;QACV,kBAAkB;KACnB,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAC3E,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;IACzB,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAC7C,GAAG,CAAC,IAAI,CACN,GAAG,EACH,GAAG,CAAC,CAAC,KAAK,yBAAyB,CAAC,CAAC,SAAS,+BAA+B,MAAM,CAAC,UAAU,CAAC,MAAM,aAAa,MAAM,CAAC,UAAU;SAChI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC;SAC3C,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IACF,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QAC5C,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CACN,GAAG,EACH,GAAG,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,CACxF,CAAC;YACF,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,GAAG,CAAC,IAAI,CACN,GAAG,EACH,GAAG,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,aAAa,IAAI,mBAAmB,CAAC,sCAAsC,CAC9J,CAAC;YACF,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GACV,IAAI,CAAC,aAAa,KAAK,SAAS;YAC9B,CAAC,CAAC,4BAA4B;YAC9B,CAAC,CAAC,WAAW,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,MAAM,MAAM,IAAI,CAAC,SAAS,cAAc,CAAC,CAAC;IACxF,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACxD,MAAM,KAAK,GACT,GAAG,CAAC,KAAK,KAAK,mBAAmB;YAC/B,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,GAAG,CAAC,KAAK,KAAK,kBAAkB,IAAI,GAAG,CAAC,KAAK,KAAK,aAAa;gBAC/D,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,QAAQ,CAAC;QACjB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;QACnF,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;aACzF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;aAC3B,IAAI,CAAC,KAAK,CAAC,CAAC;QACf,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,GAAG,CAAC,IAAI,CACN,GAAG,EACH,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,UAAU,EAAE,CAC7F,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,OAAO,OAAO,CAAC;QAC9E,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/F,GAAG,CAAC,IAAI,CACN,GAAG,EACH,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,WAAW,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,OAAO,GAAG,GAAG,EAAE,CACzI,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACrC,0EAA0E;QAC1E,2EAA2E;QAC3E,oEAAoE;QACpE,GAAG,CAAC,IAAI,CACN,GAAG,EACH,GAAG,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CACpH,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,IAAI,CACN,GAAG,EACH,GAAG,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,aAAa,oBAAoB,CAAC,CAAC,QAAQ,eAAe,CAAC,CAAC,oBAAoB,uBAAuB,CAAC,CAAC,cAAc,wBAAwB,CAAC,CAAC,WAAW,uBAAuB,CAC7P,CAAC;IACF,GAAG,CAAC,GAAG,CACL,GAAG,EACH,yLAAyL,CAC1L,CAAC;IACF,GAAG,CAAC,GAAG,CACL,GAAG,EACH,smBAAsmB,CACvmB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Render + artifact tests for `totem doctor --estate` (mmnto-ai/totem#2580).
3
+ *
4
+ * Git is injected (canned porcelain), so these assert the SURFACE — which rows
5
+ * render, what the artifact contains, and that the two never share a stream —
6
+ * rather than the local git install. The husk fixture is a real temp tree
7
+ * because husk evidence is literally a filesystem shape.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=doctor-estate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-estate.test.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-estate.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}