@better-vibe/branch-narrator 1.0.0 → 1.2.1
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 +464 -539
- package/dist/analyzers/index.d.ts +4 -0
- package/dist/analyzers/index.d.ts.map +1 -1
- package/dist/analyzers/lockfiles.d.ts.map +1 -1
- package/dist/analyzers/python-config.d.ts +26 -0
- package/dist/analyzers/python-config.d.ts.map +1 -0
- package/dist/analyzers/python-dependencies.d.ts +21 -0
- package/dist/analyzers/python-dependencies.d.ts.map +1 -0
- package/dist/analyzers/python-migrations.d.ts +26 -0
- package/dist/analyzers/python-migrations.d.ts.map +1 -0
- package/dist/analyzers/python-routes.d.ts +15 -0
- package/dist/analyzers/python-routes.d.ts.map +1 -0
- package/dist/cli.js +355 -13718
- package/dist/core/ids.d.ts.map +1 -1
- package/dist/core/types.d.ts +32 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.js +286 -6631
- package/dist/profiles/index.d.ts +14 -1
- package/dist/profiles/index.d.ts.map +1 -1
- package/dist/profiles/python.d.ts +15 -0
- package/dist/profiles/python.d.ts.map +1 -0
- package/dist/render/markdown.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/cli.js.map +0 -101
- package/dist/index.js.map +0 -60
package/README.md
CHANGED
|
@@ -1,95 +1,250 @@
|
|
|
1
1
|
# branch-narrator
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@better-vibe/branch-narrator)
|
|
4
|
+
[](https://github.com/@better-vibe/branch-narrator/actions/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
A local-first, deterministic CLI that analyzes `git diff` and provides
|
|
8
|
+
structured context for AI coding agents and human code review.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
- **Agent-grade reliability**: JSON outputs are deterministic, parseable, and pipe-safe (e.g., `branch-narrator facts | jq .`). Global `--quiet` and `--debug` flags control diagnostics.
|
|
9
|
-
- **Risk Analysis**: Framework-agnostic security and quality risk scoring (0-100) with evidence-backed flags.
|
|
10
|
-
- **SvelteKit-aware**: Detects routes, layouts, endpoints, and HTTP methods.
|
|
11
|
-
- **React Router support**: Detects route changes in React apps (JSX `<Route>` and data routers like `createBrowserRouter`).
|
|
12
|
-
- **Supabase integration**: Scans migrations for destructive SQL patterns.
|
|
13
|
-
- **Environment variable detection**: Finds `process.env`, SvelteKit `$env` imports, Vite `import.meta.env`, React App `REACT_APP_*`, and Next.js `NEXT_PUBLIC_*`.
|
|
14
|
-
- **Cloudflare detection**: Detects wrangler config and CI changes.
|
|
15
|
-
- **Dependency analysis**: Tracks package.json changes with semver impact.
|
|
16
|
-
- **CI/CD security**: Detects workflow permission changes, pull_request_target, remote script execution.
|
|
17
|
-
- **Infrastructure changes**: Tracks Dockerfile, Terraform, and Kubernetes manifest changes.
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
10
|
+
## Quick Start
|
|
20
11
|
|
|
21
12
|
```bash
|
|
22
|
-
|
|
13
|
+
# Install as dev dependency (recommended)
|
|
14
|
+
bun add -D @better-vibe/branch-narrator
|
|
23
15
|
# or
|
|
24
|
-
npm install -D branch-narrator
|
|
16
|
+
npm install -D @better-vibe/branch-narrator
|
|
17
|
+
|
|
18
|
+
# Or install globally
|
|
19
|
+
npm install -g @better-vibe/branch-narrator
|
|
20
|
+
|
|
21
|
+
# Or run without installing
|
|
22
|
+
npx @better-vibe/branch-narrator facts --pretty
|
|
25
23
|
```
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
### Common Commands
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
- **Diff Understanding**: Use `dump-diff` to get a clean, token-optimized git diff that handles exclusions smartly (ignoring lockfiles, minified files, etc.).
|
|
33
|
-
- **Self-Verification**: Use `zoom` to verify specific findings or check if a requested change (e.g., "add a route") was actually implemented correctly.
|
|
27
|
+
```bash
|
|
28
|
+
# Generate a PR description for current changes
|
|
29
|
+
branch-narrator pr-body
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- **Fast Code Review**: Run `branch-narrator pretty` to see a high-level summary of your uncommitted changes in the terminal.
|
|
38
|
-
- **PR Descriptions**: Generate a consistent, comprehensive PR description with `branch-narrator pr-body` and pipe it directly to `gh pr create` or your clipboard.
|
|
31
|
+
# Structured JSON facts for automation
|
|
32
|
+
branch-narrator facts --pretty
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- **Risk Gating**: Use `branch-narrator risk-report --fail-on-score 60` in your CI pipeline to automatically block merges that introduce high-risk changes (like destructive migrations or dangerous permissions) until they are reviewed.
|
|
34
|
+
# Risk report for review
|
|
35
|
+
branch-narrator risk-report --format md
|
|
43
36
|
|
|
44
|
-
|
|
37
|
+
# Prompt-ready diff with smart filtering
|
|
38
|
+
branch-narrator dump-diff --out .ai/diff.txt
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
# Save workspace snapshot for agent iteration
|
|
41
|
+
branch-narrator snap save "before-refactor"
|
|
47
42
|
|
|
48
|
-
|
|
43
|
+
# SARIF output for GitHub Code Scanning
|
|
44
|
+
branch-narrator facts --format sarif --out results.sarif
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
# Compare changes since last run (delta mode)
|
|
47
|
+
branch-narrator facts --since .ai/baseline.json
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Table of Contents
|
|
51
|
+
|
|
52
|
+
- [Quick Start](#quick-start)
|
|
53
|
+
- [Why branch-narrator](#why-branch-narrator)
|
|
54
|
+
- [Key Capabilities](#key-capabilities)
|
|
55
|
+
- [Documentation](#documentation)
|
|
56
|
+
- [CLI Reference](#cli-reference)
|
|
57
|
+
- [CI/CD Integration](#cicd-integration)
|
|
58
|
+
- [Programmatic API](#programmatic-api)
|
|
59
|
+
- [Example Output](#example-output)
|
|
60
|
+
- [Development](#development)
|
|
61
|
+
- [Contributing](#contributing)
|
|
62
|
+
- [Requirements](#requirements)
|
|
63
|
+
- [License](#license)
|
|
64
|
+
|
|
65
|
+
## Why branch-narrator
|
|
66
|
+
|
|
67
|
+
- Deterministic and offline: no LLMs, no network calls.
|
|
68
|
+
- Evidence-based output: summaries and risk flags are tied to diff evidence.
|
|
69
|
+
- Profile-aware analysis across frameworks and libraries.
|
|
70
|
+
- Output for humans (Markdown) and automation (JSON/SARIF).
|
|
71
|
+
|
|
72
|
+
## Key Capabilities
|
|
73
|
+
|
|
74
|
+
### Output Formats
|
|
75
|
+
- **Markdown PR descriptions** (`pr-body`) with consistent sections.
|
|
76
|
+
- **JSON facts** (`facts`) for pipelines and automation.
|
|
77
|
+
- **Prompt-ready diffs** (`dump-diff`) with smart filtering for AI context windows.
|
|
78
|
+
- **SARIF output** (`--format sarif`) for GitHub Code Scanning integration.
|
|
79
|
+
- **Risk scoring** (`risk-report`) with evidence-backed flags and categories.
|
|
80
|
+
- **Workspace snapshots** (`snap`) for saving and comparing workspace state.
|
|
81
|
+
|
|
82
|
+
### Analysis Features
|
|
83
|
+
- Route and API change detection for SvelteKit, Next.js App Router, React Router,
|
|
84
|
+
Vue/Nuxt, and Astro.
|
|
85
|
+
- Dependency and package surface analysis (semver impact, exports, lockfile
|
|
86
|
+
mismatches).
|
|
87
|
+
- Environment variables, security-sensitive files, CI workflows, and
|
|
88
|
+
infrastructure changes.
|
|
89
|
+
- Migration safety checks (Supabase migrations and SQL risk patterns).
|
|
90
|
+
|
|
91
|
+
### Agent Workflows
|
|
92
|
+
- **Delta mode** (`--since`) for comparing runs and tracking changes over time.
|
|
93
|
+
- **Stable IDs** for deterministic finding/flag references across runs.
|
|
94
|
+
- **Snapshot workflows** (`snap`) for saving and restoring workspace state.
|
|
95
|
+
- **Drill-down** (`zoom`) for detailed context on specific findings or flags.
|
|
96
|
+
- **AI assistant integration** (`integrate`) to generate provider rules for
|
|
97
|
+
Cursor, Claude, Jules, and OpenCode.
|
|
98
|
+
|
|
99
|
+
## Documentation
|
|
100
|
+
|
|
101
|
+
Start with the docs index: [`docs/README.md`](docs/README.md). The `docs/`
|
|
102
|
+
folder is the source of truth for detailed technical documentation.
|
|
103
|
+
|
|
104
|
+
Key sections:
|
|
105
|
+
|
|
106
|
+
- Product overview and roadmap: [`docs/01-product/`](docs/01-product/)
|
|
107
|
+
- CLI commands and options: [`docs/05-cli/`](docs/05-cli/)
|
|
108
|
+
- Analyzer catalog: [`docs/03-analyzers/`](docs/03-analyzers/)
|
|
109
|
+
- Profiles and detection: [`docs/07-profiles/`](docs/07-profiles/)
|
|
110
|
+
- Rendering formats and risk scoring: [`docs/08-rendering/`](docs/08-rendering/)
|
|
111
|
+
- Stable IDs and traceability: [`docs/09-stable-ids/`](docs/09-stable-ids/)
|
|
112
|
+
- Snapshots: [`docs/10-snapshots/`](docs/10-snapshots/)
|
|
113
|
+
- Delta mode: [`docs/11-delta-mode/`](docs/11-delta-mode/)
|
|
114
|
+
- Development guides: [`docs/06-development/`](docs/06-development/)
|
|
115
|
+
|
|
116
|
+
See [`CHANGELOG.md`](CHANGELOG.md) for version history and release notes.
|
|
117
|
+
|
|
118
|
+
## CLI Reference
|
|
119
|
+
|
|
120
|
+
### Global behavior
|
|
121
|
+
|
|
122
|
+
- JSON outputs (`facts`, `risk-report --format json`, `dump-diff --format json`)
|
|
123
|
+
write diagnostics to stderr so stdout is parse-safe.
|
|
124
|
+
- `--quiet` suppresses non-fatal diagnostics; `--debug` enables timing and
|
|
125
|
+
detector logs.
|
|
126
|
+
- `DEBUG=1` prints stack traces for debugging.
|
|
127
|
+
|
|
128
|
+
### Global flags
|
|
129
|
+
|
|
130
|
+
| Flag | Description |
|
|
131
|
+
|------|-------------|
|
|
132
|
+
| `--quiet` | Suppress non-fatal diagnostics (warnings, info) |
|
|
133
|
+
| `--debug` | Print debug diagnostics to stderr |
|
|
134
|
+
|
|
135
|
+
### Diff modes
|
|
136
|
+
|
|
137
|
+
| Mode | Description | Git Command |
|
|
138
|
+
|------|-------------|-------------|
|
|
139
|
+
| `unstaged` | Working tree vs index + untracked files (default) | `git diff` + `git ls-files --others` |
|
|
140
|
+
| `branch` | Compare base ref to head ref | `git diff base..head` |
|
|
141
|
+
| `staged` | Index vs HEAD (staged changes) | `git diff --staged` |
|
|
142
|
+
| `all` | All changes vs HEAD (staged + unstaged + untracked) | `git diff HEAD` + `git ls-files --others` |
|
|
143
|
+
|
|
144
|
+
### Profiles
|
|
145
|
+
|
|
146
|
+
Use `--profile <name>` to override auto-detection.
|
|
147
|
+
|
|
148
|
+
| Profile | Description | Auto-detect signals |
|
|
149
|
+
|---------|-------------|--------------------|
|
|
150
|
+
| `auto` | Default profile selection | Framework detection fallback |
|
|
151
|
+
| `sveltekit` | SvelteKit fullstack apps | `src/routes/` or `@sveltejs/kit` |
|
|
152
|
+
| `next` | Next.js App Router apps | `next` dependency + `app/` or `src/app/` |
|
|
153
|
+
| `react` | React apps using React Router | `react` + `react-router` |
|
|
154
|
+
| `vue` | Vue/Nuxt apps | `nuxt` or `vue` + `pages/` |
|
|
155
|
+
| `astro` | Astro projects | `astro` dependency or `astro.config.*` |
|
|
156
|
+
| `stencil` | StencilJS projects | `@stencil/core` or `stencil.config.*` |
|
|
157
|
+
| `library` | npm packages/libraries | `exports`, `publishConfig`, `bin`, `private: false` |
|
|
53
158
|
|
|
54
|
-
|
|
55
|
-
branch-narrator --debug risk-report
|
|
159
|
+
### Commands
|
|
56
160
|
|
|
57
|
-
|
|
58
|
-
|
|
161
|
+
#### pretty
|
|
162
|
+
|
|
163
|
+
Display a colorized summary of changes in the terminal.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
branch-narrator pretty [options]
|
|
59
167
|
```
|
|
60
168
|
|
|
61
|
-
|
|
169
|
+
| Option | Default | Description |
|
|
170
|
+
|--------|---------|-------------|
|
|
171
|
+
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
172
|
+
| `--base <ref>` | auto-detected | Base git reference (branch mode only) |
|
|
173
|
+
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
174
|
+
| `--profile <name>` | `auto` | Profile: `auto`, `sveltekit`, `next`, `react`, `vue`, `astro`, `stencil`, `library` |
|
|
62
175
|
|
|
63
|
-
|
|
176
|
+
Examples:
|
|
64
177
|
|
|
65
178
|
```bash
|
|
66
|
-
#
|
|
179
|
+
# Review unstaged changes (default)
|
|
67
180
|
branch-narrator pretty
|
|
68
181
|
|
|
69
|
-
# Compare
|
|
182
|
+
# Compare branches
|
|
70
183
|
branch-narrator pretty --mode branch --base develop --head feature/auth
|
|
71
184
|
|
|
72
|
-
# Review all uncommitted changes
|
|
185
|
+
# Review all uncommitted changes
|
|
73
186
|
branch-narrator pretty --mode all
|
|
74
187
|
```
|
|
75
188
|
|
|
76
|
-
|
|
189
|
+
#### pr-body
|
|
190
|
+
|
|
191
|
+
Generate a raw Markdown PR description.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
branch-narrator pr-body [options]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
| Option | Default | Description |
|
|
198
|
+
|--------|---------|-------------|
|
|
199
|
+
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
200
|
+
| `--base <ref>` | auto-detected | Base git reference (branch mode only) |
|
|
201
|
+
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
202
|
+
| `-u, --uncommitted` | `false` | Deprecated: use `--mode unstaged` |
|
|
203
|
+
| `--profile <name>` | `auto` | Profile: `auto`, `sveltekit`, `next`, `react`, `vue`, `astro`, `stencil`, `library` |
|
|
204
|
+
| `--interactive` | `false` | Prompt for context and test notes |
|
|
205
|
+
|
|
206
|
+
Examples:
|
|
77
207
|
|
|
78
208
|
```bash
|
|
79
209
|
# Analyze unstaged changes (default)
|
|
80
210
|
branch-narrator pr-body
|
|
81
211
|
|
|
82
212
|
# Compare branches for PR
|
|
83
|
-
branch-narrator pr-body --mode branch --base develop --head feature/
|
|
213
|
+
branch-narrator pr-body --mode branch --base develop --head feature/auth
|
|
84
214
|
|
|
85
215
|
# Interactive mode (prompts for context)
|
|
86
216
|
branch-narrator pr-body --interactive
|
|
217
|
+
```
|
|
87
218
|
|
|
88
|
-
|
|
89
|
-
|
|
219
|
+
#### facts
|
|
220
|
+
|
|
221
|
+
Output JSON findings for programmatic use.
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
branch-narrator facts [options]
|
|
90
225
|
```
|
|
91
226
|
|
|
92
|
-
|
|
227
|
+
| Option | Default | Description |
|
|
228
|
+
|--------|---------|-------------|
|
|
229
|
+
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
230
|
+
| `--base <ref>` | auto-detected | Base git reference (branch mode only) |
|
|
231
|
+
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
232
|
+
| `--profile <name>` | `auto` | Profile: `auto`, `sveltekit`, `next`, `react`, `vue`, `astro`, `stencil`, `library` |
|
|
233
|
+
| `--format <type>` | `json` | Output format: `json`, `sarif` |
|
|
234
|
+
| `--pretty` | `false` | Pretty-print JSON with 2-space indentation |
|
|
235
|
+
| `--redact` | `false` | Redact obvious secrets in evidence |
|
|
236
|
+
| `--exclude <glob>` | (none) | Exclude files matching glob (repeatable) |
|
|
237
|
+
| `--include <glob>` | (none) | Include only files matching glob (repeatable) |
|
|
238
|
+
| `--max-file-bytes <n>` | `1048576` | Max file size to analyze |
|
|
239
|
+
| `--max-diff-bytes <n>` | `5242880` | Max diff size to analyze |
|
|
240
|
+
| `--max-findings <n>` | (none) | Max findings to include |
|
|
241
|
+
| `--out <path>` | (stdout) | Write output to file |
|
|
242
|
+
| `--no-timestamp` | `false` | Omit `generatedAt` for deterministic output |
|
|
243
|
+
| `--since <path>` | (none) | Compare current output to a previous JSON file |
|
|
244
|
+
| `--since-strict` | `false` | Exit with code 1 on scope mismatch |
|
|
245
|
+
| `--test-parity` | `false` | Enable test parity checks |
|
|
246
|
+
|
|
247
|
+
Examples:
|
|
93
248
|
|
|
94
249
|
```bash
|
|
95
250
|
# Analyze unstaged changes (default)
|
|
@@ -101,620 +256,390 @@ branch-narrator facts --mode branch --base develop --head feature/auth
|
|
|
101
256
|
# Pretty-printed JSON
|
|
102
257
|
branch-narrator facts --pretty
|
|
103
258
|
|
|
104
|
-
#
|
|
105
|
-
branch-narrator facts --
|
|
106
|
-
|
|
107
|
-
# Limit output
|
|
108
|
-
branch-narrator facts --max-findings 50
|
|
109
|
-
|
|
110
|
-
# Filter files
|
|
111
|
-
branch-narrator facts --exclude "**/test/**" --include "src/**"
|
|
112
|
-
|
|
113
|
-
# Parse with jq
|
|
114
|
-
branch-narrator facts | jq '.risk.level'
|
|
115
|
-
branch-narrator facts | jq '.categories[] | select(.id == "database")'
|
|
116
|
-
branch-narrator facts | jq '.actions[] | select(.blocking == true)'
|
|
259
|
+
# SARIF output for code scanning
|
|
260
|
+
branch-narrator facts --format sarif --out branch-narrator.sarif
|
|
117
261
|
|
|
118
|
-
# Delta mode
|
|
262
|
+
# Delta mode
|
|
119
263
|
branch-narrator facts --out .ai/baseline.json
|
|
120
|
-
# ... make changes ...
|
|
121
264
|
branch-narrator facts --since .ai/baseline.json --pretty
|
|
122
265
|
```
|
|
123
266
|
|
|
124
|
-
|
|
267
|
+
SARIF output details (rule mappings, schema, limitations) are documented in
|
|
268
|
+
[`docs/08-rendering/sarif.md`](docs/08-rendering/sarif.md).
|
|
269
|
+
Delta mode details are documented in
|
|
270
|
+
[`docs/11-delta-mode/11-delta-mode.md`](docs/11-delta-mode/11-delta-mode.md).
|
|
125
271
|
|
|
126
|
-
|
|
272
|
+
#### dump-diff
|
|
127
273
|
|
|
128
|
-
|
|
129
|
-
# Generate SARIF output for GitHub Code Scanning
|
|
130
|
-
branch-narrator facts --mode branch --base main --head HEAD --format sarif
|
|
131
|
-
|
|
132
|
-
# Save to file for upload
|
|
133
|
-
branch-narrator facts --format sarif --out branch-narrator.sarif
|
|
274
|
+
Output a prompt-ready git diff with smart exclusions.
|
|
134
275
|
|
|
135
|
-
|
|
136
|
-
branch-narrator
|
|
276
|
+
```bash
|
|
277
|
+
branch-narrator dump-diff [options]
|
|
137
278
|
```
|
|
138
279
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
280
|
+
| Option | Default | Description |
|
|
281
|
+
|--------|---------|-------------|
|
|
282
|
+
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
283
|
+
| `--base <ref>` | auto-detected | Base git reference (branch mode only) |
|
|
284
|
+
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
285
|
+
| `--no-untracked` | (off) | Exclude untracked files (non-branch modes) |
|
|
286
|
+
| `--out <path>` | stdout | Write output to file |
|
|
287
|
+
| `--format <type>` | `text` | Output format: `text`, `md`, `json` |
|
|
288
|
+
| `--unified <n>` | `0` | Lines of unified context |
|
|
289
|
+
| `--include <glob>` | (none) | Include only matching files (repeatable) |
|
|
290
|
+
| `--exclude <glob>` | (none) | Additional exclusion globs |
|
|
291
|
+
| `--max-chars <n>` | (none) | Chunk output if it exceeds this size |
|
|
292
|
+
| `--chunk-dir <path>` | `.ai/diff-chunks` | Directory for chunk files |
|
|
293
|
+
| `--name <prefix>` | `diff` | Chunk file name prefix |
|
|
294
|
+
| `--dry-run` | `false` | Preview what would be included/excluded |
|
|
295
|
+
| `--name-only` | `false` | Output only file list (no diff content) |
|
|
296
|
+
| `--stat` | `false` | Output file statistics |
|
|
297
|
+
| `--patch-for <path>` | (none) | Output diff for a specific file only |
|
|
298
|
+
| `--pretty` | `false` | Pretty-print JSON with 2-space indentation |
|
|
299
|
+
| `--no-timestamp` | `false` | Omit `generatedAt` for deterministic output |
|
|
142
300
|
|
|
143
|
-
|
|
301
|
+
Notes:
|
|
144
302
|
|
|
145
|
-
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
- **BNR004**: New environment variable reference detected - `warning`
|
|
149
|
-
- **BNR005**: Cloudflare configuration changed - `note`
|
|
150
|
-
- **BNR006**: API endpoint changed (added/modified/deleted) - `note`
|
|
303
|
+
- `--name-only`, `--stat`, and `--patch-for` are mutually exclusive.
|
|
304
|
+
- Default exclusions include lockfiles, build artifacts, sourcemaps, and
|
|
305
|
+
minified files (see docs for the full list).
|
|
151
306
|
|
|
152
|
-
|
|
307
|
+
Examples:
|
|
153
308
|
|
|
154
|
-
```
|
|
155
|
-
|
|
309
|
+
```bash
|
|
310
|
+
# Output unstaged changes to stdout (default)
|
|
311
|
+
branch-narrator dump-diff
|
|
156
312
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
branches: [main]
|
|
313
|
+
# Compare branches for PR
|
|
314
|
+
branch-narrator dump-diff --mode branch --base main --head feature/auth --out .ai/diff.txt
|
|
160
315
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
runs-on: ubuntu-latest
|
|
164
|
-
permissions:
|
|
165
|
-
security-events: write
|
|
166
|
-
contents: read
|
|
316
|
+
# Chunk large diffs
|
|
317
|
+
branch-narrator dump-diff --max-chars 25000 --chunk-dir .ai/diff-chunks
|
|
167
318
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
fetch-depth: 0 # Fetch full history for diff analysis
|
|
319
|
+
# JSON output with metadata
|
|
320
|
+
branch-narrator dump-diff --format json --pretty --out .ai/diff.json
|
|
321
|
+
```
|
|
172
322
|
|
|
173
|
-
|
|
174
|
-
run: npm install -g @better-vibe/branch-narrator
|
|
323
|
+
#### risk-report
|
|
175
324
|
|
|
176
|
-
|
|
177
|
-
run: |
|
|
178
|
-
branch-narrator facts \
|
|
179
|
-
--mode branch \
|
|
180
|
-
--base ${{ github.event.pull_request.base.sha }} \
|
|
181
|
-
--head ${{ github.event.pull_request.head.sha }} \
|
|
182
|
-
--format sarif \
|
|
183
|
-
--out branch-narrator.sarif
|
|
325
|
+
Analyze diffs and emit a risk score with evidence-backed flags.
|
|
184
326
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
with:
|
|
188
|
-
sarif_file: branch-narrator.sarif
|
|
189
|
-
category: branch-narrator
|
|
327
|
+
```bash
|
|
328
|
+
branch-narrator risk-report [options]
|
|
190
329
|
```
|
|
191
330
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
331
|
+
| Option | Default | Description |
|
|
332
|
+
|--------|---------|-------------|
|
|
333
|
+
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
334
|
+
| `--base <ref>` | auto-detected | Base git reference (branch mode only) |
|
|
335
|
+
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
336
|
+
| `--format <type>` | `json` | Output format: `json`, `md`, `text` |
|
|
337
|
+
| `--out <path>` | (stdout) | Write output to file |
|
|
338
|
+
| `--fail-on-score <n>` | (none) | Exit with code 2 if risk score >= threshold |
|
|
339
|
+
| `--only <categories>` | (all) | Only include these categories (comma-separated) |
|
|
340
|
+
| `--exclude <categories>` | (none) | Exclude these categories (comma-separated) |
|
|
341
|
+
| `--max-evidence-lines <n>` | `5` | Max evidence lines per flag |
|
|
342
|
+
| `--redact` | `false` | Redact secret values in evidence |
|
|
343
|
+
| `--explain-score` | `false` | Include score breakdown |
|
|
344
|
+
| `--pretty` | `false` | Pretty-print JSON with 2-space indentation |
|
|
345
|
+
| `--no-timestamp` | `false` | Omit `generatedAt` for deterministic output |
|
|
346
|
+
| `--since <path>` | (none) | Compare current output to a previous JSON file |
|
|
347
|
+
| `--since-strict` | `false` | Exit with code 1 on scope mismatch |
|
|
348
|
+
| `--test-parity` | `false` | Enable test parity checks |
|
|
349
|
+
|
|
350
|
+
Risk levels:
|
|
351
|
+
|
|
352
|
+
- `low` (0-20)
|
|
353
|
+
- `moderate` (21-40)
|
|
354
|
+
- `elevated` (41-60)
|
|
355
|
+
- `high` (61-80)
|
|
356
|
+
- `critical` (81-100)
|
|
197
357
|
|
|
198
|
-
|
|
358
|
+
Examples:
|
|
199
359
|
|
|
200
360
|
```bash
|
|
201
361
|
# Analyze unstaged changes (default)
|
|
202
362
|
branch-narrator risk-report
|
|
203
363
|
|
|
204
|
-
# Compare branches for PR
|
|
205
|
-
branch-narrator risk-report --mode branch --base develop --head feature/auth
|
|
206
|
-
|
|
207
364
|
# Markdown format for human review
|
|
208
365
|
branch-narrator risk-report --format md
|
|
209
366
|
|
|
210
|
-
# Text format for terminal
|
|
211
|
-
branch-narrator risk-report --format text
|
|
212
|
-
|
|
213
367
|
# Fail CI if risk score >= threshold
|
|
214
368
|
branch-narrator risk-report --fail-on-score 50
|
|
215
369
|
|
|
216
|
-
#
|
|
217
|
-
branch-narrator risk-report --only security,deps,db
|
|
218
|
-
|
|
219
|
-
# Exclude certain categories
|
|
220
|
-
branch-narrator risk-report --exclude tests,churn
|
|
221
|
-
|
|
222
|
-
# Show score breakdown
|
|
223
|
-
branch-narrator risk-report --explain-score
|
|
224
|
-
|
|
225
|
-
# Redact secrets in evidence
|
|
226
|
-
branch-narrator risk-report --redact
|
|
227
|
-
|
|
228
|
-
# Limit evidence lines per flag
|
|
229
|
-
branch-narrator risk-report --max-evidence-lines 3
|
|
230
|
-
|
|
231
|
-
# Write to file
|
|
232
|
-
branch-narrator risk-report --format md --out .ai/risk-report.md
|
|
233
|
-
|
|
234
|
-
# Parse with jq
|
|
235
|
-
branch-narrator risk-report | jq '.riskScore'
|
|
236
|
-
branch-narrator risk-report | jq '.flags[] | select(.category == "security")'
|
|
237
|
-
branch-narrator risk-report | jq '.categoryScores.db'
|
|
238
|
-
|
|
239
|
-
# Delta mode: track risk improvement
|
|
370
|
+
# Delta mode
|
|
240
371
|
branch-narrator risk-report --out .ai/baseline-risk.json
|
|
241
|
-
# ... make changes ...
|
|
242
372
|
branch-narrator risk-report --since .ai/baseline-risk.json --pretty
|
|
243
|
-
# Shows: risk score change, added/removed/changed flags
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
**Risk Categories:**
|
|
247
|
-
- `security`: Workflow permissions, pull_request_target, remote script execution
|
|
248
|
-
- `ci`: CI/CD pipeline configuration changes
|
|
249
|
-
- `deps`: New dependencies, major version bumps, lockfile inconsistencies
|
|
250
|
-
- `db`: Database migrations, destructive SQL, schema changes
|
|
251
|
-
- `infra`: Dockerfile, Terraform, Kubernetes manifests
|
|
252
|
-
- `api`: OpenAPI, GraphQL, Protocol Buffer schema changes
|
|
253
|
-
- `tests`: Test coverage gaps, test file changes
|
|
254
|
-
- `churn`: Large changesets (>50 files or >1500 lines)
|
|
255
|
-
|
|
256
|
-
**Risk Levels:** (based on 0-100 score)
|
|
257
|
-
- `low` (0-20): Minimal risk, safe to merge
|
|
258
|
-
- `moderate` (21-40): Some risk, review recommended
|
|
259
|
-
- `elevated` (41-60): Moderate risk, careful review needed
|
|
260
|
-
- `high` (61-80): High risk, thorough review required
|
|
261
|
-
- `critical` (81-100): Critical risk, requires security review
|
|
262
|
-
|
|
263
|
-
**Output Schema (v1.0):**
|
|
264
|
-
- `schemaVersion`: Schema version identifier
|
|
265
|
-
- `generatedAt`: ISO timestamp
|
|
266
|
-
- `git`: Git metadata (base, head, range, isDirty)
|
|
267
|
-
- `profile`: Detected project profile with confidence
|
|
268
|
-
- `stats`: File change statistics
|
|
269
|
-
- `filters`: Applied filtering configuration
|
|
270
|
-
- `summary`: High-level summary with highlights
|
|
271
|
-
- `categories`: Findings aggregated by category with risk weights
|
|
272
|
-
- `risk`: Structured risk score with factors and evidence
|
|
273
|
-
- `findings`: Detailed findings array (typed discriminated union)
|
|
274
|
-
- `actions`: Actionable recommendations (blocking/non-blocking)
|
|
275
|
-
- `skippedFiles`: Files excluded from analysis with reasons
|
|
276
|
-
- `warnings`: Any warnings encountered during analysis
|
|
277
|
-
|
|
278
|
-
**Example categories output:**
|
|
279
|
-
```json
|
|
280
|
-
{
|
|
281
|
-
"categories": [
|
|
282
|
-
{
|
|
283
|
-
"id": "database",
|
|
284
|
-
"count": 2,
|
|
285
|
-
"riskWeight": 45,
|
|
286
|
-
"topEvidence": [
|
|
287
|
-
{
|
|
288
|
-
"file": "supabase/migrations/002_users.sql",
|
|
289
|
-
"excerpt": "DROP TABLE IF EXISTS old_users;"
|
|
290
|
-
}
|
|
291
|
-
]
|
|
292
|
-
}
|
|
293
|
-
]
|
|
294
|
-
}
|
|
295
373
|
```
|
|
296
374
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
# Output unstaged changes (default)
|
|
301
|
-
branch-narrator dump-diff
|
|
302
|
-
|
|
303
|
-
# Write to file
|
|
304
|
-
branch-narrator dump-diff --out .ai/diff.txt
|
|
305
|
-
|
|
306
|
-
# Compare branches for PR
|
|
307
|
-
branch-narrator dump-diff --mode branch --base main --head feature/auth --out .ai/diff.txt
|
|
308
|
-
|
|
309
|
-
# Staged changes only (index vs HEAD)
|
|
310
|
-
branch-narrator dump-diff --mode staged --format md --out .ai/staged.md
|
|
311
|
-
|
|
312
|
-
# All changes since HEAD (staged + unstaged + untracked)
|
|
313
|
-
branch-narrator dump-diff --mode all --out .ai/all-changes.txt
|
|
375
|
+
Risk scoring details are documented in
|
|
376
|
+
[`docs/08-rendering/risk-scoring.md`](docs/08-rendering/risk-scoring.md).
|
|
314
377
|
|
|
315
|
-
|
|
316
|
-
branch-narrator dump-diff --mode all --no-untracked --out .ai/diff.txt
|
|
378
|
+
#### zoom
|
|
317
379
|
|
|
318
|
-
|
|
319
|
-
branch-narrator dump-diff --max-chars 25000 --chunk-dir .ai/diff-chunks
|
|
320
|
-
|
|
321
|
-
# JSON format with metadata
|
|
322
|
-
branch-narrator dump-diff --format json --out .ai/diff.json
|
|
380
|
+
Zoom into a specific finding or risk flag for detailed context.
|
|
323
381
|
|
|
324
|
-
|
|
325
|
-
branch-narrator
|
|
382
|
+
```bash
|
|
383
|
+
branch-narrator zoom [options]
|
|
326
384
|
```
|
|
327
385
|
|
|
328
|
-
|
|
386
|
+
| Option | Default | Description |
|
|
387
|
+
|--------|---------|-------------|
|
|
388
|
+
| `--finding <id>` | (none) | Finding ID to zoom into |
|
|
389
|
+
| `--flag <id>` | (none) | Flag ID to zoom into |
|
|
390
|
+
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
391
|
+
| `--base <ref>` | auto-detected | Base git reference (branch mode only) |
|
|
392
|
+
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
393
|
+
| `--profile <name>` | `auto` | Profile: `auto`, `sveltekit`, `next`, `react`, `vue`, `astro`, `stencil`, `library` |
|
|
394
|
+
| `--format <type>` | `json` | Output format: `json`, `md`, `text` |
|
|
395
|
+
| `--unified <n>` | `3` | Lines of unified context |
|
|
396
|
+
| `--no-patch` | `false` | Exclude patch context (evidence only) |
|
|
397
|
+
| `--max-evidence-lines <n>` | `8` | Max evidence excerpt lines |
|
|
398
|
+
| `--redact` | `false` | Redact obvious secret values |
|
|
399
|
+
| `--out <path>` | stdout | Write output to file |
|
|
400
|
+
| `--pretty` | `false` | Pretty-print JSON with 2-space indentation |
|
|
401
|
+
| `--no-timestamp` | `false` | Omit `generatedAt` for deterministic output |
|
|
329
402
|
|
|
330
|
-
|
|
403
|
+
Examples:
|
|
331
404
|
|
|
332
405
|
```bash
|
|
333
|
-
# Zoom into a
|
|
334
|
-
branch-narrator zoom --finding finding-
|
|
335
|
-
|
|
336
|
-
# Zoom into a risk flag by ID (from 'risk-report' output)
|
|
337
|
-
branch-narrator zoom --flag flag-456
|
|
338
|
-
|
|
339
|
-
# Output as Markdown (default is markdown, can be json or text)
|
|
340
|
-
branch-narrator zoom --finding finding-123 --format md
|
|
406
|
+
# Zoom into a finding
|
|
407
|
+
branch-narrator zoom --finding finding.env-var#abc123
|
|
341
408
|
|
|
342
|
-
#
|
|
343
|
-
branch-narrator zoom --flag flag
|
|
409
|
+
# Zoom into a risk flag
|
|
410
|
+
branch-narrator zoom --flag flag.db.destructive_sql#def456 --format md
|
|
344
411
|
|
|
345
|
-
#
|
|
346
|
-
branch-narrator zoom --finding finding-
|
|
347
|
-
|
|
348
|
-
# Adjust context lines
|
|
349
|
-
branch-narrator zoom --finding finding-123 --unified 5
|
|
412
|
+
# Zoom without patch context
|
|
413
|
+
branch-narrator zoom --finding finding.dependency-change#c0ffee --no-patch
|
|
350
414
|
```
|
|
351
415
|
|
|
352
|
-
|
|
416
|
+
#### integrate
|
|
353
417
|
|
|
354
|
-
Generate provider-specific rules for AI coding assistants
|
|
418
|
+
Generate provider-specific rules for AI coding assistants.
|
|
355
419
|
|
|
356
420
|
```bash
|
|
357
|
-
|
|
358
|
-
branch-narrator integrate cursor
|
|
359
|
-
|
|
360
|
-
# Generate Jules rules
|
|
361
|
-
branch-narrator integrate jules
|
|
362
|
-
|
|
363
|
-
# Preview what would be created without writing files
|
|
364
|
-
branch-narrator integrate cursor --dry-run
|
|
365
|
-
|
|
366
|
-
# Overwrite existing rule files
|
|
367
|
-
branch-narrator integrate cursor --force
|
|
421
|
+
branch-narrator integrate [target] [options]
|
|
368
422
|
```
|
|
369
423
|
|
|
370
|
-
|
|
371
|
-
- Creates provider-specific rule files (e.g., `.cursor/rules/branch-narrator.md`)
|
|
372
|
-
- Instructs the AI on when and how to use `branch-narrator` commands
|
|
373
|
-
- Provides consistent workflows for PR descriptions and analysis
|
|
374
|
-
|
|
375
|
-
**Why use this:**
|
|
376
|
-
- AI assistants will automatically read these rules when working in your repository
|
|
377
|
-
- Ensures the AI uses branch-narrator to ground PR descriptions in actual git diffs instead of guessing
|
|
378
|
-
- Provides consistent PR description templates across your team
|
|
379
|
-
|
|
380
|
-
**Exit codes:**
|
|
381
|
-
- `0`: Success
|
|
382
|
-
- `1`: Expected failure (unknown target, files exist without --force, etc.)
|
|
383
|
-
|
|
384
|
-
## CLI Commands
|
|
385
|
-
|
|
386
|
-
### `pretty` Command
|
|
387
|
-
|
|
388
|
-
Display a colorized summary of changes in the terminal.
|
|
424
|
+
Options:
|
|
389
425
|
|
|
390
426
|
| Option | Default | Description |
|
|
391
427
|
|--------|---------|-------------|
|
|
392
|
-
| `--
|
|
393
|
-
| `--
|
|
394
|
-
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
395
|
-
| `--profile <name>` | `auto` | Profile: `auto`, `sveltekit`, `stencil`, `next`, or `react` |
|
|
396
|
-
|
|
397
|
-
### `pr-body` Command
|
|
398
|
-
|
|
399
|
-
Generate a raw Markdown PR description.
|
|
400
|
-
|
|
401
|
-
| Option | Default | Description |
|
|
402
|
-
|--------|---------|-------------|
|
|
403
|
-
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
404
|
-
| `--base <ref>` | auto-detected | Base git reference (branch mode only; auto-detected from remote HEAD, falls back to `main`) |
|
|
405
|
-
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
406
|
-
| `-u, --uncommitted` | `false` | **[DEPRECATED]** Use `--mode unstaged` instead |
|
|
407
|
-
| `--profile <name>` | `auto` | Profile: `auto`, `sveltekit`, `stencil`, `next`, or `react` |
|
|
408
|
-
| `--interactive` | `false` | Prompt for additional context |
|
|
428
|
+
| `--dry-run` | `false` | Preview without writing files |
|
|
429
|
+
| `--force` | `false` | Overwrite existing files |
|
|
409
430
|
|
|
410
|
-
|
|
431
|
+
Targets:
|
|
411
432
|
|
|
412
|
-
|
|
433
|
+
- `cursor` -> `.cursor/rules/branch-narrator.md` and `.cursor/rules/pr-description.md`
|
|
434
|
+
- `jules` -> `AGENTS.md`
|
|
435
|
+
- `claude` -> `CLAUDE.md`
|
|
436
|
+
- `jules-rules` -> `.jules/rules/branch-narrator.md`
|
|
437
|
+
- `opencode` -> `OPENCODE.md` / `.opencode/branch-narrator.md`
|
|
413
438
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
417
|
-
| `--base <ref>` | auto-detected | Base git reference (branch mode only; auto-detected from remote HEAD, falls back to `main`) |
|
|
418
|
-
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
419
|
-
| `--profile <name>` | `auto` | Profile: `auto`, `sveltekit`, `stencil`, `next`, or `react` |
|
|
439
|
+
When `target` is omitted, `integrate` auto-detects existing guide locations and
|
|
440
|
+
applies matching integrations.
|
|
420
441
|
|
|
421
|
-
|
|
442
|
+
Examples:
|
|
422
443
|
|
|
423
|
-
|
|
444
|
+
```bash
|
|
445
|
+
branch-narrator integrate cursor
|
|
446
|
+
branch-narrator integrate --dry-run
|
|
447
|
+
branch-narrator integrate opencode --force
|
|
448
|
+
```
|
|
424
449
|
|
|
425
|
-
|
|
426
|
-
|--------|---------|-------------|
|
|
427
|
-
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
428
|
-
| `--base <ref>` | auto-detected | Base git reference (branch mode only; auto-detected from remote HEAD, falls back to `main`) |
|
|
429
|
-
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
430
|
-
| `--no-untracked` | (off) | Exclude untracked files (non-branch modes) |
|
|
431
|
-
| `--out <path>` | stdout | Write output to file |
|
|
432
|
-
| `--format <type>` | `text` | Format: `text`, `md`, or `json` |
|
|
433
|
-
| `--unified <n>` | `0` | Lines of unified context |
|
|
434
|
-
| `--include <glob>` | (none) | Include only matching files |
|
|
435
|
-
| `--exclude <glob>` | (none) | Additional exclusion globs |
|
|
436
|
-
| `--max-chars <n>` | (none) | Chunk if output exceeds size |
|
|
437
|
-
| `--chunk-dir <path>` | `.ai/diff-chunks` | Directory for chunks |
|
|
438
|
-
| `--name <prefix>` | `diff` | Chunk file prefix |
|
|
439
|
-
| `--dry-run` | `false` | Preview without writing |
|
|
450
|
+
#### snap
|
|
440
451
|
|
|
441
|
-
|
|
442
|
-
- `unstaged` (default): Working tree vs index (uncommitted changes)
|
|
443
|
-
- `branch`: Compare `--base` to `--head` refs
|
|
444
|
-
- `staged`: Index vs HEAD (staged changes)
|
|
445
|
-
- `all`: Working tree vs HEAD (all uncommitted changes)
|
|
452
|
+
Manage local workspace snapshots.
|
|
446
453
|
|
|
447
|
-
|
|
454
|
+
```bash
|
|
455
|
+
branch-narrator snap <subcommand> [options]
|
|
456
|
+
```
|
|
448
457
|
|
|
449
|
-
|
|
458
|
+
Subcommands:
|
|
450
459
|
|
|
451
|
-
|
|
460
|
+
- `snap save [label]` -- Save a snapshot.
|
|
461
|
+
- Options: `--out <path>`
|
|
462
|
+
- `snap list` -- List snapshots.
|
|
463
|
+
- Options: `--pretty`
|
|
464
|
+
- `snap show <snapshotId>` -- Show snapshot details.
|
|
465
|
+
- Options: `--pretty`
|
|
466
|
+
- `snap diff <idA> <idB>` -- Compare two snapshots.
|
|
467
|
+
- Options: `--pretty`
|
|
468
|
+
- `snap restore <snapshotId>` -- Restore workspace to a snapshot.
|
|
452
469
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
| `<target>` | (required) | Integration target: `cursor`, `jules` |
|
|
456
|
-
| `--dry-run` | `false` | Preview what would be written without creating files |
|
|
457
|
-
| `--force` | `false` | Overwrite existing files |
|
|
470
|
+
Snapshots are stored under `.branch-narrator/`. Add it to `.gitignore` to keep
|
|
471
|
+
snapshots local.
|
|
458
472
|
|
|
459
|
-
|
|
460
|
-
- `cursor`: Generates `.cursor/rules/branch-narrator.md` and `.cursor/rules/pr-description.md`
|
|
461
|
-
- `jules`: Generates `AGENTS.md` in the repository root with Branch Narrator rules for Jules
|
|
473
|
+
Examples:
|
|
462
474
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
-
|
|
466
|
-
- Outputs exact file paths and contents in `--dry-run` mode
|
|
475
|
+
```bash
|
|
476
|
+
# Save a snapshot
|
|
477
|
+
branch-narrator snap save "before-refactor"
|
|
467
478
|
|
|
468
|
-
|
|
479
|
+
# Compare two snapshots
|
|
480
|
+
branch-narrator snap diff abc123def456 def456abc789 --pretty
|
|
481
|
+
```
|
|
469
482
|
|
|
470
|
-
|
|
483
|
+
### Exit Codes
|
|
471
484
|
|
|
472
|
-
| Option | Default | Description |
|
|
473
|
-
|--------|---------|-------------|
|
|
474
|
-
| `--mode <type>` | `unstaged` | Diff mode: `branch`, `unstaged`, `staged`, `all` |
|
|
475
|
-
| `--base <ref>` | auto-detected | Base git reference (branch mode only; auto-detected from remote HEAD, falls back to `main`) |
|
|
476
|
-
| `--head <ref>` | `HEAD` | Head git reference (branch mode only) |
|
|
477
|
-
| `--format <type>` | `json` | Output format: `json`, `md`, or `text` |
|
|
478
|
-
| `--out <path>` | stdout | Write output to file |
|
|
479
|
-
| `--fail-on-score <n>` | (none) | Exit with code 2 if risk score >= threshold |
|
|
480
|
-
| `--only <categories>` | (none) | Only include these categories (comma-separated) |
|
|
481
|
-
| `--exclude <categories>` | (none) | Exclude these categories (comma-separated) |
|
|
482
|
-
| `--max-evidence-lines <n>` | `5` | Max evidence lines per flag |
|
|
483
|
-
| `--redact` | `false` | Redact secret values in evidence |
|
|
484
|
-
| `--explain-score` | `false` | Include score breakdown in output |
|
|
485
|
-
|
|
486
|
-
**Output Schema (v1.0):**
|
|
487
|
-
- `schemaVersion`: "1.0"
|
|
488
|
-
- `range`: { base, head }
|
|
489
|
-
- `riskScore`: 0-100 computed score
|
|
490
|
-
- `riskLevel`: "low" | "moderate" | "elevated" | "high" | "critical"
|
|
491
|
-
- `categoryScores`: Scores per category (0-100)
|
|
492
|
-
- `flags`: Array of risk flags with evidence
|
|
493
|
-
- `skippedFiles`: Files excluded from analysis
|
|
494
|
-
- `scoreBreakdown`: (optional) Score computation details
|
|
495
|
-
|
|
496
|
-
**Exit Codes:**
|
|
497
485
|
| Code | Description |
|
|
498
486
|
|------|-------------|
|
|
499
487
|
| `0` | Success |
|
|
500
|
-
| `1` | Expected
|
|
501
|
-
| `2` | Risk score
|
|
502
|
-
|
|
503
|
-
### `zoom` Command
|
|
504
|
-
|
|
505
|
-
Zoom into a specific finding or flag for detailed context.
|
|
488
|
+
| `1` | Expected failures (not a git repo, invalid refs) |
|
|
489
|
+
| `2` | Risk score threshold exceeded (`risk-report --fail-on-score`) |
|
|
506
490
|
|
|
507
|
-
|
|
508
|
-
|--------|---------|-------------|
|
|
509
|
-
| `--finding <id>` | (optional) | Finding ID to zoom into (mutually exclusive with `--flag`) |
|
|
510
|
-
| `--flag <id>` | (optional) | Flag ID to zoom into (mutually exclusive with `--finding`) |
|
|
511
|
-
| `--format <type>` | `md` | Output format: `json`, `md`, `text` |
|
|
512
|
-
| `--no-patch` | `false` | Exclude patch context, only show evidence |
|
|
513
|
-
| `--unified <n>` | `3` | Lines of unified context for patch hunks |
|
|
514
|
-
| `--max-evidence-lines <n>` | `8` | Max evidence excerpt lines to show |
|
|
515
|
-
| `--redact` | `false` | Redact obvious secret values |
|
|
516
|
-
| `--out <path>` | stdout | Write output to file |
|
|
491
|
+
## CI/CD Integration
|
|
517
492
|
|
|
518
|
-
|
|
493
|
+
### GitHub Actions with SARIF
|
|
519
494
|
|
|
520
|
-
|
|
495
|
+
Upload findings to GitHub Code Scanning:
|
|
521
496
|
|
|
522
|
-
```
|
|
523
|
-
|
|
497
|
+
```yaml
|
|
498
|
+
name: Code Analysis
|
|
524
499
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
- Database migrations detected
|
|
500
|
+
on:
|
|
501
|
+
pull_request:
|
|
502
|
+
branches: [main]
|
|
529
503
|
|
|
530
|
-
|
|
504
|
+
jobs:
|
|
505
|
+
analyze:
|
|
506
|
+
runs-on: ubuntu-latest
|
|
507
|
+
steps:
|
|
508
|
+
- uses: actions/checkout@v4
|
|
509
|
+
with:
|
|
510
|
+
fetch-depth: 0
|
|
531
511
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
512
|
+
- name: Setup Node
|
|
513
|
+
uses: actions/setup-node@v4
|
|
514
|
+
with:
|
|
515
|
+
node-version: "20"
|
|
536
516
|
|
|
537
|
-
|
|
517
|
+
- name: Install branch-narrator
|
|
518
|
+
run: npm install -g @better-vibe/branch-narrator
|
|
538
519
|
|
|
539
|
-
|
|
520
|
+
- name: Generate SARIF report
|
|
521
|
+
run: branch-narrator facts --mode branch --base origin/main --format sarif --out results.sarif
|
|
540
522
|
|
|
541
|
-
|
|
542
|
-
|
|
523
|
+
- name: Upload SARIF to GitHub
|
|
524
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
525
|
+
with:
|
|
526
|
+
sarif_file: results.sarif
|
|
527
|
+
```
|
|
543
528
|
|
|
544
|
-
|
|
529
|
+
### Risk Gate
|
|
545
530
|
|
|
546
|
-
|
|
547
|
-
|----------|--------|----------|
|
|
548
|
-
| `PUBLIC_API_URL` | added | src/lib/config.ts |
|
|
549
|
-
| `DATABASE_URL` | added | src/hooks.server.ts |
|
|
531
|
+
Fail CI if risk score exceeds threshold:
|
|
550
532
|
|
|
551
|
-
|
|
533
|
+
```yaml
|
|
534
|
+
- name: Check risk score
|
|
535
|
+
run: branch-narrator risk-report --mode branch --base origin/main --fail-on-score 60
|
|
536
|
+
```
|
|
552
537
|
|
|
553
|
-
|
|
538
|
+
## Programmatic API
|
|
554
539
|
|
|
555
|
-
|
|
556
|
-
|---------|------|-----|--------|
|
|
557
|
-
| `@sveltejs/kit` | ^1.0.0 | ^2.0.0 | major |
|
|
540
|
+
Use branch-narrator as a library for custom integrations:
|
|
558
541
|
|
|
559
|
-
|
|
542
|
+
```typescript
|
|
543
|
+
import {
|
|
544
|
+
collectChangeSet,
|
|
545
|
+
getProfile,
|
|
546
|
+
resolveProfileName,
|
|
547
|
+
runAnalyzersInParallel,
|
|
548
|
+
computeRiskScore,
|
|
549
|
+
} from "@better-vibe/branch-narrator";
|
|
560
550
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
551
|
+
// Collect git changes
|
|
552
|
+
const changeSet = await collectChangeSet({
|
|
553
|
+
mode: "branch",
|
|
554
|
+
base: "main",
|
|
555
|
+
head: "HEAD",
|
|
556
|
+
});
|
|
565
557
|
|
|
566
|
-
|
|
558
|
+
// Resolve and run profile analyzers
|
|
559
|
+
const profileName = resolveProfileName("auto", changeSet, process.cwd());
|
|
560
|
+
const profile = getProfile(profileName);
|
|
561
|
+
const findings = await runAnalyzersInParallel(profile.analyzers, changeSet);
|
|
567
562
|
|
|
568
|
-
|
|
563
|
+
// Compute risk
|
|
564
|
+
const riskScore = computeRiskScore(findings);
|
|
569
565
|
|
|
570
|
-
|
|
571
|
-
|
|
566
|
+
console.log(`Risk: ${riskScore.level} (${riskScore.score}/100)`);
|
|
567
|
+
console.log(`Findings: ${findings.length}`);
|
|
572
568
|
```
|
|
573
569
|
|
|
574
|
-
|
|
570
|
+
## Example Output
|
|
571
|
+
|
|
572
|
+
Sample `facts` output (truncated):
|
|
575
573
|
|
|
576
574
|
```json
|
|
577
575
|
{
|
|
578
|
-
"
|
|
579
|
-
"
|
|
576
|
+
"schemaVersion": "2.1",
|
|
577
|
+
"git": {
|
|
578
|
+
"base": "main",
|
|
579
|
+
"head": "HEAD",
|
|
580
|
+
"range": "main..HEAD",
|
|
581
|
+
"mode": "branch"
|
|
582
|
+
},
|
|
583
|
+
"profile": {
|
|
584
|
+
"requested": "auto",
|
|
585
|
+
"detected": "sveltekit",
|
|
586
|
+
"confidence": "high"
|
|
587
|
+
},
|
|
588
|
+
"stats": {
|
|
589
|
+
"filesChanged": 12,
|
|
590
|
+
"insertions": 245,
|
|
591
|
+
"deletions": 89
|
|
592
|
+
},
|
|
593
|
+
"risk": {
|
|
580
594
|
"score": 35,
|
|
581
|
-
"level": "
|
|
582
|
-
"
|
|
583
|
-
"
|
|
595
|
+
"level": "moderate",
|
|
596
|
+
"factors": [
|
|
597
|
+
{ "category": "routes", "weight": 15 },
|
|
598
|
+
{ "category": "dependencies", "weight": 10 },
|
|
599
|
+
{ "category": "config", "weight": 10 }
|
|
584
600
|
]
|
|
585
601
|
},
|
|
586
602
|
"findings": [
|
|
587
|
-
{
|
|
588
|
-
"type": "file-summary",
|
|
589
|
-
"added": ["src/routes/dashboard/+page.svelte"],
|
|
590
|
-
"modified": ["package.json"],
|
|
591
|
-
"deleted": [],
|
|
592
|
-
"renamed": []
|
|
593
|
-
},
|
|
594
603
|
{
|
|
595
604
|
"type": "route-change",
|
|
596
|
-
"
|
|
597
|
-
"
|
|
605
|
+
"findingId": "finding.route-change#a1b2c3d4",
|
|
606
|
+
"route": "/api/users",
|
|
598
607
|
"change": "added",
|
|
599
|
-
"
|
|
600
|
-
|
|
601
|
-
{
|
|
602
|
-
"type": "dependency-change",
|
|
603
|
-
"name": "@sveltejs/kit",
|
|
604
|
-
"section": "dependencies",
|
|
605
|
-
"from": "^1.0.0",
|
|
606
|
-
"to": "^2.0.0",
|
|
607
|
-
"impact": "major"
|
|
608
|
+
"methods": ["GET", "POST"],
|
|
609
|
+
"evidence": [...]
|
|
608
610
|
}
|
|
609
611
|
]
|
|
610
612
|
}
|
|
611
613
|
```
|
|
612
614
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
### Route Detector
|
|
616
|
-
|
|
617
|
-
Detects changes under `src/routes/**`:
|
|
618
|
-
|
|
619
|
-
- Maps filesystem paths to SvelteKit route IDs
|
|
620
|
-
- Identifies page, layout, endpoint, and error types
|
|
621
|
-
- Extracts HTTP methods from endpoint exports
|
|
622
|
-
- Preserves param notation (`[slug]`, `[[id]]`, `[...rest]`)
|
|
623
|
-
|
|
624
|
-
### Supabase Migration Detector
|
|
625
|
-
|
|
626
|
-
Scans `supabase/migrations/*.sql` for:
|
|
627
|
-
|
|
628
|
-
- **High risk**: `DROP TABLE`, `DROP COLUMN`, `TRUNCATE`, `ALTER TYPE`, `DELETE` without `WHERE`
|
|
629
|
-
- **Medium risk**: Migrations without destructive patterns
|
|
630
|
-
- **Low risk**: Only seed/config files changed
|
|
631
|
-
|
|
632
|
-
### Environment Variable Detector
|
|
633
|
-
|
|
634
|
-
Extracts env vars from:
|
|
615
|
+
See [`docs/04-types/findings.md`](docs/04-types/findings.md) for the complete
|
|
616
|
+
schema and all finding types.
|
|
635
617
|
|
|
636
|
-
|
|
637
|
-
- `PUBLIC_*` patterns
|
|
638
|
-
- SvelteKit `$env/static/public` imports
|
|
639
|
-
- SvelteKit `$env/static/private` imports
|
|
640
|
-
|
|
641
|
-
### Cloudflare Detector
|
|
642
|
-
|
|
643
|
-
Detects:
|
|
644
|
-
|
|
645
|
-
- `wrangler.toml` / `wrangler.json` changes
|
|
646
|
-
- GitHub workflow changes mentioning Cloudflare/wrangler
|
|
647
|
-
|
|
648
|
-
### Vitest Detector
|
|
649
|
-
|
|
650
|
-
Detects:
|
|
651
|
-
|
|
652
|
-
- `*.test.ts`, `*.spec.ts` files
|
|
653
|
-
- `tests/` directory changes
|
|
654
|
-
- `vitest.config.*` changes
|
|
655
|
-
|
|
656
|
-
### Dependency Analyzer
|
|
657
|
-
|
|
658
|
-
Compares `package.json`:
|
|
659
|
-
|
|
660
|
-
- Additions, removals, and version bumps
|
|
661
|
-
- Semver impact classification (major/minor/patch)
|
|
662
|
-
- Risk flags for critical package major bumps
|
|
663
|
-
|
|
664
|
-
## Profiles
|
|
665
|
-
|
|
666
|
-
### Auto Detection
|
|
667
|
-
|
|
668
|
-
When `--profile auto` (default), the profile is detected by:
|
|
669
|
-
|
|
670
|
-
1. **SvelteKit**: Checking for `src/routes` directory or `@sveltejs/kit` in package.json
|
|
671
|
-
2. **React**: Checking for `react`, `react-dom`, and `react-router-dom` in package.json (only when Next.js is not detected)
|
|
672
|
-
3. **Default**: Generic profile for all other projects
|
|
673
|
-
|
|
674
|
-
### SvelteKit Profile
|
|
675
|
-
|
|
676
|
-
Runs all analyzers optimized for SvelteKit projects, including:
|
|
677
|
-
- SvelteKit route detection (`src/routes/`)
|
|
678
|
-
- SvelteKit env var patterns (`$env/static/public`, `$env/static/private`)
|
|
679
|
-
|
|
680
|
-
### React Profile
|
|
681
|
-
|
|
682
|
-
Runs all analyzers optimized for React projects, including:
|
|
683
|
-
- React Router route detection (JSX `<Route>` components and data routers)
|
|
684
|
-
- Vite env var patterns (`import.meta.env.VITE_*`)
|
|
685
|
-
- React App env var patterns (`process.env.REACT_APP_*`)
|
|
686
|
-
|
|
687
|
-
**Note**: React Router detection requires `react-router` or `react-router-dom` in package.json.
|
|
688
|
-
|
|
689
|
-
## Exit Codes
|
|
618
|
+
## Development
|
|
690
619
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
| `0` | Success |
|
|
694
|
-
| `1` | Expected failures (not a git repo, invalid refs, etc.) |
|
|
695
|
-
| `2` | Risk score threshold exceeded (when using `risk-report --fail-on-score`) |
|
|
620
|
+
See [`docs/06-development/getting-started.md`](docs/06-development/getting-started.md)
|
|
621
|
+
and [`docs/06-development/testing.md`](docs/06-development/testing.md).
|
|
696
622
|
|
|
697
|
-
|
|
623
|
+
Quick commands:
|
|
698
624
|
|
|
699
625
|
```bash
|
|
700
|
-
# Install dependencies
|
|
701
626
|
bun install
|
|
702
|
-
|
|
703
|
-
# Run tests
|
|
704
627
|
bun run test
|
|
705
|
-
|
|
706
|
-
# Build
|
|
707
628
|
bun run build
|
|
708
|
-
|
|
709
|
-
# Type check
|
|
710
629
|
bun run typecheck
|
|
711
|
-
|
|
712
|
-
# Run locally
|
|
713
|
-
bun src/cli.ts pretty -u
|
|
714
|
-
bun src/cli.ts pr-body --base main --head HEAD
|
|
715
|
-
bun src/cli.ts facts -u | jq '.riskScore'
|
|
716
630
|
```
|
|
717
631
|
|
|
632
|
+
## Contributing
|
|
633
|
+
|
|
634
|
+
Contributions are welcome! Please read the development guides before submitting
|
|
635
|
+
a pull request:
|
|
636
|
+
|
|
637
|
+
- [Getting Started](docs/06-development/getting-started.md) - Setup and workflow
|
|
638
|
+
- [Coding Standards](docs/06-development/coding-standards.md) - Code style and conventions
|
|
639
|
+
- [Testing](docs/06-development/testing.md) - Test requirements
|
|
640
|
+
|
|
641
|
+
For bug reports and feature requests, please open an issue.
|
|
642
|
+
|
|
718
643
|
## Requirements
|
|
719
644
|
|
|
720
645
|
- Node.js >= 18
|