@mmnto/cli 1.122.0 → 1.123.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.
Files changed (43) hide show
  1. package/dist/commands/config-drift.test.js +73 -1
  2. package/dist/commands/config-drift.test.js.map +1 -1
  3. package/dist/commands/init-templates.d.ts +6 -6
  4. package/dist/commands/init-templates.d.ts.map +1 -1
  5. package/dist/commands/init-templates.js +8 -7
  6. package/dist/commands/init-templates.js.map +1 -1
  7. package/dist/commands/init.test.js +18 -5
  8. package/dist/commands/init.test.js.map +1 -1
  9. package/dist/commands/install-hooks.d.ts.map +1 -1
  10. package/dist/commands/install-hooks.js +58 -0
  11. package/dist/commands/install-hooks.js.map +1 -1
  12. package/dist/commands/install-hooks.test.js +460 -5
  13. package/dist/commands/install-hooks.test.js.map +1 -1
  14. package/dist/commands/legs.d.ts +259 -0
  15. package/dist/commands/legs.d.ts.map +1 -0
  16. package/dist/commands/legs.js +623 -0
  17. package/dist/commands/legs.js.map +1 -0
  18. package/dist/commands/legs.test.d.ts +20 -0
  19. package/dist/commands/legs.test.d.ts.map +1 -0
  20. package/dist/commands/legs.test.js +1004 -0
  21. package/dist/commands/legs.test.js.map +1 -0
  22. package/dist/commands/pre-push-gate-matrix.test.js +14 -0
  23. package/dist/commands/pre-push-gate-matrix.test.js.map +1 -1
  24. package/dist/commands/review-fan.d.ts +40 -1
  25. package/dist/commands/review-fan.d.ts.map +1 -1
  26. package/dist/commands/review-fan.js +108 -3
  27. package/dist/commands/review-fan.js.map +1 -1
  28. package/dist/commands/review-fan.test.js +444 -6
  29. package/dist/commands/review-fan.test.js.map +1 -1
  30. package/dist/commands/shield-covariate.test.js +19 -2
  31. package/dist/commands/shield-covariate.test.js.map +1 -1
  32. package/dist/commands/shield-nonreview.test.js +140 -1
  33. package/dist/commands/shield-nonreview.test.js.map +1 -1
  34. package/dist/commands/shield.d.ts.map +1 -1
  35. package/dist/commands/shield.js +53 -1
  36. package/dist/commands/shield.js.map +1 -1
  37. package/dist/git.d.ts +19 -0
  38. package/dist/git.d.ts.map +1 -1
  39. package/dist/git.js +13 -4
  40. package/dist/git.js.map +1 -1
  41. package/dist/index.js +40 -0
  42. package/dist/index.js.map +1 -1
  43. package/package.json +2 -2
@@ -0,0 +1,259 @@
1
+ /**
2
+ * `totem legs deposit` / `totem legs gate` — the two verbs over the
3
+ * leg-deposit store (mmnto-ai/totem#2698, ruled 2026-09-03;
4
+ * `doctrine/model-tiering.md` § Review legs).
5
+ *
6
+ * `deposit` is the ONLY writer: it resolves the head a falsification leg
7
+ * actually read, binds the leg's findings file to that sha, and hands the
8
+ * bytes to core's validate-on-write `saveLegDeposit`. `gate` is a READER — it
9
+ * never writes, never judges a finding's severity, and never decides policy:
10
+ * it answers one question for a push, *was this head read by a leg*, and says
11
+ * exactly how it derived the answer.
12
+ *
13
+ * Three properties of the gate are contract, not style:
14
+ *
15
+ * 1. **The tier changes only the exit code.** `--advisory` prints the
16
+ * BYTE-IDENTICAL lines of every state and exits 0; the strict caller is
17
+ * the pre-push hook, which maps 3 and 2 to a block. That is why the
18
+ * derivation returns its lines and BOTH codes, and the flag is applied at
19
+ * one place at the very end — a second formatting path per tier is how the
20
+ * advisory line and the blocking line drift apart.
21
+ * 2. **Not owed never consults the store.** The predicate is derived from the
22
+ * changed-file set alone; a repo whose diff matches no glob must not have
23
+ * its deposit directory read, so the "not owed" line is honest about
24
+ * having judged globs and nothing else.
25
+ * 3. **stdout is written SYNCHRONOUSLY before exit.** A piped write is
26
+ * asynchronous on macOS, so `process.stdout.write` followed by
27
+ * `process.exit` can truncate the very line the `sh` arm is about to echo
28
+ * — the `fs.writeSync(1, …)` precedent from the strict pre-commit reader.
29
+ *
30
+ * Everything the gate echoes is control-character sanitized. The deposit's own
31
+ * strings are already refused at the schema boundary (core `artifacts/legs.ts`),
32
+ * but paths, glob names and corrupt-file reasons come off a filesystem and a
33
+ * config file, so they are sanitized here too rather than trusted by provenance.
34
+ *
35
+ * Per the CLI command-module contract, every VALUE import is dynamic inside
36
+ * the command bodies (the core barrel pulls LanceDB into `--help` otherwise);
37
+ * `import type` is erased at build and stays static.
38
+ */
39
+ import type { LegCoverageQuery, LegGitAdapter } from '@mmnto/totem';
40
+ /**
41
+ * List what a candidate could have READ: the paths its own branch diff added
42
+ * relative to `base` (three-dot).
43
+ *
44
+ * `-z` is load-bearing, not a style choice (mmnto-ai/totem#2698 fold 4). Under
45
+ * git's default `core.quotePath=true`, `--name-only` C-QUOTES any path with a
46
+ * non-ASCII byte, a quote or a backslash — `docs/caf\303\251.md` — while the
47
+ * owed set comes from `extractChangedFiles`, which is unquoted. The two sets
48
+ * then never intersect for such a path, and a covering ancestor is rejected
49
+ * with the false reason "predates every owed change". `-z` emits raw
50
+ * NUL-separated names and never quotes, so both sides speak one spelling.
51
+ *
52
+ * One helper, taking the runner: the gate shells out through `safeExec` and the
53
+ * covariate through its injected `GitExec`, and a second copy of this argv is
54
+ * exactly how one of them would drift back to the quoted form.
55
+ */
56
+ export declare function legReachPaths(run: (args: readonly string[]) => string, base: string, head: string): string[];
57
+ export interface LegsDepositOptions {
58
+ /** The head the leg READ. Any rev git accepts; defaults to `HEAD`. */
59
+ sha?: string;
60
+ /** Path to the leg's findings JSON. */
61
+ from: string;
62
+ /** Overwrite an existing deposit for this sha, reporting what was replaced. */
63
+ replace?: boolean;
64
+ /** The leg's own instant (ISO-8601). Overrides the file's `readAt`. */
65
+ readAt?: string;
66
+ }
67
+ /**
68
+ * `totem legs deposit --sha <ref> --from <file> [--replace] [--read-at <iso>]`
69
+ *
70
+ * The writer. Refuses, loudly and before touching the store, every way the
71
+ * deposit could name the wrong head: a `--sha` that is not a commit, a file
72
+ * whose own `diffSha` disagrees with it, and an occupied address without
73
+ * `--replace`. `readAt` is the leg's own instant — when the file carries none
74
+ * and none is passed, the stamp is `now` and that substitution is PRINTED,
75
+ * because a deposit's instant is what the resolver breaks ties on.
76
+ */
77
+ export declare function legsDepositCommand(options: LegsDepositOptions): Promise<void>;
78
+ export interface LegsGateOptions {
79
+ /**
80
+ * Print every line of the derived state, but exit 0 for every GATE state
81
+ * (not owed, evidence, blocked, not derived). A failure BEFORE the
82
+ * derivation — an unloadable config, an unknown flag — still exits non-zero.
83
+ */
84
+ advisory?: boolean;
85
+ }
86
+ /**
87
+ * There is deliberately no `--head`: the gate judges `HEAD` and nothing else
88
+ * (mmnto-ai/totem#2698 fold 2, MATERIAL). A caller-chosen head turns a block
89
+ * into a pass — a deposit written on a sibling branch answers for a commit
90
+ * this push does not contain — and the hook has no reason to ask about any
91
+ * head but the one being pushed. Tests inject a head through
92
+ * {@link LegsGateDeps.resolveHead}, which is a seam, not a public flag.
93
+ */
94
+ /**
95
+ * The derivation seam. Everything the gate needs that touches the world —
96
+ * git, the config's globs, the diff — arrives through this interface, so the
97
+ * five states are testable against a temp store and a fake git without a
98
+ * fixture repo per case (core's `LegGitAdapter` precedent).
99
+ */
100
+ export interface LegsGateDeps {
101
+ /** The root every printed path is relative to (the config root). */
102
+ root: string;
103
+ /** Absolute totem dir — the deposit store lives under it. */
104
+ totemDirAbs: string;
105
+ /** The judgment-dense floor this push is judged against. */
106
+ globs: readonly string[];
107
+ /** Ancestry seam handed to core's resolver. */
108
+ git: LegGitAdapter;
109
+ /** Full 40-hex head sha. Throws when the head cannot be resolved. */
110
+ resolveHead(): string;
111
+ /** The push's resolved branch scope. Throws when the diff cannot be resolved. */
112
+ changedFiles(): Promise<LegsGateScope>;
113
+ }
114
+ /**
115
+ * The branch scope the gate judges: the unfiltered changed-file set, plus the
116
+ * base it was resolved against.
117
+ *
118
+ * The base is carried because COVERAGE is measured against it
119
+ * (mmnto-ai/totem#2698 fold 3) — a candidate's reach is `base...<diffSha>`, and
120
+ * it has to be the SAME base HEAD was resolved against or the two diffs are not
121
+ * comparable. Absent when the resolution produced no base, which the gate
122
+ * treats as "coverage is not derivable" rather than guessing one.
123
+ */
124
+ export interface LegsGateScope {
125
+ files: readonly string[];
126
+ base?: string;
127
+ }
128
+ /**
129
+ * The coverage query for a set of owed paths, or `undefined` when it cannot be
130
+ * derived (no base). Exported because the covariate resolves through the SAME
131
+ * inputs as the gate — a field that named a deposit the gate rejects would be
132
+ * the round reading evidence the push gate does not accept.
133
+ *
134
+ * The basis lists one entry per `glob -> file` MATCH, so a file matching three
135
+ * globs appears three times; the owed set is those files, deduplicated in
136
+ * basis order.
137
+ */
138
+ export declare function legsCoverageForBasis(base: string | undefined, basis: readonly {
139
+ glob: string;
140
+ file: string;
141
+ }[]): LegCoverageQuery | undefined;
142
+ /** Exit vocabulary: 0 not owed / evidence · 2 could not derive · 3 owed, no deposit. */
143
+ export type LegsGateCode = 0 | 2 | 3;
144
+ export interface LegsGateOutcome {
145
+ /** The DERIVED state — what the gate concluded, before any tier mapping. */
146
+ derived: LegsGateCode;
147
+ /** What the process exits with: `derived`, or 0 under `--advisory`. */
148
+ status: LegsGateCode;
149
+ /** stdout lines, in order. Identical for both tiers, by contract. */
150
+ stdout: string[];
151
+ /** stderr lines (the corrupt-deposit sensor rows). */
152
+ stderr: string[];
153
+ }
154
+ /**
155
+ * Derive the gate's verdict and its lines.
156
+ *
157
+ * The tier is applied ONLY to `status`; `stdout` is produced once, so an
158
+ * advisory run and a strict run of the same state cannot print different text.
159
+ */
160
+ export declare function runLegsGate(options: LegsGateOptions, deps: LegsGateDeps): Promise<LegsGateOutcome>;
161
+ /**
162
+ * How a caller wants the branch scope resolved.
163
+ *
164
+ * `run` is the git seam (mmnto-ai/totem#2698 fold 5, Q1): the covariate
165
+ * resolves HEAD and ancestry through an INJECTED runner, and a reach probe that
166
+ * shelled out to real git regardless left half that seam unhonored — a test
167
+ * could fake the ancestry half and silently get real git for the other.
168
+ */
169
+ export interface LegsScopeOptions {
170
+ /** Suppress this module's `[Legs]` scope lines AND the resolver's own. */
171
+ suppressScopeNarration?: boolean;
172
+ /** Git runner; defaults to `safeExec('git', …, { cwd })`. */
173
+ run?: (args: readonly string[]) => string;
174
+ }
175
+ /**
176
+ * Resolve the branch scope the floor is judged on — the ONE derivation the gate
177
+ * and the covariate both use (mmnto-ai/totem#2698 fold 3 item 3), so the
178
+ * covariate can never name a deposit the gate would reject.
179
+ *
180
+ * The push-gate scope (`--branch`): the branch-vs-base diff is what the leg
181
+ * read, and it is what the push actually proposes. An empty result is not owed
182
+ * — there is nothing for a leg to read.
183
+ *
184
+ * UNFILTERED, deliberately (mmnto-ai/totem#2698 fold 1). The same base/head
185
+ * resolution runs, but with an EMPTY ignore configuration, so neither
186
+ * `ignorePatterns` nor `shieldIgnorePatterns` can hide a path from the floor.
187
+ * Those keys carry INDEX-exclusion semantics that were merged into the
188
+ * review/lint diff filter for back-compat (mmnto-ai/totem#1746,
189
+ * mmnto-ai/totem#1748) — letting them narrow this predicate would mean a repo
190
+ * that excludes `README.md` from its index silently stops owing a leg for its
191
+ * public copy, which is the claim-without-mechanism shape the floor exists to
192
+ * close.
193
+ *
194
+ * The resolved BASE rides back with the files: coverage is measured against it,
195
+ * and it must be the same base HEAD was resolved against.
196
+ */
197
+ export declare function resolveUnfilteredBranchScope(cwd: string, options?: LegsScopeOptions): Promise<LegsGateScope>;
198
+ /**
199
+ * The judgment-dense floor this repo declares, or the default when it declares
200
+ * none — the ONE spelling, shared by the gate and both covariate sites.
201
+ */
202
+ export declare function legsOwedGlobs(config: {
203
+ hooks?: {
204
+ legsOwed?: {
205
+ globs?: readonly string[];
206
+ };
207
+ };
208
+ }): Promise<readonly string[]>;
209
+ /**
210
+ * What a covariate site learned when it asked for coverage inputs: either the
211
+ * query, or the reason it is not derivable for that site's scope.
212
+ */
213
+ export interface LegsCoverageResolution {
214
+ query?: LegCoverageQuery;
215
+ /** Present iff `query` is absent — the caller discloses it as one Sensor line. */
216
+ reason?: string;
217
+ }
218
+ /**
219
+ * Derive the coverage query for a COVARIATE site (mmnto-ai/totem#2698 fold 3,
220
+ * corrected in fold 4).
221
+ *
222
+ * The inputs come from HEAD's branch-vs-base scope ALWAYS — never from the
223
+ * scope the review itself ran on. The leg field answers "was THIS HEAD read",
224
+ * so what it owes is a property of HEAD, not of whether the operator happened
225
+ * to review a staged slice or a dirty tree. Deriving from the review's scope
226
+ * meant the default `uncommitted` scope resolved ancestry-only and NAMED the
227
+ * merge-base deposit the gate rejects — the field disagreeing with the gate,
228
+ * which is the one thing it must never do.
229
+ *
230
+ * Both covariate sites route through this one function, and it reuses the
231
+ * gate's own pieces — the unfiltered branch scope and core's single
232
+ * `classifyLegsOwed` — so the guarantee is unconditional: the field never names
233
+ * a deposit the gate would reject. When HEAD has no branch base the answer is
234
+ * `leg: none` plus one sensor, never a name resolved on ancestry alone.
235
+ */
236
+ export declare function deriveLegsCoverageForHead(cwd: string, globs: readonly string[], options?: LegsScopeOptions): Promise<LegsCoverageResolution>;
237
+ /**
238
+ * Build the gate's real-world seam from the repo's config and git.
239
+ *
240
+ * Exported so the UNFILTERED-diff contract below is testable against a real
241
+ * checkout without capturing a process exit: a test resolves these deps in a
242
+ * fixture repo and asserts what `changedFiles()` actually returns.
243
+ *
244
+ * It takes no options: since `--head` was removed (mmnto-ai/totem#2698 fold 2)
245
+ * nothing about the seam varies with a flag — `--advisory` is applied to the
246
+ * STATUS, after the derivation, and never to what is derived.
247
+ */
248
+ export declare function buildLegsGateDeps(): Promise<LegsGateDeps>;
249
+ /**
250
+ * `totem legs gate [--advisory]`
251
+ *
252
+ * The reader the strict pre-push arm calls. Loads the repo's config, builds
253
+ * the real git and diff seams, derives, writes SYNCHRONOUSLY, exits with the
254
+ * tier-mapped status. `--advisory` maps every GATE state to 0; a failure
255
+ * before the derivation (config load, flag parse) still exits non-zero
256
+ * through the CLI's error boundary.
257
+ */
258
+ export declare function legsGateCommand(options: LegsGateOptions): Promise<void>;
259
+ //# sourceMappingURL=legs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legs.d.ts","sourceRoot":"","sources":["../../src/commands/legs.ts"],"names":[],"mappings":"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"}