@mmnto/cli 1.89.0 → 1.90.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/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # @mmnto/cli
2
+
3
+ Command-line interface for [Totem](https://github.com/mmnto-ai/totem), a persistent memory and context layer for AI coding agents. Installs the `totem` binary.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add -D @mmnto/cli
9
+ # or run without installing
10
+ pnpm dlx @mmnto/cli init
11
+ ```
12
+
13
+ Requires Node >= 24.
14
+
15
+ ## Usage
16
+
17
+ ```bash
18
+ totem init # scaffold totem.config.ts, git hooks, and baseline rules
19
+ totem lint # run compiled rules against your changes (zero LLM, offline)
20
+ totem lesson compile # compile markdown lessons into regex/AST rules (needs an LLM key)
21
+ totem lesson extract # extract lessons from PR reviews (needs an LLM key)
22
+ totem sync # rebuild the semantic index (needs an embedding key)
23
+ totem --help # full command list
24
+ ```
25
+
26
+ `totem init`, `totem lint`, and the git hooks run with no API keys. LLM-backed commands (`lesson compile`, `lesson extract`, `review`, `spec`) use the orchestrator configured in `totem.config.ts`; the Anthropic, OpenAI, and Google SDKs are optional peer dependencies loaded only when configured.
27
+
28
+ ## Docs
29
+
30
+ - Repository: <https://github.com/mmnto-ai/totem>
31
+ - Architecture: [docs/reference/architecture.md](https://github.com/mmnto-ai/totem/blob/main/docs/reference/architecture.md)
32
+ - CLI reference: [docs/wiki/cli-reference.md](https://github.com/mmnto-ai/totem/blob/main/docs/wiki/cli-reference.md)
33
+
34
+ Apache-2.0.
@@ -0,0 +1,259 @@
1
+ /**
2
+ * `totem ecl-gc` — ECL outbox retention prune (mmnto-ai/totem#2279; parent
3
+ * mmnto-ai/totem-strategy#700 / doctrine/ecl-discipline.md § 4.4).
4
+ *
5
+ * The binary-guaranteed cohort-wide replacement for the interim
6
+ * `scripts/prune-outbox.mjs`: it deletes an agent's OWN outbox dispatches once
7
+ * they age past the retention window N (default 14 days). Outbox dispatches are
8
+ * TRANSPORT, not archive — the durable record of whatever a dispatch carried
9
+ * lives in its home (rulings → ADRs / issues, work-state → the GH board,
10
+ * session history → `journal/`), so an aged courier file is disposable.
11
+ *
12
+ * SINGLE-WRITER INVARIANT (ADR-106): each agent prunes only its OWN
13
+ * `<repoRoot>/.totem/orchestration/<agent-id>/outbox/` — never a peer's, never
14
+ * the operator's chore. Self-resolution (Tenet-21 reuse of `resolveSelfSender`)
15
+ * makes pruning a peer structurally unreachable: the target path is composed
16
+ * from the resolved single agent-id and nothing else. This command NEVER reads
17
+ * or touches `journal/` (bounded-past record + MCP-indexed) or `processed/`
18
+ * (the handled-state cursor — erasing it makes consumed backlog re-read as
19
+ * unread) or any inbox / other seat. Scope is `outbox/` only.
20
+ *
21
+ * Safe by default: dry-run (list only) unless `--apply` is passed.
22
+ *
23
+ * COMPACTION (mmnto-ai/totem#2307; contract ADR-106 § A2 + ecl-discipline § 4.5,
24
+ * ratified strategy#826). `eclCompact` is the cursor-coupled processed-mark GC
25
+ * sibling of the prune above: it deletes an agent's OWN `processed/` marks that
26
+ * shadow nothing — a mark whose inbound dispatch its sender already swept per
27
+ * § 4.4. The retained cursor is `processed ∩ raw-addressed-inbound` (A2.1: the
28
+ * PRE-dedupe scan, never `pollMail`'s `inbound − processed` list). Deletion is
29
+ * licensed ONLY against a provably-complete poll (A2.2: full expected roster
30
+ * present, zero warnings, not truncated — else zero deletes), binds to exactly
31
+ * one seat (A2.3), and self-verifies via an immediate re-poll (A2.4). Unlike the
32
+ * prune's age window, compaction couples to the outbox lifecycle, not to time.
33
+ */
34
+ export interface EclGcOptions {
35
+ /** Actually delete (default: dry-run — list would-prune, delete nothing). */
36
+ apply?: boolean;
37
+ /** Retention window in days (default 14). Must be a non-negative integer. */
38
+ retainDays?: number;
39
+ /**
40
+ * Override the self-resolved agent-id (visiting / orchestrator case only).
41
+ * NOT used by the signoff step — that path self-resolves.
42
+ */
43
+ agentId?: string;
44
+ /** Repo root override (default: `process.cwd()`). Test injection point. */
45
+ repoRoot?: string;
46
+ /** Env override (default: `process.env`). Test injection point. */
47
+ env?: Record<string, string | undefined>;
48
+ /** Clock injection for deterministic cutoffs in tests (default: `new Date()`). */
49
+ now?: () => Date;
50
+ }
51
+ /**
52
+ * Structured prune result. Also the `--json` payload. `pruned` lists the files
53
+ * actually removed under `--apply` (or the would-prune set in dry-run);
54
+ * `failed` captures per-file delete failures (never fatal); `skipped` surfaces
55
+ * every entry left untouched together with WHY (non-file, non-`.md`,
56
+ * unparseable stamp).
57
+ */
58
+ export interface EclGcResult {
59
+ agent: string;
60
+ retainDays: number;
61
+ dryRun: boolean;
62
+ outbox: string;
63
+ cutoffKey: string;
64
+ pruned: string[];
65
+ failed: {
66
+ file: string;
67
+ error: string;
68
+ }[];
69
+ kept: number;
70
+ skipped: {
71
+ file: string;
72
+ reason: string;
73
+ }[];
74
+ warnings: string[];
75
+ }
76
+ /**
77
+ * Canonicalize either stamp form to a 14-digit `YYYYMMDDHHMMSS` key (seconds
78
+ * default to `00`) so mixed-length stamps compare correctly. Ported from
79
+ * `scripts/prune-outbox.mjs:toKey`.
80
+ */
81
+ export declare function toStampKey(stamp: string): string;
82
+ /**
83
+ * Cutoff = `now − retainDays`, as a comparable 14-digit `YYYYMMDDHHMMSS` key.
84
+ * Derives from the injected `now` for determinism (Tenet 15). Ported from
85
+ * `scripts/prune-outbox.mjs:cutoffKey`.
86
+ */
87
+ export declare function cutoffKey(now: Date, retainDays: number): string;
88
+ /** A directory entry reduced to the classification inputs (pure-helper seam). */
89
+ export interface DirEntryLike {
90
+ name: string;
91
+ isFile: boolean;
92
+ }
93
+ /** The per-entry verdict a classifier returns. */
94
+ export type PruneClass = {
95
+ action: 'prune';
96
+ } | {
97
+ action: 'keep';
98
+ } | {
99
+ action: 'skip';
100
+ reason: string;
101
+ };
102
+ /**
103
+ * Classify a single directory entry against the cutoff. Safe-direction bias:
104
+ * anything whose age is not derivable from an eligible filename is KEPT +
105
+ * surfaced, never deleted (auto-deleting an un-ageable file is worse than
106
+ * letting it linger — mmnto-ai/totem-strategy#700 by-design). Non-file entries
107
+ * are checked FIRST so a directory named `*.md` can never reach a delete.
108
+ */
109
+ export declare function classifyEntry(entry: DirEntryLike, cutoff: string): PruneClass;
110
+ /** The classification plan for a whole directory listing. */
111
+ export interface PrunePlan {
112
+ prune: string[];
113
+ kept: number;
114
+ skipped: {
115
+ file: string;
116
+ reason: string;
117
+ }[];
118
+ }
119
+ /**
120
+ * Pure prune-plan classification: given a directory listing + a cutoff key,
121
+ * partition entries into prune / keep / skip. Deterministic order (filename
122
+ * sort) so the reported lists are stable across platforms.
123
+ */
124
+ export declare function planPrune(entries: DirEntryLike[], cutoff: string): PrunePlan;
125
+ /**
126
+ * Programmatic entry point. Resolves the single self-agent, validates inputs,
127
+ * scans that agent's OWN outbox, and (under `--apply`) deletes the aged
128
+ * dispatches. Returns a structured `EclGcResult`.
129
+ *
130
+ * Throws ONLY on usage errors (unresolvable/ambiguous self, unsafe agent-id,
131
+ * invalid `--retain-days`), and always BEFORE any directory scan or deletion.
132
+ * Filesystem failures are NEVER thrown — a per-file delete failure is captured
133
+ * into `result.failed` (janitorial sensor, not a gate — Tenet 13).
134
+ */
135
+ export declare function eclGc(opts?: EclGcOptions): EclGcResult;
136
+ /**
137
+ * Render an `EclGcResult`. With `json`, the structured result goes to stdout
138
+ * (hook-friendly clean stream). Otherwise a human summary goes to stderr via
139
+ * the standard CLI logger (agent, mode, pruned/kept counts, skipped-with-
140
+ * reasons, failed count) — mirrors `mail.ts`'s stderr `log` usage.
141
+ */
142
+ export declare function eclGcCommand(result: EclGcResult, json: boolean): Promise<EclGcResult>;
143
+ export interface EclCompactOptions {
144
+ /** Actually delete inert marks (default: dry-run — list would-collect only). */
145
+ apply?: boolean;
146
+ /**
147
+ * Override the self-resolved agent-id (visiting/orchestrator case). The
148
+ * single-writer compaction target; NOT used by the signoff step (self-resolves).
149
+ */
150
+ agentId?: string;
151
+ /** Repo root override (default: `process.cwd()`). Test injection point. */
152
+ repoRoot?: string;
153
+ /** Env override (default: `process.env`). Test injection point. */
154
+ env?: Record<string, string | undefined>;
155
+ /** Workspace override (default: `TOTEM_WORKSPACE` env, else parent of repoRoot). */
156
+ workspace?: string;
157
+ /** Scan cap override (default: mail's `MAX_SCAN`). Injection point for the
158
+ * A2.2 truncation abort arm — exercised with small fixtures. */
159
+ maxScan?: number;
160
+ /**
161
+ * Declared expected cohort repo roster for the A2.2 completeness gate — the
162
+ * yardstick the workspace glob is checked against (default: `cohortRepos()`,
163
+ * the strategy#611 interim constant pending config-ification, mmnto-ai/totem#2310).
164
+ * An EMPTY roster is the "undeclared" case: compaction HARD-ABORTS (fail-loud,
165
+ * exit 3), never "assume complete" and never a silent no-op — completeness is
166
+ * unprovable without a declared expectation (strategy#828 no-roster corollary).
167
+ * Tests inject explicitly.
168
+ */
169
+ expectedRepos?: string[];
170
+ /**
171
+ * Operator escape (`--force-incomplete`): proceed with compaction even when
172
+ * the workspace glob is a strict subset of the declared roster (a cohort repo
173
+ * is absent). UNSAFE — a live mark in an unscanned repo can be collected as a
174
+ * false-unread; use only when you know the absent repo holds no inbound for
175
+ * this seat. Bypasses ONLY the roster-presence check; scan warnings and
176
+ * truncation remain hard aborts, and an undeclared (empty) roster still
177
+ * hard-aborts (there is no presence to force when nothing was declared).
178
+ */
179
+ forceIncomplete?: boolean;
180
+ }
181
+ /**
182
+ * Structured compaction result. Also the `--json` payload. `collectable` is the
183
+ * would-collect set in dry-run (or the eligible set pre-delete under apply);
184
+ * `collected` is what actually got deleted (gate-green only); `resurfaced` is
185
+ * the A2.4 falsifier output — MUST be empty (a non-empty set means a live mark
186
+ * was collected and the completeness gate was too weak).
187
+ */
188
+ export interface EclCompactResult {
189
+ agent: string;
190
+ dryRun: boolean;
191
+ workspace: string;
192
+ expectedRepos: string[];
193
+ /**
194
+ * Whether a non-empty roster was declared. `false` = the undeclared case,
195
+ * folded INTO the A2.2 gate: `gateComplete` is also false and compaction
196
+ * HARD-ABORTS (exit 3), because completeness cannot be proven without a
197
+ * declared expectation (strategy#828). Retained only to frame the specific
198
+ * operator message ("no cohort roster declared" vs a missing/unscannable repo).
199
+ */
200
+ rosterDeclared: boolean;
201
+ /** A2.2 gate: true iff full roster present (or forced) AND zero scan warnings AND not truncated. */
202
+ gateComplete: boolean;
203
+ /** Why the gate is red (missing repos, scan/read/parse warnings, truncation); empty iff complete. */
204
+ gateReasons: string[];
205
+ /** Count of raw addressed-inbound basenames discovered (pre-dedupe; to:S ∪ broadcast). */
206
+ rawInbound: number;
207
+ /** Total own processed marks examined (direct ∪ broadcast). */
208
+ marks: number;
209
+ /** Marks whose dispatch is absent from raw inbound — the would-collect set (dry-run / pre-delete). */
210
+ collectable: string[];
211
+ /** Marks actually deleted (⊆ collectable; gate-green apply only). */
212
+ collected: string[];
213
+ /** Marks left in place after the run. */
214
+ retained: number;
215
+ failed: {
216
+ file: string;
217
+ error: string;
218
+ }[];
219
+ /** A2.4 falsifier: previously-handled dispatches that re-surfaced as unread post-compact (MUST be []). */
220
+ resurfaced: string[];
221
+ /**
222
+ * A2.4 self-check trustworthiness: `false` iff the post-compact re-poll was
223
+ * itself truncated or warned, so a resurfaced dispatch beyond its horizon
224
+ * could read as clean. An untrustworthy verify is a hard failure (we deleted
225
+ * marks and cannot confirm no resurface) — maps to the abort exit code.
226
+ */
227
+ verifyComplete: boolean;
228
+ warnings: string[];
229
+ }
230
+ /**
231
+ * Programmatic entry point for cursor-coupled processed-mark compaction. For a
232
+ * single resolved seat, deletes `processed/` marks whose inbound dispatch is
233
+ * absent from the RAW addressed-inbound set (A2.1) — but ONLY when discovery is
234
+ * provably complete (A2.2), and then self-verifies (A2.4).
235
+ *
236
+ * Throws ONLY on usage errors (unresolvable/ambiguous self, unsafe agent-id),
237
+ * always BEFORE any scan or deletion (exit-2 class, parity with `eclGc`). Every
238
+ * safety failure (incomplete roster, scan warning, truncation) is a STRUCTURED
239
+ * gate-red result with zero deletes, never a throw — the caller maps it to the
240
+ * compaction-abort exit code.
241
+ */
242
+ export declare function eclCompact(opts?: EclCompactOptions): EclCompactResult;
243
+ /**
244
+ * Render an `EclCompactResult`. `--json` → structured stdout; otherwise a human
245
+ * summary to stderr. A red gate reports the reasons + zero deletes; a tripped
246
+ * A2.4 falsifier and per-mark delete failures are surfaced via the error logger.
247
+ */
248
+ export declare function eclCompactCommand(result: EclCompactResult, json: boolean): Promise<EclCompactResult>;
249
+ /**
250
+ * Combined prune+compact exit-code contract (codex panel, mmnto-ai/totem#2307).
251
+ * Pure so the precedence is unit-testable independent of the CLI wrapper. The
252
+ * usage code `2` is NOT modeled here — it is the thrown-error path the wrapper
253
+ * catches around this call. Precedence: `3` (compaction abort — A2.2 gate red or
254
+ * A2.4 falsifier tripped) outranks `1` (partial janitorial delete failure, from
255
+ * either phase), which outranks `0` (clean). So a prune-partial + compact-abort
256
+ * is `3`, with the prune count still carried in the structured result.
257
+ */
258
+ export declare function resolveEclGcExitCode(prune: Pick<EclGcResult, 'failed'>, compact?: Pick<EclCompactResult, 'gateComplete' | 'resurfaced' | 'verifyComplete' | 'failed'>): 0 | 1 | 3;
259
+ //# sourceMappingURL=ecl-gc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecl-gc.d.ts","sourceRoot":"","sources":["../../src/commands/ecl-gc.ts"],"names":[],"mappings":"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"}