@mrsf/cli 0.7.1 → 0.8.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/LICENSE +21 -21
- package/README.md +513 -513
- package/dist/bin.js +6 -6
- package/dist/browser.cjs +2 -2
- package/dist/browser.cjs.map +1 -1
- package/dist/commands/add.js +3 -3
- package/dist/index.cjs +17 -6
- package/dist/index.cjs.map +3 -3
- package/dist/lib/comments.d.ts +2 -1
- package/dist/lib/comments.js +2 -1
- package/dist/lib/reanchor.js +1 -1
- package/dist/lib/types.d.ts +2 -0
- package/dist/lib/writer.js +15 -1
- package/mrsf.schema.json +113 -113
- package/package.json +95 -95
package/README.md
CHANGED
|
@@ -1,513 +1,513 @@
|
|
|
1
|
-
# MRSF CLI
|
|
2
|
-
|
|
3
|
-
[](LICENSE)
|
|
4
|
-
[](MRSF-v1.0.md)
|
|
5
|
-
[](https://www.npmjs.com/package/@mrsf/cli)
|
|
6
|
-
[](https://www.npmjs.com/package/@mrsf/cli)
|
|
7
|
-
|
|
8
|
-
Command-line tool and Node.js library for **Sidemark** — the **Markdown Review Sidecar Format** ([MRSF v1.0](../MRSF-v1.0.md)).
|
|
9
|
-
|
|
10
|
-
Validate sidecars, add and resolve review comments, re-anchor comments after document edits, and integrate MRSF into CI/CD pipelines — all from the terminal.
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
╔╦╗╦═╗╔═╗╔═╗
|
|
14
|
-
║║║╠╦╝╚═╗╠╣
|
|
15
|
-
╩ ╩╩╚═╚═╝╚
|
|
16
|
-
Markdown Review Sidecar Format
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Quick Start
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
# Install globally
|
|
23
|
-
npm install -g @mrsf/cli
|
|
24
|
-
|
|
25
|
-
# …or run without installing
|
|
26
|
-
npx @mrsf/cli --help
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### From source
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
git clone https://github.com/wictorwilen/MRSF.git
|
|
33
|
-
cd MRSF/cli
|
|
34
|
-
npm install
|
|
35
|
-
npm run build
|
|
36
|
-
node dist/bin.js --help
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Browser / Embedder API (`@mrsf/cli/browser`)
|
|
40
|
-
|
|
41
|
-
Use `@mrsf/cli/browser` in Vite, Electron renderers, and editor extensions that
|
|
42
|
-
need side-effect-free MRSF helpers without Node built-ins. This entrypoint does
|
|
43
|
-
not import `fs`, git helpers, or other Node-only APIs, and is designed to be
|
|
44
|
-
tree-shakeable.
|
|
45
|
-
|
|
46
|
-
Key exports include:
|
|
47
|
-
|
|
48
|
-
- Types: `MrsfDocument`, `Comment`, `AnchorPosition`
|
|
49
|
-
- Anchoring: `resolveAnchor`, `reanchorComment`, `reanchorDocumentText`,
|
|
50
|
-
`toReanchorLines`, `applyReanchorResults`
|
|
51
|
-
- Validation: `validateDocument`, `mrsfSchema`
|
|
52
|
-
- Identity: `formatAuthor`, `parseAuthor`, `newCommentId`
|
|
53
|
-
- Pure fuzzy helpers: `exactMatch`, `normalizedMatch`, `fuzzySearch`,
|
|
54
|
-
`combinedScore`
|
|
55
|
-
|
|
56
|
-
Example editor decoration flow:
|
|
57
|
-
|
|
58
|
-
```ts
|
|
59
|
-
import { resolveAnchor, type Comment } from "@mrsf/cli/browser";
|
|
60
|
-
|
|
61
|
-
function decorationRange(comment: Comment, text: string) {
|
|
62
|
-
const anchor = resolveAnchor(comment, text);
|
|
63
|
-
if (anchor.from == null || anchor.to == null) return undefined;
|
|
64
|
-
return { from: anchor.from, to: anchor.to };
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Commands
|
|
69
|
-
|
|
70
|
-
### `mrsf validate [files...]`
|
|
71
|
-
|
|
72
|
-
Validate sidecar files against the JSON Schema and MRSF spec rules.
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
# Validate a single sidecar
|
|
76
|
-
mrsf validate docs/architecture.md.review.yaml
|
|
77
|
-
|
|
78
|
-
# Validate all sidecars discovered in the workspace
|
|
79
|
-
mrsf validate
|
|
80
|
-
|
|
81
|
-
# Treat warnings as errors (useful for CI)
|
|
82
|
-
mrsf validate --strict
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
| Option | Description |
|
|
86
|
-
|---|---|
|
|
87
|
-
| `-s, --strict` | Treat warnings as errors (exit non-zero) |
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
### `mrsf add <document>`
|
|
92
|
-
|
|
93
|
-
Add a review comment to a document's sidecar file. Creates the sidecar if it doesn't exist. Automatically populates `selected_text` from the document when a line is specified, and stamps the current git commit. When `--author` is omitted, MRSF uses `user.name` from the repository-local `.git/config`; global Git identity is not used.
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
# Add a line comment
|
|
97
|
-
mrsf add docs/api.md \
|
|
98
|
-
--author "alice" \
|
|
99
|
-
--text "Clarify the rate limit behavior" \
|
|
100
|
-
--line 42
|
|
101
|
-
|
|
102
|
-
# Add a column-span comment with type and severity
|
|
103
|
-
mrsf add docs/api.md \
|
|
104
|
-
--author "bob" \
|
|
105
|
-
--text "Typo: should be 'response'" \
|
|
106
|
-
--line 18 --start-column 10 --end-column 18 \
|
|
107
|
-
--type suggestion --severity low
|
|
108
|
-
|
|
109
|
-
# Reply to an existing comment
|
|
110
|
-
mrsf add docs/api.md \
|
|
111
|
-
--author "alice" \
|
|
112
|
-
--text "Good catch, fixed in abc123" \
|
|
113
|
-
--reply-to 3eeccbd3
|
|
114
|
-
|
|
115
|
-
# Attach tool-specific x_* metadata
|
|
116
|
-
mrsf add docs/api.md \
|
|
117
|
-
--author "bot" \
|
|
118
|
-
--text "Flagging this for follow-up" \
|
|
119
|
-
--line 27 \
|
|
120
|
-
--ext x_source=triage-bot \
|
|
121
|
-
--ext x_score=0.91 \
|
|
122
|
-
--ext 'x_labels=["needs-review","docs"]'
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
| Option | Description |
|
|
126
|
-
|---|---|
|
|
127
|
-
| `-a, --author <name>` | Comment author; overrides repository-local Git `user.name` |
|
|
128
|
-
| `-t, --text <text>` | Comment body (required) |
|
|
129
|
-
| `-l, --line <n>` | Line number (1-based) |
|
|
130
|
-
| `--end-line <n>` | End line (inclusive) |
|
|
131
|
-
| `--start-column <n>` | Start column (0-based) |
|
|
132
|
-
| `--end-column <n>` | End column (0-based) |
|
|
133
|
-
| `--type <type>` | Category: `suggestion`, `issue`, `question`, `accuracy`, `style`, `clarity` |
|
|
134
|
-
| `--severity <level>` | Importance: `low`, `medium`, `high` |
|
|
135
|
-
| `--reply-to <id>` | Reply to an existing comment by ID |
|
|
136
|
-
| `--selected-text <text>` | Override auto-detected selected text |
|
|
137
|
-
| `--ext <key=value>` | Add an `x_*` extension field; repeat for multiple fields |
|
|
138
|
-
|
|
139
|
-
`--ext` values are stored as flat `x_*` fields in the sidecar. Primitive JSON literals like numbers, `true`, `false`, and `null` are parsed automatically, and objects/arrays can be passed as JSON.
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
### `mrsf resolve <sidecar> <id>`
|
|
144
|
-
|
|
145
|
-
Resolve (or unresolve) a comment by ID.
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
# Resolve a comment
|
|
149
|
-
mrsf resolve docs/api.md.review.yaml 1d3c72b0
|
|
150
|
-
|
|
151
|
-
# Unresolve it
|
|
152
|
-
mrsf resolve --undo docs/api.md.review.yaml 1d3c72b0
|
|
153
|
-
|
|
154
|
-
# Resolve and cascade to all direct replies
|
|
155
|
-
mrsf resolve --cascade docs/api.md.review.yaml 1d3c72b0
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
| Option | Description |
|
|
159
|
-
|---|---|
|
|
160
|
-
| `--cascade` | Also resolve direct replies |
|
|
161
|
-
| `-u, --undo` | Unresolve instead of resolving |
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
### `mrsf list [files...]`
|
|
166
|
-
|
|
167
|
-
List and filter comments across one or more sidecar files.
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
# List all open comments
|
|
171
|
-
mrsf list --open docs/api.md.review.yaml
|
|
172
|
-
|
|
173
|
-
# Filter by author and severity
|
|
174
|
-
mrsf list --author alice --severity high
|
|
175
|
-
|
|
176
|
-
# Summary view (counts, types, severities)
|
|
177
|
-
mrsf list --summary
|
|
178
|
-
|
|
179
|
-
# Machine-readable JSON output
|
|
180
|
-
mrsf list --json --open
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
| Option | Description |
|
|
184
|
-
|---|---|
|
|
185
|
-
| `--open` | Show only open (unresolved) comments |
|
|
186
|
-
| `--resolved` | Show only resolved comments |
|
|
187
|
-
| `--orphaned` | Show only orphaned comments |
|
|
188
|
-
| `--author <name>` | Filter by author |
|
|
189
|
-
| `--type <type>` | Filter by comment type |
|
|
190
|
-
| `--severity <level>` | Filter by severity |
|
|
191
|
-
| `--summary` | Show aggregate summary instead of individual comments |
|
|
192
|
-
| `--json` | Output as JSON |
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
### `mrsf reanchor [files...]`
|
|
197
|
-
|
|
198
|
-
Re-anchor comments after the source document has been edited. The repository's
|
|
199
|
-
**Anchor Mesh** implementation combines verified Git shifts, source-revision
|
|
200
|
-
projection, Markdown structure, bounded text matching, confidence calibration,
|
|
201
|
-
and nearby comments as landmarks. It prefers `ambiguous` or `orphaned` results
|
|
202
|
-
over an unsupported relocation.
|
|
203
|
-
|
|
204
|
-
See the
|
|
205
|
-
[non-normative implementation guide](https://sidemark.org/guide/reanchoring)
|
|
206
|
-
for the complete pipeline, execution modes, tuning values, and evaluation
|
|
207
|
-
methodology.
|
|
208
|
-
|
|
209
|
-
```bash
|
|
210
|
-
# Dry run — see what would change without writing
|
|
211
|
-
mrsf reanchor --dry-run docs/api.md.review.yaml
|
|
212
|
-
|
|
213
|
-
# Re-anchor with a higher fuzzy threshold (stricter matching)
|
|
214
|
-
mrsf reanchor --threshold 0.8
|
|
215
|
-
|
|
216
|
-
# Only process sidecars for staged files (pre-commit hook)
|
|
217
|
-
mrsf reanchor --staged
|
|
218
|
-
|
|
219
|
-
# Disable git (pure text-based matching only)
|
|
220
|
-
mrsf reanchor --no-git
|
|
221
|
-
|
|
222
|
-
# Override the from-commit for all comments
|
|
223
|
-
mrsf reanchor --from abc1234
|
|
224
|
-
|
|
225
|
-
# Also update selected_text to match the current document text (opt-in)
|
|
226
|
-
mrsf reanchor --update-text
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
| Option | Description | Default |
|
|
230
|
-
|---|---|---|
|
|
231
|
-
| `-n, --dry-run` | Report without modifying files | `false` |
|
|
232
|
-
| `-t, --threshold <n>` | Fuzzy match threshold (0.0–1.0) | `0.6` |
|
|
233
|
-
| `--staged` | Only process sidecars for git-staged documents | `false` |
|
|
234
|
-
| `--no-git` | Disable git integration entirely | git enabled |
|
|
235
|
-
| `--from <commit>` | Override from-commit for diff calculation | per-comment `commit` field |
|
|
236
|
-
| `--update-text` | Also replace `selected_text` with current document text | `false` |
|
|
237
|
-
|
|
238
|
-
> **Text preservation (§6.2):** By default, re-anchoring preserves the
|
|
239
|
-
> original `selected_text` and records the current document text in
|
|
240
|
-
> `anchored_text`. Use `--update-text` to opt in to overwriting
|
|
241
|
-
> `selected_text` directly.
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
### `mrsf status [files...]`
|
|
246
|
-
|
|
247
|
-
Assess anchor health for each comment.
|
|
248
|
-
|
|
249
|
-
```bash
|
|
250
|
-
mrsf status docs/api.md.review.yaml
|
|
251
|
-
mrsf status --json
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Health states:
|
|
255
|
-
|
|
256
|
-
| State | Meaning |
|
|
257
|
-
|---|---|
|
|
258
|
-
| `fresh` | `selected_text` matches at the recorded position |
|
|
259
|
-
| `stale` | `selected_text` matches but at a different position, or commit differs |
|
|
260
|
-
| `orphaned` | `selected_text` not found in the document |
|
|
261
|
-
| `unknown` | No `selected_text` to verify |
|
|
262
|
-
|
|
263
|
-
| Option | Description |
|
|
264
|
-
|---|---|
|
|
265
|
-
| `--json` | Output as JSON |
|
|
266
|
-
|
|
267
|
-
---
|
|
268
|
-
|
|
269
|
-
### `mrsf init <document>`
|
|
270
|
-
|
|
271
|
-
Create an empty sidecar file for a Markdown document.
|
|
272
|
-
|
|
273
|
-
```bash
|
|
274
|
-
mrsf init docs/new-feature.md
|
|
275
|
-
mrsf init --force docs/existing.md # overwrite
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
| Option | Description |
|
|
279
|
-
|---|---|
|
|
280
|
-
| `-f, --force` | Overwrite an existing sidecar |
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
### `mrsf rename <old-document> <new-document>`
|
|
285
|
-
|
|
286
|
-
Update a sidecar after its source document has been renamed or moved.
|
|
287
|
-
|
|
288
|
-
```bash
|
|
289
|
-
mrsf rename docs/old-name.md docs/new-name.md
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
Updates the `document` field inside the sidecar, writes it to the new path, and removes the old sidecar file.
|
|
293
|
-
|
|
294
|
-
### `mrsf watch [files...]`
|
|
295
|
-
|
|
296
|
-
Watch files for changes and continuously validate (and optionally reanchor).
|
|
297
|
-
|
|
298
|
-
```bash
|
|
299
|
-
# Validate all sidecars on every change
|
|
300
|
-
mrsf watch
|
|
301
|
-
|
|
302
|
-
# Watch specific files
|
|
303
|
-
mrsf watch docs/api.md docs/guide.md
|
|
304
|
-
|
|
305
|
-
# Auto-reanchor when Markdown files change
|
|
306
|
-
mrsf watch --reanchor
|
|
307
|
-
|
|
308
|
-
# Preview reanchor changes without writing
|
|
309
|
-
mrsf watch --reanchor --dry-run
|
|
310
|
-
|
|
311
|
-
# Custom threshold and strict validation
|
|
312
|
-
mrsf watch --reanchor --threshold 0.8 --strict
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
**Trigger rules** (avoids feedback loops):
|
|
316
|
-
|
|
317
|
-
| File type | Action |
|
|
318
|
-
|---|---|
|
|
319
|
-
| `.md` (Markdown) | Reanchor (if `--reanchor` is set), then validate sidecar |
|
|
320
|
-
| `.review.yaml` / `.review.json` | Validate only |
|
|
321
|
-
|
|
322
|
-
| Option | Description |
|
|
323
|
-
|---|---|
|
|
324
|
-
| `--reanchor` | Auto-reanchor when Markdown files change |
|
|
325
|
-
| `-n, --dry-run` | Preview reanchor changes without writing |
|
|
326
|
-
| `-t, --threshold <n>` | Fuzzy match threshold 0.0–1.0 (default `0.6`) |
|
|
327
|
-
| `-s, --strict` | Treat validation warnings as errors |
|
|
328
|
-
| `--no-git` | Disable git integration |
|
|
329
|
-
| `--from <commit>` | Override from-commit for reanchor |
|
|
330
|
-
| `--update-text` | Update `selected_text` on reanchor |
|
|
331
|
-
| `-f, --force` | Force reanchor — update commit, clear audit fields |
|
|
332
|
-
| `--debounce <ms>` | Debounce interval in ms (default `300`) |
|
|
333
|
-
|
|
334
|
-
Press `Ctrl+C` to stop — a summary of events, reanchors, and errors is printed.
|
|
335
|
-
|
|
336
|
-
## Global Options
|
|
337
|
-
|
|
338
|
-
These apply to all commands:
|
|
339
|
-
|
|
340
|
-
| Option | Description |
|
|
341
|
-
|---|---|
|
|
342
|
-
| `--cwd <dir>` | Override the working directory |
|
|
343
|
-
| `--config <path>` | Path to `.mrsf.yaml` configuration |
|
|
344
|
-
| `--no-color` | Disable coloured output |
|
|
345
|
-
| `-q, --quiet` | Suppress informational output |
|
|
346
|
-
| `-V, --version` | Print version |
|
|
347
|
-
| `-h, --help` | Show help |
|
|
348
|
-
|
|
349
|
-
## CI/CD Integration
|
|
350
|
-
|
|
351
|
-
### GitHub Actions
|
|
352
|
-
|
|
353
|
-
```yaml
|
|
354
|
-
name: MRSF Review Lint
|
|
355
|
-
on: [pull_request]
|
|
356
|
-
jobs:
|
|
357
|
-
mrsf:
|
|
358
|
-
runs-on: ubuntu-latest
|
|
359
|
-
steps:
|
|
360
|
-
- uses: actions/checkout@v4
|
|
361
|
-
- uses: actions/setup-node@v4
|
|
362
|
-
with:
|
|
363
|
-
node-version: 20
|
|
364
|
-
- run: npx @mrsf/cli validate --strict
|
|
365
|
-
- run: npx @mrsf/cli reanchor --staged --dry-run
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
### Git Pre-commit Hook
|
|
369
|
-
|
|
370
|
-
```bash
|
|
371
|
-
#!/usr/bin/env bash
|
|
372
|
-
# .git/hooks/pre-commit
|
|
373
|
-
npx @mrsf/cli reanchor --staged
|
|
374
|
-
npx @mrsf/cli validate --strict
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Git Post-merge Hook
|
|
378
|
-
|
|
379
|
-
```bash
|
|
380
|
-
#!/usr/bin/env bash
|
|
381
|
-
# .git/hooks/post-merge
|
|
382
|
-
npx @mrsf/cli reanchor
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
## Library Usage
|
|
386
|
-
|
|
387
|
-
The CLI is built library-first. All functionality is available as importable functions:
|
|
388
|
-
|
|
389
|
-
```typescript
|
|
390
|
-
import {
|
|
391
|
-
parseSidecar,
|
|
392
|
-
parseSidecarLenient,
|
|
393
|
-
writeSidecar,
|
|
394
|
-
validate,
|
|
395
|
-
reanchorDocument,
|
|
396
|
-
addComment,
|
|
397
|
-
resolveComment,
|
|
398
|
-
removeComment,
|
|
399
|
-
filterComments,
|
|
400
|
-
summarize,
|
|
401
|
-
discoverSidecar,
|
|
402
|
-
discoverAllSidecars,
|
|
403
|
-
} from "@mrsf/cli";
|
|
404
|
-
|
|
405
|
-
// Validate a sidecar programmatically
|
|
406
|
-
const doc = await parseSidecar("docs/api.md.review.yaml");
|
|
407
|
-
const result = await validate(doc);
|
|
408
|
-
console.log(result.valid, result.errors, result.warnings);
|
|
409
|
-
|
|
410
|
-
// Add a comment
|
|
411
|
-
const updated = addComment(doc, lines, {
|
|
412
|
-
author: "ci-bot",
|
|
413
|
-
text: "Auto-generated review comment",
|
|
414
|
-
line: 10,
|
|
415
|
-
});
|
|
416
|
-
await writeSidecar("docs/api.md.review.yaml", updated);
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### Browser-safe reanchoring
|
|
420
|
-
|
|
421
|
-
The default `@mrsf/cli` entrypoint is Node-oriented and includes file system and git-backed helpers such as `parseSidecar`, `readDocumentLines`, and `reanchorFile`. For browser bundles and editor integrations, use the `@mrsf/cli/browser` subpath instead.
|
|
422
|
-
|
|
423
|
-
`@mrsf/cli/browser` exports the pure text-based matching and reanchoring primitives only:
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
import {
|
|
427
|
-
applyReanchorResults,
|
|
428
|
-
reanchorDocumentText,
|
|
429
|
-
} from "@mrsf/cli/browser";
|
|
430
|
-
|
|
431
|
-
const results = reanchorDocumentText(sidecar, markdownText);
|
|
432
|
-
const changed = applyReanchorResults(sidecar, results);
|
|
433
|
-
|
|
434
|
-
console.log(changed, results.map((result) => result.status));
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
Use this entrypoint when you already have the document text and sidecar object in memory. It intentionally excludes Node-only helpers such as sidecar discovery, file parsing, file writing, and git-aware diff reanchoring.
|
|
438
|
-
|
|
439
|
-
## Configuration
|
|
440
|
-
|
|
441
|
-
Place a `.mrsf.yaml` at your repository root to configure sidecar discovery:
|
|
442
|
-
|
|
443
|
-
```yaml
|
|
444
|
-
# Store all sidecars in a central directory instead of co-located
|
|
445
|
-
sidecar_root: .reviews
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
With this config, the sidecar for `docs/architecture.md` is resolved as `.reviews/docs/architecture.md.review.yaml`.
|
|
449
|
-
|
|
450
|
-
See [§3.2 Alternate Sidecar Location](../MRSF-v1.0.md) in the spec for details.
|
|
451
|
-
|
|
452
|
-
## Extension Fields (`x_*`)
|
|
453
|
-
|
|
454
|
-
MRSF reserves the `x_` prefix for tool-specific, non-standard extension properties (see [§10 Extension Fields](../MRSF-v1.0.md)). These fields may appear on the top-level document object or on individual comments. The CLI preserves them during round-trip writes and exposes them through the catch-all index signature on both `MrsfDocument` and `Comment`.
|
|
455
|
-
|
|
456
|
-
### Built-in `x_` fields
|
|
457
|
-
|
|
458
|
-
The CLI and Sidemark VS Code extension use the following extension fields:
|
|
459
|
-
|
|
460
|
-
| Field | Scope | Type | Set by | Description |
|
|
461
|
-
|---|---|---|---|---|
|
|
462
|
-
| `x_reanchor_status` | comment | `"anchored"` \| `"shifted"` \| `"fuzzy"` \| `"ambiguous"` \| `"orphaned"` | `mrsf reanchor` | Result of the most recent reanchor pass. `ambiguous` means evidence conflicts or multiple candidates remain; `orphaned` means no defensible anchor was found. |
|
|
463
|
-
| `x_reanchor_score` | comment | `number` (0–1) | `mrsf reanchor` | Confidence score from the reanchor algorithm. `1.0` = exact match, lower values indicate fuzzy or shifted matches. |
|
|
464
|
-
|
|
465
|
-
### Adding your own fields
|
|
466
|
-
|
|
467
|
-
Any property whose key starts with `x_` is valid on both the document root and on each comment. The CLI and Sidemark will silently preserve these fields through all operations (validate, add, resolve, reanchor, etc.).
|
|
468
|
-
|
|
469
|
-
```yaml
|
|
470
|
-
comments:
|
|
471
|
-
- id: abc123
|
|
472
|
-
author: ci-bot
|
|
473
|
-
timestamp: "2025-01-15T10:00:00Z"
|
|
474
|
-
text: Possible security concern
|
|
475
|
-
resolved: false
|
|
476
|
-
line: 42
|
|
477
|
-
# Custom extension fields
|
|
478
|
-
x_ai_confidence: 0.92
|
|
479
|
-
x_tool_name: security-scanner
|
|
480
|
-
x_category: injection
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
**Rules** (from the spec):
|
|
484
|
-
|
|
485
|
-
- Keys MUST start with `x_` (underscore, not hyphen).
|
|
486
|
-
- Implementations MUST NOT assign semantic meaning to `x_` fields defined by other tools.
|
|
487
|
-
- Future MRSF spec versions will never introduce normative fields with the `x_` prefix.
|
|
488
|
-
- Unknown `x_` fields are preserved by the CLI's round-trip writer and never stripped or modified.
|
|
489
|
-
|
|
490
|
-
### Programmatic access
|
|
491
|
-
|
|
492
|
-
```typescript
|
|
493
|
-
import { parseSidecar } from "@mrsf/cli";
|
|
494
|
-
|
|
495
|
-
const doc = await parseSidecar("file.md.review.yaml");
|
|
496
|
-
for (const comment of doc.comments) {
|
|
497
|
-
// Access built-in x_ fields
|
|
498
|
-
if (comment.x_reanchor_status === "orphaned") {
|
|
499
|
-
console.log(`Comment ${comment.id} is orphaned`);
|
|
500
|
-
}
|
|
501
|
-
// Access custom x_ fields
|
|
502
|
-
const confidence = comment.x_ai_confidence as number | undefined;
|
|
503
|
-
}
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
## Requirements
|
|
507
|
-
|
|
508
|
-
- Node.js 18 or later
|
|
509
|
-
- Git (optional — enables diff-based re-anchoring, commit stamping, rename detection)
|
|
510
|
-
|
|
511
|
-
## License
|
|
512
|
-
|
|
513
|
-
MIT — see [LICENSE](../LICENSE).
|
|
1
|
+
# MRSF CLI
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](MRSF-v1.0.md)
|
|
5
|
+
[](https://www.npmjs.com/package/@mrsf/cli)
|
|
6
|
+
[](https://www.npmjs.com/package/@mrsf/cli)
|
|
7
|
+
|
|
8
|
+
Command-line tool and Node.js library for **Sidemark** — the **Markdown Review Sidecar Format** ([MRSF v1.0](../MRSF-v1.0.md)).
|
|
9
|
+
|
|
10
|
+
Validate sidecars, add and resolve review comments, re-anchor comments after document edits, and integrate MRSF into CI/CD pipelines — all from the terminal.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
╔╦╗╦═╗╔═╗╔═╗
|
|
14
|
+
║║║╠╦╝╚═╗╠╣
|
|
15
|
+
╩ ╩╩╚═╚═╝╚
|
|
16
|
+
Markdown Review Sidecar Format
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Install globally
|
|
23
|
+
npm install -g @mrsf/cli
|
|
24
|
+
|
|
25
|
+
# …or run without installing
|
|
26
|
+
npx @mrsf/cli --help
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### From source
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/wictorwilen/MRSF.git
|
|
33
|
+
cd MRSF/cli
|
|
34
|
+
npm install
|
|
35
|
+
npm run build
|
|
36
|
+
node dist/bin.js --help
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Browser / Embedder API (`@mrsf/cli/browser`)
|
|
40
|
+
|
|
41
|
+
Use `@mrsf/cli/browser` in Vite, Electron renderers, and editor extensions that
|
|
42
|
+
need side-effect-free MRSF helpers without Node built-ins. This entrypoint does
|
|
43
|
+
not import `fs`, git helpers, or other Node-only APIs, and is designed to be
|
|
44
|
+
tree-shakeable.
|
|
45
|
+
|
|
46
|
+
Key exports include:
|
|
47
|
+
|
|
48
|
+
- Types: `MrsfDocument`, `Comment`, `AnchorPosition`
|
|
49
|
+
- Anchoring: `resolveAnchor`, `reanchorComment`, `reanchorDocumentText`,
|
|
50
|
+
`toReanchorLines`, `applyReanchorResults`
|
|
51
|
+
- Validation: `validateDocument`, `mrsfSchema`
|
|
52
|
+
- Identity: `formatAuthor`, `parseAuthor`, `newCommentId`
|
|
53
|
+
- Pure fuzzy helpers: `exactMatch`, `normalizedMatch`, `fuzzySearch`,
|
|
54
|
+
`combinedScore`
|
|
55
|
+
|
|
56
|
+
Example editor decoration flow:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { resolveAnchor, type Comment } from "@mrsf/cli/browser";
|
|
60
|
+
|
|
61
|
+
function decorationRange(comment: Comment, text: string) {
|
|
62
|
+
const anchor = resolveAnchor(comment, text);
|
|
63
|
+
if (anchor.from == null || anchor.to == null) return undefined;
|
|
64
|
+
return { from: anchor.from, to: anchor.to };
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Commands
|
|
69
|
+
|
|
70
|
+
### `mrsf validate [files...]`
|
|
71
|
+
|
|
72
|
+
Validate sidecar files against the JSON Schema and MRSF spec rules.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Validate a single sidecar
|
|
76
|
+
mrsf validate docs/architecture.md.review.yaml
|
|
77
|
+
|
|
78
|
+
# Validate all sidecars discovered in the workspace
|
|
79
|
+
mrsf validate
|
|
80
|
+
|
|
81
|
+
# Treat warnings as errors (useful for CI)
|
|
82
|
+
mrsf validate --strict
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Option | Description |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `-s, --strict` | Treat warnings as errors (exit non-zero) |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### `mrsf add <document>`
|
|
92
|
+
|
|
93
|
+
Add a review comment to a document's sidecar file. Creates the sidecar if it doesn't exist. Automatically populates `selected_text` from the document when a line is specified, and stamps the current git commit. When `--author` is omitted, MRSF uses `user.name` from the repository-local `.git/config`; global Git identity is not used.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Add a line comment
|
|
97
|
+
mrsf add docs/api.md \
|
|
98
|
+
--author "alice" \
|
|
99
|
+
--text "Clarify the rate limit behavior" \
|
|
100
|
+
--line 42
|
|
101
|
+
|
|
102
|
+
# Add a column-span comment with type and severity
|
|
103
|
+
mrsf add docs/api.md \
|
|
104
|
+
--author "bob" \
|
|
105
|
+
--text "Typo: should be 'response'" \
|
|
106
|
+
--line 18 --start-column 10 --end-column 18 \
|
|
107
|
+
--type suggestion --severity low
|
|
108
|
+
|
|
109
|
+
# Reply to an existing comment
|
|
110
|
+
mrsf add docs/api.md \
|
|
111
|
+
--author "alice" \
|
|
112
|
+
--text "Good catch, fixed in abc123" \
|
|
113
|
+
--reply-to 3eeccbd3
|
|
114
|
+
|
|
115
|
+
# Attach tool-specific x_* metadata
|
|
116
|
+
mrsf add docs/api.md \
|
|
117
|
+
--author "bot" \
|
|
118
|
+
--text "Flagging this for follow-up" \
|
|
119
|
+
--line 27 \
|
|
120
|
+
--ext x_source=triage-bot \
|
|
121
|
+
--ext x_score=0.91 \
|
|
122
|
+
--ext 'x_labels=["needs-review","docs"]'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
| Option | Description |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `-a, --author <name>` | Comment author; overrides repository-local Git `user.name` |
|
|
128
|
+
| `-t, --text <text>` | Comment body (required) |
|
|
129
|
+
| `-l, --line <n>` | Line number (1-based) |
|
|
130
|
+
| `--end-line <n>` | End line (inclusive) |
|
|
131
|
+
| `--start-column <n>` | Start column (0-based) |
|
|
132
|
+
| `--end-column <n>` | End column (0-based) |
|
|
133
|
+
| `--type <type>` | Category: `suggestion`, `issue`, `question`, `accuracy`, `style`, `clarity` |
|
|
134
|
+
| `--severity <level>` | Importance: `low`, `medium`, `high` |
|
|
135
|
+
| `--reply-to <id>` | Reply to an existing comment by ID |
|
|
136
|
+
| `--selected-text <text>` | Override auto-detected selected text |
|
|
137
|
+
| `--ext <key=value>` | Add an `x_*` extension field; repeat for multiple fields |
|
|
138
|
+
|
|
139
|
+
`--ext` values are stored as flat `x_*` fields in the sidecar. Primitive JSON literals like numbers, `true`, `false`, and `null` are parsed automatically, and objects/arrays can be passed as JSON.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### `mrsf resolve <sidecar> <id>`
|
|
144
|
+
|
|
145
|
+
Resolve (or unresolve) a comment by ID.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Resolve a comment
|
|
149
|
+
mrsf resolve docs/api.md.review.yaml 1d3c72b0
|
|
150
|
+
|
|
151
|
+
# Unresolve it
|
|
152
|
+
mrsf resolve --undo docs/api.md.review.yaml 1d3c72b0
|
|
153
|
+
|
|
154
|
+
# Resolve and cascade to all direct replies
|
|
155
|
+
mrsf resolve --cascade docs/api.md.review.yaml 1d3c72b0
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
| Option | Description |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `--cascade` | Also resolve direct replies |
|
|
161
|
+
| `-u, --undo` | Unresolve instead of resolving |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### `mrsf list [files...]`
|
|
166
|
+
|
|
167
|
+
List and filter comments across one or more sidecar files.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# List all open comments
|
|
171
|
+
mrsf list --open docs/api.md.review.yaml
|
|
172
|
+
|
|
173
|
+
# Filter by author and severity
|
|
174
|
+
mrsf list --author alice --severity high
|
|
175
|
+
|
|
176
|
+
# Summary view (counts, types, severities)
|
|
177
|
+
mrsf list --summary
|
|
178
|
+
|
|
179
|
+
# Machine-readable JSON output
|
|
180
|
+
mrsf list --json --open
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Option | Description |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `--open` | Show only open (unresolved) comments |
|
|
186
|
+
| `--resolved` | Show only resolved comments |
|
|
187
|
+
| `--orphaned` | Show only orphaned comments |
|
|
188
|
+
| `--author <name>` | Filter by author |
|
|
189
|
+
| `--type <type>` | Filter by comment type |
|
|
190
|
+
| `--severity <level>` | Filter by severity |
|
|
191
|
+
| `--summary` | Show aggregate summary instead of individual comments |
|
|
192
|
+
| `--json` | Output as JSON |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### `mrsf reanchor [files...]`
|
|
197
|
+
|
|
198
|
+
Re-anchor comments after the source document has been edited. The repository's
|
|
199
|
+
**Anchor Mesh** implementation combines verified Git shifts, source-revision
|
|
200
|
+
projection, Markdown structure, bounded text matching, confidence calibration,
|
|
201
|
+
and nearby comments as landmarks. It prefers `ambiguous` or `orphaned` results
|
|
202
|
+
over an unsupported relocation.
|
|
203
|
+
|
|
204
|
+
See the
|
|
205
|
+
[non-normative implementation guide](https://sidemark.org/guide/reanchoring)
|
|
206
|
+
for the complete pipeline, execution modes, tuning values, and evaluation
|
|
207
|
+
methodology.
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Dry run — see what would change without writing
|
|
211
|
+
mrsf reanchor --dry-run docs/api.md.review.yaml
|
|
212
|
+
|
|
213
|
+
# Re-anchor with a higher fuzzy threshold (stricter matching)
|
|
214
|
+
mrsf reanchor --threshold 0.8
|
|
215
|
+
|
|
216
|
+
# Only process sidecars for staged files (pre-commit hook)
|
|
217
|
+
mrsf reanchor --staged
|
|
218
|
+
|
|
219
|
+
# Disable git (pure text-based matching only)
|
|
220
|
+
mrsf reanchor --no-git
|
|
221
|
+
|
|
222
|
+
# Override the from-commit for all comments
|
|
223
|
+
mrsf reanchor --from abc1234
|
|
224
|
+
|
|
225
|
+
# Also update selected_text to match the current document text (opt-in)
|
|
226
|
+
mrsf reanchor --update-text
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
| Option | Description | Default |
|
|
230
|
+
|---|---|---|
|
|
231
|
+
| `-n, --dry-run` | Report without modifying files | `false` |
|
|
232
|
+
| `-t, --threshold <n>` | Fuzzy match threshold (0.0–1.0) | `0.6` |
|
|
233
|
+
| `--staged` | Only process sidecars for git-staged documents | `false` |
|
|
234
|
+
| `--no-git` | Disable git integration entirely | git enabled |
|
|
235
|
+
| `--from <commit>` | Override from-commit for diff calculation | per-comment `commit` field |
|
|
236
|
+
| `--update-text` | Also replace `selected_text` with current document text | `false` |
|
|
237
|
+
|
|
238
|
+
> **Text preservation (§6.2):** By default, re-anchoring preserves the
|
|
239
|
+
> original `selected_text` and records the current document text in
|
|
240
|
+
> `anchored_text`. Use `--update-text` to opt in to overwriting
|
|
241
|
+
> `selected_text` directly.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### `mrsf status [files...]`
|
|
246
|
+
|
|
247
|
+
Assess anchor health for each comment.
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
mrsf status docs/api.md.review.yaml
|
|
251
|
+
mrsf status --json
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Health states:
|
|
255
|
+
|
|
256
|
+
| State | Meaning |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `fresh` | `selected_text` matches at the recorded position |
|
|
259
|
+
| `stale` | `selected_text` matches but at a different position, or commit differs |
|
|
260
|
+
| `orphaned` | `selected_text` not found in the document |
|
|
261
|
+
| `unknown` | No `selected_text` to verify |
|
|
262
|
+
|
|
263
|
+
| Option | Description |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `--json` | Output as JSON |
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### `mrsf init <document>`
|
|
270
|
+
|
|
271
|
+
Create an empty sidecar file for a Markdown document.
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
mrsf init docs/new-feature.md
|
|
275
|
+
mrsf init --force docs/existing.md # overwrite
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
| Option | Description |
|
|
279
|
+
|---|---|
|
|
280
|
+
| `-f, --force` | Overwrite an existing sidecar |
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### `mrsf rename <old-document> <new-document>`
|
|
285
|
+
|
|
286
|
+
Update a sidecar after its source document has been renamed or moved.
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
mrsf rename docs/old-name.md docs/new-name.md
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Updates the `document` field inside the sidecar, writes it to the new path, and removes the old sidecar file.
|
|
293
|
+
|
|
294
|
+
### `mrsf watch [files...]`
|
|
295
|
+
|
|
296
|
+
Watch files for changes and continuously validate (and optionally reanchor).
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# Validate all sidecars on every change
|
|
300
|
+
mrsf watch
|
|
301
|
+
|
|
302
|
+
# Watch specific files
|
|
303
|
+
mrsf watch docs/api.md docs/guide.md
|
|
304
|
+
|
|
305
|
+
# Auto-reanchor when Markdown files change
|
|
306
|
+
mrsf watch --reanchor
|
|
307
|
+
|
|
308
|
+
# Preview reanchor changes without writing
|
|
309
|
+
mrsf watch --reanchor --dry-run
|
|
310
|
+
|
|
311
|
+
# Custom threshold and strict validation
|
|
312
|
+
mrsf watch --reanchor --threshold 0.8 --strict
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Trigger rules** (avoids feedback loops):
|
|
316
|
+
|
|
317
|
+
| File type | Action |
|
|
318
|
+
|---|---|
|
|
319
|
+
| `.md` (Markdown) | Reanchor (if `--reanchor` is set), then validate sidecar |
|
|
320
|
+
| `.review.yaml` / `.review.json` | Validate only |
|
|
321
|
+
|
|
322
|
+
| Option | Description |
|
|
323
|
+
|---|---|
|
|
324
|
+
| `--reanchor` | Auto-reanchor when Markdown files change |
|
|
325
|
+
| `-n, --dry-run` | Preview reanchor changes without writing |
|
|
326
|
+
| `-t, --threshold <n>` | Fuzzy match threshold 0.0–1.0 (default `0.6`) |
|
|
327
|
+
| `-s, --strict` | Treat validation warnings as errors |
|
|
328
|
+
| `--no-git` | Disable git integration |
|
|
329
|
+
| `--from <commit>` | Override from-commit for reanchor |
|
|
330
|
+
| `--update-text` | Update `selected_text` on reanchor |
|
|
331
|
+
| `-f, --force` | Force reanchor — update commit, clear audit fields |
|
|
332
|
+
| `--debounce <ms>` | Debounce interval in ms (default `300`) |
|
|
333
|
+
|
|
334
|
+
Press `Ctrl+C` to stop — a summary of events, reanchors, and errors is printed.
|
|
335
|
+
|
|
336
|
+
## Global Options
|
|
337
|
+
|
|
338
|
+
These apply to all commands:
|
|
339
|
+
|
|
340
|
+
| Option | Description |
|
|
341
|
+
|---|---|
|
|
342
|
+
| `--cwd <dir>` | Override the working directory |
|
|
343
|
+
| `--config <path>` | Path to `.mrsf.yaml` configuration |
|
|
344
|
+
| `--no-color` | Disable coloured output |
|
|
345
|
+
| `-q, --quiet` | Suppress informational output |
|
|
346
|
+
| `-V, --version` | Print version |
|
|
347
|
+
| `-h, --help` | Show help |
|
|
348
|
+
|
|
349
|
+
## CI/CD Integration
|
|
350
|
+
|
|
351
|
+
### GitHub Actions
|
|
352
|
+
|
|
353
|
+
```yaml
|
|
354
|
+
name: MRSF Review Lint
|
|
355
|
+
on: [pull_request]
|
|
356
|
+
jobs:
|
|
357
|
+
mrsf:
|
|
358
|
+
runs-on: ubuntu-latest
|
|
359
|
+
steps:
|
|
360
|
+
- uses: actions/checkout@v4
|
|
361
|
+
- uses: actions/setup-node@v4
|
|
362
|
+
with:
|
|
363
|
+
node-version: 20
|
|
364
|
+
- run: npx @mrsf/cli validate --strict
|
|
365
|
+
- run: npx @mrsf/cli reanchor --staged --dry-run
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Git Pre-commit Hook
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
#!/usr/bin/env bash
|
|
372
|
+
# .git/hooks/pre-commit
|
|
373
|
+
npx @mrsf/cli reanchor --staged
|
|
374
|
+
npx @mrsf/cli validate --strict
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Git Post-merge Hook
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
#!/usr/bin/env bash
|
|
381
|
+
# .git/hooks/post-merge
|
|
382
|
+
npx @mrsf/cli reanchor
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Library Usage
|
|
386
|
+
|
|
387
|
+
The CLI is built library-first. All functionality is available as importable functions:
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import {
|
|
391
|
+
parseSidecar,
|
|
392
|
+
parseSidecarLenient,
|
|
393
|
+
writeSidecar,
|
|
394
|
+
validate,
|
|
395
|
+
reanchorDocument,
|
|
396
|
+
addComment,
|
|
397
|
+
resolveComment,
|
|
398
|
+
removeComment,
|
|
399
|
+
filterComments,
|
|
400
|
+
summarize,
|
|
401
|
+
discoverSidecar,
|
|
402
|
+
discoverAllSidecars,
|
|
403
|
+
} from "@mrsf/cli";
|
|
404
|
+
|
|
405
|
+
// Validate a sidecar programmatically
|
|
406
|
+
const doc = await parseSidecar("docs/api.md.review.yaml");
|
|
407
|
+
const result = await validate(doc);
|
|
408
|
+
console.log(result.valid, result.errors, result.warnings);
|
|
409
|
+
|
|
410
|
+
// Add a comment
|
|
411
|
+
const updated = addComment(doc, lines, {
|
|
412
|
+
author: "ci-bot",
|
|
413
|
+
text: "Auto-generated review comment",
|
|
414
|
+
line: 10,
|
|
415
|
+
});
|
|
416
|
+
await writeSidecar("docs/api.md.review.yaml", updated);
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Browser-safe reanchoring
|
|
420
|
+
|
|
421
|
+
The default `@mrsf/cli` entrypoint is Node-oriented and includes file system and git-backed helpers such as `parseSidecar`, `readDocumentLines`, and `reanchorFile`. For browser bundles and editor integrations, use the `@mrsf/cli/browser` subpath instead.
|
|
422
|
+
|
|
423
|
+
`@mrsf/cli/browser` exports the pure text-based matching and reanchoring primitives only:
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
import {
|
|
427
|
+
applyReanchorResults,
|
|
428
|
+
reanchorDocumentText,
|
|
429
|
+
} from "@mrsf/cli/browser";
|
|
430
|
+
|
|
431
|
+
const results = reanchorDocumentText(sidecar, markdownText);
|
|
432
|
+
const changed = applyReanchorResults(sidecar, results);
|
|
433
|
+
|
|
434
|
+
console.log(changed, results.map((result) => result.status));
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Use this entrypoint when you already have the document text and sidecar object in memory. It intentionally excludes Node-only helpers such as sidecar discovery, file parsing, file writing, and git-aware diff reanchoring.
|
|
438
|
+
|
|
439
|
+
## Configuration
|
|
440
|
+
|
|
441
|
+
Place a `.mrsf.yaml` at your repository root to configure sidecar discovery:
|
|
442
|
+
|
|
443
|
+
```yaml
|
|
444
|
+
# Store all sidecars in a central directory instead of co-located
|
|
445
|
+
sidecar_root: .reviews
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
With this config, the sidecar for `docs/architecture.md` is resolved as `.reviews/docs/architecture.md.review.yaml`.
|
|
449
|
+
|
|
450
|
+
See [§3.2 Alternate Sidecar Location](../MRSF-v1.0.md) in the spec for details.
|
|
451
|
+
|
|
452
|
+
## Extension Fields (`x_*`)
|
|
453
|
+
|
|
454
|
+
MRSF reserves the `x_` prefix for tool-specific, non-standard extension properties (see [§10 Extension Fields](../MRSF-v1.0.md)). These fields may appear on the top-level document object or on individual comments. The CLI preserves them during round-trip writes and exposes them through the catch-all index signature on both `MrsfDocument` and `Comment`.
|
|
455
|
+
|
|
456
|
+
### Built-in `x_` fields
|
|
457
|
+
|
|
458
|
+
The CLI and Sidemark VS Code extension use the following extension fields:
|
|
459
|
+
|
|
460
|
+
| Field | Scope | Type | Set by | Description |
|
|
461
|
+
|---|---|---|---|---|
|
|
462
|
+
| `x_reanchor_status` | comment | `"anchored"` \| `"shifted"` \| `"fuzzy"` \| `"ambiguous"` \| `"orphaned"` | `mrsf reanchor` | Result of the most recent reanchor pass. `ambiguous` means evidence conflicts or multiple candidates remain; `orphaned` means no defensible anchor was found. |
|
|
463
|
+
| `x_reanchor_score` | comment | `number` (0–1) | `mrsf reanchor` | Confidence score from the reanchor algorithm. `1.0` = exact match, lower values indicate fuzzy or shifted matches. |
|
|
464
|
+
|
|
465
|
+
### Adding your own fields
|
|
466
|
+
|
|
467
|
+
Any property whose key starts with `x_` is valid on both the document root and on each comment. The CLI and Sidemark will silently preserve these fields through all operations (validate, add, resolve, reanchor, etc.).
|
|
468
|
+
|
|
469
|
+
```yaml
|
|
470
|
+
comments:
|
|
471
|
+
- id: abc123
|
|
472
|
+
author: ci-bot
|
|
473
|
+
timestamp: "2025-01-15T10:00:00Z"
|
|
474
|
+
text: Possible security concern
|
|
475
|
+
resolved: false
|
|
476
|
+
line: 42
|
|
477
|
+
# Custom extension fields
|
|
478
|
+
x_ai_confidence: 0.92
|
|
479
|
+
x_tool_name: security-scanner
|
|
480
|
+
x_category: injection
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Rules** (from the spec):
|
|
484
|
+
|
|
485
|
+
- Keys MUST start with `x_` (underscore, not hyphen).
|
|
486
|
+
- Implementations MUST NOT assign semantic meaning to `x_` fields defined by other tools.
|
|
487
|
+
- Future MRSF spec versions will never introduce normative fields with the `x_` prefix.
|
|
488
|
+
- Unknown `x_` fields are preserved by the CLI's round-trip writer and never stripped or modified.
|
|
489
|
+
|
|
490
|
+
### Programmatic access
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
import { parseSidecar } from "@mrsf/cli";
|
|
494
|
+
|
|
495
|
+
const doc = await parseSidecar("file.md.review.yaml");
|
|
496
|
+
for (const comment of doc.comments) {
|
|
497
|
+
// Access built-in x_ fields
|
|
498
|
+
if (comment.x_reanchor_status === "orphaned") {
|
|
499
|
+
console.log(`Comment ${comment.id} is orphaned`);
|
|
500
|
+
}
|
|
501
|
+
// Access custom x_ fields
|
|
502
|
+
const confidence = comment.x_ai_confidence as number | undefined;
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## Requirements
|
|
507
|
+
|
|
508
|
+
- Node.js 18 or later
|
|
509
|
+
- Git (optional — enables diff-based re-anchoring, commit stamping, rename detection)
|
|
510
|
+
|
|
511
|
+
## License
|
|
512
|
+
|
|
513
|
+
MIT — see [LICENSE](../LICENSE).
|