@probelabs/visor 0.1.37 → 0.1.39
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 +22 -0
- package/README.md +228 -1981
- package/action.yml +10 -0
- package/defaults/.visor.yaml +1 -1
- package/dist/action-cli-bridge.d.ts +2 -0
- package/dist/action-cli-bridge.d.ts.map +1 -1
- package/dist/ai-review-service.d.ts +4 -0
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/check-execution-engine.d.ts +6 -1
- package/dist/check-execution-engine.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/defaults/.visor.yaml +1 -1
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +569 -163
- package/dist/output-formatters.d.ts.map +1 -1
- package/dist/providers/ai-check-provider.d.ts +8 -0
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/check-provider-registry.d.ts.map +1 -1
- package/dist/providers/check-provider.interface.d.ts +1 -7
- package/dist/providers/check-provider.interface.d.ts.map +1 -1
- package/dist/providers/claude-code-check-provider.d.ts.map +1 -1
- package/dist/providers/http-check-provider.d.ts.map +1 -1
- package/dist/providers/http-client-provider.d.ts.map +1 -1
- package/dist/providers/http-input-provider.d.ts.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/log-check-provider.d.ts +29 -0
- package/dist/providers/log-check-provider.d.ts.map +1 -0
- package/dist/providers/noop-check-provider.d.ts.map +1 -1
- package/dist/providers/tool-check-provider.d.ts +0 -1
- package/dist/providers/tool-check-provider.d.ts.map +1 -1
- package/dist/reviewer.d.ts +0 -1
- package/dist/reviewer.d.ts.map +1 -1
- package/dist/types/cli.d.ts +4 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts +22 -1
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,2153 +1,400 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img src="site/visor.png" alt="Visor Logo" width="500" />
|
|
3
3
|
|
|
4
|
-
# Visor
|
|
4
|
+
# Visor — Open‑source SDLC automation & code review orchestration
|
|
5
5
|
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://nodejs.org/)
|
|
8
8
|
[]()
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Config‑driven checks and automations with native GitHub checks/annotations.
|
|
11
|
+
PR reviews, issue assistants, release notes, scheduled audits, and webhooks.
|
|
12
|
+
AI‑assisted when you want it, fully predictable when you don’t.
|
|
11
13
|
</div>
|
|
12
14
|
|
|
13
15
|
---
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
Visor ships with a ready-to-run configuration at `defaults/.visor.yaml`, so you immediately get:
|
|
18
|
+
- A staged review pipeline (`overview → security → performance → quality → style`).
|
|
19
|
+
- Native GitHub integration: check runs, annotations, and PR comments out of the box.
|
|
20
|
+
- Built‑in code answering assistant: trigger from any issue or PR comment, e.g. `/visor how it works?`.
|
|
21
|
+
- A manual release-notes generator for tagged release workflows.
|
|
22
|
+
- No magic: everything is config‑driven in `.visor.yaml`; prompts/context are visible and templatable.
|
|
23
|
+
- Built for scale: composable checks, tag-based profiles, and flexible `extends` for shared policies.
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
## 🚀 90‑second Quick Start
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
### Add the Action
|
|
20
28
|
|
|
21
|
-
#### Option 1: Using GitHub Token (Default)
|
|
22
29
|
```yaml
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
env:
|
|
35
|
-
# Choose one AI provider (see AI Configuration below)
|
|
36
|
-
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
37
|
-
# ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
38
|
-
# OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
#### Option 2: Using GitHub App Authentication (Recommended for Production)
|
|
42
|
-
For better security and to have comments appear from your custom GitHub App:
|
|
43
|
-
|
|
44
|
-
```yaml
|
|
45
|
-
name: Code Review with GitHub App
|
|
46
|
-
on: pull_request
|
|
47
|
-
|
|
30
|
+
# .github/workflows/visor.yml
|
|
31
|
+
name: Visor
|
|
32
|
+
on:
|
|
33
|
+
pull_request: { types: [opened, synchronize] }
|
|
34
|
+
issues: { types: [opened] }
|
|
35
|
+
issue_comment: { types: [created] }
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
pull-requests: write
|
|
39
|
+
issues: write
|
|
40
|
+
checks: write
|
|
48
41
|
jobs:
|
|
49
|
-
|
|
42
|
+
visor:
|
|
50
43
|
runs-on: ubuntu-latest
|
|
51
44
|
steps:
|
|
52
45
|
- uses: actions/checkout@v4
|
|
53
|
-
- uses:
|
|
54
|
-
with:
|
|
55
|
-
app-id: ${{ secrets.APP_ID }}
|
|
56
|
-
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
|
57
|
-
# installation-id: ${{ secrets.APP_INSTALLATION_ID }} # Optional, auto-detected
|
|
46
|
+
- uses: probelabs/visor@v1
|
|
58
47
|
env:
|
|
59
|
-
|
|
60
|
-
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
61
|
-
# ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
62
|
-
# OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
48
|
+
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} # or ANTHROPIC/OPENAI
|
|
63
49
|
```
|
|
64
50
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- **Pull requests**: Read & Write
|
|
68
|
-
- **Issues**: Write
|
|
69
|
-
- **Metadata**: Read
|
|
70
|
-
2. Generate and download a private key for your app
|
|
71
|
-
3. Install the app on your repository
|
|
72
|
-
4. Add these secrets to your repository:
|
|
73
|
-
- `APP_ID`: Your GitHub App's ID
|
|
74
|
-
- `APP_PRIVATE_KEY`: The private key you downloaded (entire contents)
|
|
75
|
-
- `APP_INSTALLATION_ID`: (Optional) The installation ID for this repository
|
|
51
|
+
### Open a PR
|
|
52
|
+
- Visor posts a PR summary, creates GitHub Check runs, and annotates lines.
|
|
76
53
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
#### Advanced Configuration Options
|
|
80
|
-
|
|
81
|
-
For more control over execution behavior:
|
|
82
|
-
|
|
83
|
-
```yaml
|
|
84
|
-
name: Code Review with Performance Tuning
|
|
85
|
-
on: pull_request
|
|
86
|
-
|
|
87
|
-
jobs:
|
|
88
|
-
review:
|
|
89
|
-
runs-on: ubuntu-latest
|
|
90
|
-
steps:
|
|
91
|
-
- uses: actions/checkout@v4
|
|
92
|
-
- uses: ./ # or: gates-ai/visor-action@v1
|
|
93
|
-
with:
|
|
94
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
95
|
-
max-parallelism: '5' # Run up to 5 checks in parallel
|
|
96
|
-
fail-fast: 'true' # Stop on first failure
|
|
97
|
-
checks: 'security,performance' # Run specific checks only
|
|
98
|
-
env:
|
|
99
|
-
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### As CLI Tool
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
# Build the project
|
|
106
|
-
npm install
|
|
107
|
-
npm run build
|
|
108
|
-
|
|
109
|
-
# Run analysis
|
|
110
|
-
./dist/cli-main.js --check all
|
|
111
|
-
|
|
112
|
-
# Output as JSON
|
|
113
|
-
./dist/cli-main.js --check security --output json
|
|
114
|
-
|
|
115
|
-
# Use custom config
|
|
116
|
-
./dist/cli-main.js --config custom.yaml
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## ✨ Features
|
|
120
|
-
|
|
121
|
-
- **Automated PR Reviews** - Analyzes code changes and posts review comments
|
|
122
|
-
- **Schema-Template System** - Flexible data validation with JSON Schema and Liquid templating
|
|
123
|
-
- **Group-Based Comments** - Multiple GitHub comments organized by check groups
|
|
124
|
-
- **Multiple Check Types** - Security, performance, style, and architecture analysis
|
|
125
|
-
- **Flexible Output** - Table, JSON, Markdown, or SARIF format
|
|
126
|
-
- **Step Dependencies** - Define execution order with `depends_on` relationships
|
|
127
|
-
- **PR Commands** - Trigger reviews with `/review` comments
|
|
128
|
-
- **GitHub Integration** - Creates check runs, adds labels, posts comments
|
|
129
|
-
- **Warning Suppression** - Suppress false positives with `visor-disable` comments
|
|
130
|
-
|
|
131
|
-
## 💬 PR Comment Commands
|
|
132
|
-
|
|
133
|
-
Add comments to your PR to trigger Visor:
|
|
134
|
-
|
|
135
|
-
- `/review` - Run all checks
|
|
136
|
-
- `/review --check security` - Run security checks only
|
|
137
|
-
- `/review --check performance` - Run performance checks only
|
|
138
|
-
- `/review --help` - Show available commands
|
|
139
|
-
|
|
140
|
-
## 🔇 Suppressing Warnings
|
|
141
|
-
|
|
142
|
-
Visor supports suppressing specific warnings or all warnings in a file using special comments in your code. This is useful for false positives or intentional code patterns that should not trigger warnings.
|
|
143
|
-
|
|
144
|
-
### Line-Level Suppression
|
|
145
|
-
|
|
146
|
-
Add `visor-disable` in a comment within ±2 lines of the issue to suppress it:
|
|
147
|
-
|
|
148
|
-
```javascript
|
|
149
|
-
// Example: Suppress a specific warning
|
|
150
|
-
function authenticate() {
|
|
151
|
-
const testPassword = "demo123"; // visor-disable
|
|
152
|
-
// This hardcoded password warning will be suppressed
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
The suppression works with any comment style:
|
|
157
|
-
- `// visor-disable` (JavaScript, TypeScript, C++, etc.)
|
|
158
|
-
- `# visor-disable` (Python, Ruby, Shell, etc.)
|
|
159
|
-
- `/* visor-disable */` (Multi-line comments)
|
|
160
|
-
- `<!-- visor-disable -->` (HTML, XML)
|
|
161
|
-
|
|
162
|
-
### File-Level Suppression
|
|
163
|
-
|
|
164
|
-
To suppress all warnings in an entire file, add `visor-disable-file` in the first 5 lines:
|
|
165
|
-
|
|
166
|
-
```javascript
|
|
167
|
-
// visor-disable-file
|
|
168
|
-
// All warnings in this file will be suppressed
|
|
169
|
-
|
|
170
|
-
function insecureCode() {
|
|
171
|
-
eval("user input"); // No warning
|
|
172
|
-
const password = "hardcoded"; // No warning
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Configuration
|
|
177
|
-
|
|
178
|
-
The suppression feature is enabled by default. You can disable it in your configuration:
|
|
179
|
-
|
|
180
|
-
```yaml
|
|
181
|
-
# .visor.yaml
|
|
182
|
-
version: "1.0"
|
|
183
|
-
output:
|
|
184
|
-
suppressionEnabled: false # Disable suppression comments
|
|
185
|
-
pr_comment:
|
|
186
|
-
format: markdown
|
|
187
|
-
group_by: check
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Important Notes
|
|
191
|
-
|
|
192
|
-
- Suppression comments are **case-insensitive** (`visor-disable`, `VISOR-DISABLE`, `Visor-Disable` all work)
|
|
193
|
-
- The comment just needs to contain the suppression keyword as a substring
|
|
194
|
-
- When issues are suppressed, Visor logs a summary showing which files had suppressed issues
|
|
195
|
-
- Use suppression judiciously - it's better to fix issues than suppress them
|
|
196
|
-
|
|
197
|
-
### Examples
|
|
198
|
-
|
|
199
|
-
```python
|
|
200
|
-
# Python example
|
|
201
|
-
def process_data():
|
|
202
|
-
api_key = "sk-12345" # visor-disable
|
|
203
|
-
return api_key
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
// TypeScript example - suppress within range
|
|
208
|
-
function riskyOperation() {
|
|
209
|
-
// visor-disable
|
|
210
|
-
const unsafe = eval(userInput); // Suppressed (within 2 lines)
|
|
211
|
-
processData(unsafe); // Suppressed (within 2 lines)
|
|
212
|
-
|
|
213
|
-
doSomethingElse();
|
|
214
|
-
anotherOperation(); // NOT suppressed (> 2 lines away)
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
```go
|
|
219
|
-
// Go example - file-level suppression
|
|
220
|
-
// visor-disable-file
|
|
221
|
-
package main
|
|
222
|
-
|
|
223
|
-
func main() {
|
|
224
|
-
password := "hardcoded" // All issues suppressed
|
|
225
|
-
fmt.Println(password)
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## 📋 CLI Usage
|
|
230
|
-
|
|
231
|
-
```bash
|
|
232
|
-
visor [options]
|
|
233
|
-
|
|
234
|
-
Options:
|
|
235
|
-
-c, --check <type> Check type: security, performance, style, architecture, all
|
|
236
|
-
Can be used multiple times: --check security --check style
|
|
237
|
-
-o, --output <format> Output format: table, json, markdown, sarif
|
|
238
|
-
Default: table
|
|
239
|
-
--config <path> Path to configuration file
|
|
240
|
-
Default: visor.config.yaml
|
|
241
|
-
--max-parallelism <count> Maximum number of checks to run in parallel
|
|
242
|
-
Default: 3
|
|
243
|
-
--fail-fast Stop execution when any check fails
|
|
244
|
-
Default: false
|
|
245
|
-
--timeout <ms> Timeout for check operations in milliseconds
|
|
246
|
-
Default: 600000ms (10 minutes)
|
|
247
|
-
--debug Enable debug mode for detailed output
|
|
248
|
-
--allowed-remote-patterns Comma-separated list of allowed URL prefixes for remote configs
|
|
249
|
-
Example: "https://github.com/myorg/,https://raw.githubusercontent.com/"
|
|
250
|
-
--no-remote-extends Disable remote configuration extends for security
|
|
251
|
-
--version Show version
|
|
252
|
-
--help Show help
|
|
253
|
-
|
|
254
|
-
Examples:
|
|
255
|
-
visor --check all # Run all checks
|
|
256
|
-
visor --check security --output json # Security check with JSON output
|
|
257
|
-
visor --check style --check performance # Multiple specific checks
|
|
258
|
-
visor --check all --max-parallelism 5 # Run up to 5 checks in parallel
|
|
259
|
-
visor --check all --fail-fast # Stop on first failure
|
|
260
|
-
visor --check all --timeout 300000 --debug # 5 minute timeout with debug output
|
|
261
|
-
|
|
262
|
-
# Using remote configs with security allowlist
|
|
263
|
-
visor --check all --allowed-remote-patterns "https://github.com/myorg/"
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## 🤖 AI Configuration
|
|
267
|
-
|
|
268
|
-
Visor uses AI-powered code analysis to provide intelligent review feedback. Configure one of the following providers:
|
|
269
|
-
|
|
270
|
-
### Supported AI Providers
|
|
271
|
-
|
|
272
|
-
| Provider | Environment Variable | Recommended Models |
|
|
273
|
-
|----------|---------------------|-------------------|
|
|
274
|
-
| Google Gemini | `GOOGLE_API_KEY` | `gemini-2.0-flash-exp` (default), `gemini-1.5-pro` |
|
|
275
|
-
| Anthropic Claude | `ANTHROPIC_API_KEY` | `claude-3-opus`, `claude-3-sonnet` |
|
|
276
|
-
| OpenAI GPT | `OPENAI_API_KEY` | `gpt-4`, `gpt-4-turbo`, `gpt-3.5-turbo` |
|
|
277
|
-
|
|
278
|
-
### Setting Up API Keys
|
|
279
|
-
|
|
280
|
-
#### For GitHub Actions
|
|
281
|
-
Add your API key as a repository secret:
|
|
282
|
-
1. Go to Settings → Secrets and variables → Actions
|
|
283
|
-
2. Click "New repository secret"
|
|
284
|
-
3. Add one of: `GOOGLE_API_KEY`, `ANTHROPIC_API_KEY`, or `OPENAI_API_KEY`
|
|
285
|
-
4. (Optional) Add `AI_MODEL_NAME` to specify a model
|
|
286
|
-
|
|
287
|
-
#### For Local Development
|
|
288
|
-
Set environment variables:
|
|
289
|
-
```bash
|
|
290
|
-
# Using Google Gemini
|
|
291
|
-
export GOOGLE_API_KEY="your-api-key"
|
|
292
|
-
export MODEL_NAME="gemini-2.0-flash-exp"
|
|
293
|
-
|
|
294
|
-
# Using Anthropic Claude
|
|
295
|
-
export ANTHROPIC_API_KEY="your-api-key"
|
|
296
|
-
export MODEL_NAME="claude-3-sonnet"
|
|
297
|
-
|
|
298
|
-
# Using OpenAI GPT
|
|
299
|
-
export OPENAI_API_KEY="your-api-key"
|
|
300
|
-
export MODEL_NAME="gpt-4"
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### Getting API Keys
|
|
304
|
-
|
|
305
|
-
- **Google Gemini**: [Get API Key](https://makersuite.google.com/app/apikey) (Free tier available)
|
|
306
|
-
- **Anthropic Claude**: [Get API Key](https://console.anthropic.com/)
|
|
307
|
-
- **OpenAI GPT**: [Get API Key](https://platform.openai.com/api-keys)
|
|
308
|
-
|
|
309
|
-
### Fallback Behavior
|
|
310
|
-
|
|
311
|
-
If no API key is configured, Visor will fall back to basic pattern-matching analysis:
|
|
312
|
-
- Keyword detection for security issues (e.g., `eval`, `innerHTML`)
|
|
313
|
-
- Simple performance checks (nested loops, large files)
|
|
314
|
-
- Basic style validation
|
|
315
|
-
|
|
316
|
-
For best results, configure an AI provider for intelligent, context-aware code review.
|
|
317
|
-
|
|
318
|
-
## 📊 Step Dependencies & Intelligent Execution
|
|
319
|
-
|
|
320
|
-
### Dependency-Aware Check Execution
|
|
321
|
-
|
|
322
|
-
Visor supports defining dependencies between checks using the `depends_on` field. This enables:
|
|
323
|
-
|
|
324
|
-
- **Sequential Execution**: Dependent checks wait for their dependencies to complete
|
|
325
|
-
- **Parallel Optimization**: Independent checks run simultaneously for faster execution
|
|
326
|
-
- **Smart Scheduling**: Automatic topological sorting ensures correct execution order
|
|
327
|
-
|
|
328
|
-
### Configuration Example
|
|
54
|
+
### Optional: Add `.visor.yaml`
|
|
329
55
|
|
|
330
56
|
```yaml
|
|
331
57
|
version: "1.0"
|
|
332
58
|
checks:
|
|
333
59
|
security:
|
|
334
60
|
type: ai
|
|
335
|
-
group: code-review
|
|
336
|
-
schema: code-review
|
|
337
|
-
prompt: "Comprehensive security analysis..."
|
|
338
|
-
on: [pr_opened, pr_updated]
|
|
339
|
-
# No dependencies - runs first
|
|
340
|
-
|
|
341
|
-
performance:
|
|
342
|
-
type: ai
|
|
343
|
-
group: code-review
|
|
344
|
-
schema: code-review
|
|
345
|
-
prompt: "Performance analysis..."
|
|
346
|
-
on: [pr_opened, pr_updated]
|
|
347
|
-
# No dependencies - runs parallel with security
|
|
348
|
-
|
|
349
|
-
style:
|
|
350
|
-
type: ai
|
|
351
|
-
group: code-review
|
|
352
|
-
schema: code-review
|
|
353
|
-
prompt: "Style analysis based on security findings..."
|
|
354
|
-
on: [pr_opened]
|
|
355
|
-
depends_on: [security] # Waits for security to complete
|
|
356
|
-
|
|
357
|
-
architecture:
|
|
358
|
-
type: ai
|
|
359
|
-
group: code-review
|
|
360
|
-
schema: code-review
|
|
361
|
-
prompt: "Architecture analysis building on previous checks..."
|
|
362
|
-
on: [pr_opened, pr_updated]
|
|
363
|
-
depends_on: [security, performance] # Waits for both to complete
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### Execution Flow
|
|
367
|
-
|
|
368
|
-
With the above configuration:
|
|
369
|
-
1. **Level 0**: `security` and `performance` run in parallel
|
|
370
|
-
2. **Level 1**: `style` runs after `security` completes
|
|
371
|
-
3. **Level 2**: `architecture` runs after both `security` and `performance` complete
|
|
372
|
-
|
|
373
|
-
### Benefits
|
|
374
|
-
|
|
375
|
-
- **Faster Execution**: Independent checks run in parallel
|
|
376
|
-
- **Better Context**: Later checks can reference findings from dependencies
|
|
377
|
-
- **Logical Flow**: Ensures foundational checks (like security) complete before specialized ones
|
|
378
|
-
- **Error Handling**: Failed dependencies don't prevent other independent checks from running
|
|
379
|
-
|
|
380
|
-
### Advanced Patterns
|
|
381
|
-
|
|
382
|
-
#### Diamond Dependency
|
|
383
|
-
```yaml
|
|
384
|
-
version: "1.0"
|
|
385
|
-
checks:
|
|
386
|
-
foundation:
|
|
387
|
-
type: ai
|
|
388
|
-
group: base
|
|
389
|
-
schema: code-review
|
|
390
|
-
prompt: "Base analysis"
|
|
391
|
-
|
|
392
|
-
branch_a:
|
|
393
|
-
type: ai
|
|
394
|
-
group: code-review
|
|
395
|
-
schema: code-review
|
|
396
|
-
depends_on: [foundation]
|
|
397
|
-
|
|
398
|
-
branch_b:
|
|
399
|
-
type: ai
|
|
400
|
-
group: code-review
|
|
401
|
-
schema: code-review
|
|
402
|
-
depends_on: [foundation]
|
|
403
|
-
|
|
404
|
-
final:
|
|
405
|
-
type: ai
|
|
406
|
-
group: summary
|
|
407
|
-
schema: markdown
|
|
408
|
-
depends_on: [branch_a, branch_b]
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
#### Multiple Independent Chains
|
|
412
|
-
```yaml
|
|
413
|
-
version: "1.0"
|
|
414
|
-
checks:
|
|
415
|
-
# Security chain
|
|
416
|
-
security_basic:
|
|
417
|
-
type: ai
|
|
418
|
-
group: security
|
|
419
|
-
schema: code-review
|
|
420
|
-
prompt: "Basic security scan"
|
|
421
|
-
|
|
422
|
-
security_advanced:
|
|
423
|
-
type: ai
|
|
424
|
-
group: security
|
|
425
61
|
schema: code-review
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
62
|
+
prompt: "Identify security issues in changed files"
|
|
63
|
+
tags: ["fast", "security"]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Tip: Pin releases for stability, e.g. `uses: probelabs/visor@v1`.
|
|
67
|
+
|
|
68
|
+
## 🧩 Core Concepts (1 minute)
|
|
69
|
+
|
|
70
|
+
- Check – unit of work (`security`, `performance`).
|
|
71
|
+
- Schema – JSON shape checks return (e.g., `code-review`).
|
|
72
|
+
- Template – renders results (tables/markdown).
|
|
73
|
+
- Group – which comment a check is posted into.
|
|
74
|
+
- Provider – how a check runs (`ai`, `http`, `tool`, `script`, `claude-code`).
|
|
75
|
+
- Dependencies – `depends_on` controls order; independents run in parallel.
|
|
76
|
+
- Tags – label checks (`fast`, `local`, `comprehensive`) and filter with `--tags`.
|
|
77
|
+
- Events – PRs, issues, `/review` comments, webhooks, or cron schedules.
|
|
78
|
+
|
|
79
|
+
## Beyond Code Review
|
|
80
|
+
|
|
81
|
+
Visor is a general SDLC automation framework:
|
|
82
|
+
- PR Reviews – security/perf/style findings with native annotations
|
|
83
|
+
- Issue Assistant – `/visor …` for code Q&A and triage
|
|
84
|
+
- Release Notes – manual or tagged release workflows
|
|
85
|
+
- Scheduled Audits – cron‑driven checks against main
|
|
86
|
+
- Webhooks & HTTP – receive events, call APIs, and post results
|
|
87
|
+
- Policy‑as‑Code – schemas + templates for predictable, auditable outputs
|
|
88
|
+
|
|
89
|
+
## Table of Contents
|
|
90
|
+
|
|
91
|
+
- [90‑second Quick Start](#90-second-quick-start)
|
|
92
|
+
- [Core Concepts](#core-concepts-1-minute)
|
|
93
|
+
- [Beyond Code Review](#beyond-code-review)
|
|
94
|
+
- [Features](#features)
|
|
95
|
+
- [When to pick Visor](#when-to-pick-visor)
|
|
96
|
+
- [Developer Experience Playbook](#developer-experience-playbook)
|
|
97
|
+
- [Tag-Based Filtering](#tag-based-check-filtering)
|
|
98
|
+
- [PR Comment Commands](#pr-comment-commands)
|
|
99
|
+
- [Suppress Warnings](#suppressing-warnings)
|
|
100
|
+
- [CLI Usage](#cli-usage)
|
|
101
|
+
- [Troubleshooting](#troubleshooting)
|
|
102
|
+
- [Security Defaults](#security-defaults)
|
|
103
|
+
- [Performance & Cost Controls](#performance--cost-controls)
|
|
104
|
+
- [Observability](#observability)
|
|
105
|
+
- [AI Configuration](#ai-configuration)
|
|
106
|
+
- [Step Dependencies](#step-dependencies--intelligent-execution)
|
|
107
|
+
- [Claude Code Provider](#claude-code-provider)
|
|
108
|
+
- [AI Session Reuse](#ai-session-reuse)
|
|
109
|
+
- [Schema-Template System](#schema-template-system)
|
|
110
|
+
- [Enhanced Prompts](#enhanced-prompts)
|
|
111
|
+
- [Advanced Configuration](#advanced-configuration)
|
|
112
|
+
- [HTTP Integration & Scheduling](#http-integration--scheduling)
|
|
113
|
+
- [Pluggable Architecture](#pluggable-architecture)
|
|
114
|
+
- [GitHub Action Reference](#github-action-reference)
|
|
115
|
+
- [Output Formats](#output-formats)
|
|
455
116
|
|
|
456
|
-
##
|
|
117
|
+
## ✨ Features
|
|
457
118
|
|
|
458
|
-
|
|
119
|
+
- Native GitHub reviews: Check runs, inline annotations, and status reporting wired into PRs.
|
|
120
|
+
- Config‑first: One `.visor.yaml` defines checks, prompts, schemas, and templates — no hidden logic.
|
|
121
|
+
- Structured outputs: JSON Schema validation drives deterministic rendering, annotations, and SARIF.
|
|
122
|
+
- Orchestrated pipelines: Dependencies, parallelism, and tag‑based profiles; run in Actions or any CI.
|
|
123
|
+
- Multi‑provider AI: Google Gemini, Anthropic Claude, OpenAI — plus MCP tools and Claude Code SDK.
|
|
124
|
+
- Assistants & commands: `/review` to rerun checks, `/visor …` for Q&A, predictable comment groups.
|
|
125
|
+
- HTTP & schedules: Receive webhooks, call external APIs, and run cron‑scheduled audits and reports.
|
|
126
|
+
- Extensible providers: `ai`, `http`, `http_client`, `log`, `tool`, `script`, `claude-code` — or add your own.
|
|
127
|
+
- Security by default: GitHub App support, scoped tokens, remote‑extends allowlist, opt‑in network usage.
|
|
128
|
+
- Observability & control: JSON/SARIF outputs, fail‑fast and timeouts, parallelism and cost control.
|
|
459
129
|
|
|
460
|
-
|
|
130
|
+
## When to pick Visor
|
|
461
131
|
|
|
462
|
-
-
|
|
463
|
-
-
|
|
464
|
-
-
|
|
465
|
-
-
|
|
466
|
-
-
|
|
132
|
+
- You want native GitHub checks/annotations and config‑driven behavior
|
|
133
|
+
- You need structured outputs (schemas) and predictable templates
|
|
134
|
+
- You care about dependency‑aware execution and tag‑based profiles
|
|
135
|
+
- You want PR reviews + assistants + scheduled audits from one tool
|
|
136
|
+
- You prefer open‑source with no hidden rules
|
|
467
137
|
|
|
468
|
-
|
|
138
|
+
## 🧭 Developer Experience Playbook
|
|
469
139
|
|
|
470
|
-
|
|
471
|
-
checks:
|
|
472
|
-
claude_comprehensive:
|
|
473
|
-
type: claude-code
|
|
474
|
-
prompt: "Perform a comprehensive security and performance review"
|
|
475
|
-
claude_code:
|
|
476
|
-
allowedTools: ['Grep', 'Read', 'WebSearch']
|
|
477
|
-
maxTurns: 5
|
|
478
|
-
systemPrompt: "You are an expert security auditor"
|
|
479
|
-
|
|
480
|
-
claude_with_mcp:
|
|
481
|
-
type: claude-code
|
|
482
|
-
prompt: "Analyze code complexity and architecture"
|
|
483
|
-
claude_code:
|
|
484
|
-
allowedTools: ['analyze_file_structure', 'calculate_complexity']
|
|
485
|
-
mcpServers:
|
|
486
|
-
custom_analyzer:
|
|
487
|
-
command: "node"
|
|
488
|
-
args: ["./mcp-servers/analyzer.js"]
|
|
489
|
-
env:
|
|
490
|
-
ANALYSIS_MODE: "deep"
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
### Built-in MCP Tools
|
|
494
|
-
|
|
495
|
-
- `analyze_file_structure`: Analyzes project organization
|
|
496
|
-
- `detect_patterns`: Identifies code patterns and anti-patterns
|
|
497
|
-
- `calculate_complexity`: Computes complexity metrics
|
|
498
|
-
- `suggest_improvements`: Provides improvement recommendations
|
|
499
|
-
|
|
500
|
-
### Custom MCP Servers
|
|
501
|
-
|
|
502
|
-
Create `.mcp.json` in your project root:
|
|
503
|
-
|
|
504
|
-
```json
|
|
505
|
-
{
|
|
506
|
-
"mcpServers": {
|
|
507
|
-
"security_scanner": {
|
|
508
|
-
"command": "python",
|
|
509
|
-
"args": ["./tools/security_scanner.py"],
|
|
510
|
-
"env": {
|
|
511
|
-
"SCAN_DEPTH": "full"
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
### Environment Setup
|
|
140
|
+
Start with the defaults, iterate locally, and commit a shared `.visor.yaml` for your team.
|
|
519
141
|
|
|
142
|
+
Example:
|
|
520
143
|
```bash
|
|
521
|
-
|
|
522
|
-
npm install -g @anthropic-ai/claude-code
|
|
523
|
-
|
|
524
|
-
# Set API key (optional - uses local Claude Code if available)
|
|
525
|
-
export CLAUDE_CODE_API_KEY=your-api-key
|
|
144
|
+
npx @probelabs/visor --check all --debug
|
|
526
145
|
```
|
|
527
146
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
Visor supports AI session reuse for dependent checks, allowing follow-up analysis to maintain conversation context with the AI. This creates more intelligent, contextual analysis workflows.
|
|
531
|
-
|
|
532
|
-
### How It Works
|
|
147
|
+
Learn more: [docs/dev-playbook.md](docs/dev-playbook.md)
|
|
533
148
|
|
|
534
|
-
|
|
535
|
-
1. **Reuses the ProbeAgent session** from the parent check
|
|
536
|
-
2. **Maintains conversation context** - the AI remembers the previous discussion
|
|
537
|
-
3. **Forces sequential execution** - dependent checks with session reuse run sequentially to preserve context
|
|
538
|
-
4. **Provides intelligent follow-ups** - the AI can reference previous findings
|
|
149
|
+
## 🏷️ Tag-Based Check Filtering
|
|
539
150
|
|
|
540
|
-
|
|
151
|
+
Run subsets of checks (e.g., `local`, `fast`, `security`) and select them per environment with `--tags`/`--exclude-tags`.
|
|
541
152
|
|
|
153
|
+
Example:
|
|
542
154
|
```yaml
|
|
543
|
-
version: "1.0"
|
|
544
|
-
|
|
545
155
|
checks:
|
|
546
|
-
security:
|
|
156
|
+
security-quick:
|
|
547
157
|
type: ai
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
prompt: "Analyze code for security vulnerabilities..."
|
|
551
|
-
on: [pr_opened, pr_updated]
|
|
552
|
-
|
|
553
|
-
security-remediation:
|
|
554
|
-
type: ai
|
|
555
|
-
group: review
|
|
556
|
-
schema: code-review
|
|
557
|
-
prompt: |
|
|
558
|
-
Based on our previous security analysis discussion,
|
|
559
|
-
provide detailed remediation guidance for the issues we identified.
|
|
560
|
-
depends_on: [security]
|
|
561
|
-
reuse_ai_session: true # 🔄 Reuses security check's AI session
|
|
562
|
-
on: [pr_opened, pr_updated]
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
### Key Benefits
|
|
566
|
-
|
|
567
|
-
- **Context Continuity**: AI remembers previous analysis and can reference it
|
|
568
|
-
- **Cost Efficiency**: Reuses existing AI sessions instead of creating new ones
|
|
569
|
-
- **Better Analysis**: Follow-up prompts build on previous discussion
|
|
570
|
-
- **Natural Conversation Flow**: Creates multi-turn conversations with AI
|
|
571
|
-
|
|
572
|
-
### Validation Rules
|
|
573
|
-
|
|
574
|
-
- **Requires Dependencies**: `reuse_ai_session: true` can only be used with `depends_on`
|
|
575
|
-
- **Sequential Execution**: Checks with session reuse are automatically scheduled sequentially
|
|
576
|
-
- **AI Checks Only**: Only works with `type: ai` checks
|
|
577
|
-
- **Clear Error Messages**: Invalid configurations provide helpful guidance
|
|
578
|
-
|
|
579
|
-
### Example Use Cases
|
|
580
|
-
|
|
581
|
-
#### Security Analysis + Remediation
|
|
582
|
-
```yaml
|
|
583
|
-
security:
|
|
584
|
-
type: ai
|
|
585
|
-
prompt: "Identify security vulnerabilities..."
|
|
586
|
-
|
|
587
|
-
security-fixes:
|
|
588
|
-
type: ai
|
|
589
|
-
prompt: "Based on our security discussion, provide step-by-step fix instructions..."
|
|
590
|
-
depends_on: [security]
|
|
591
|
-
reuse_ai_session: true
|
|
158
|
+
prompt: "Quick security scan"
|
|
159
|
+
tags: ["local", "fast", "security"]
|
|
592
160
|
```
|
|
593
161
|
|
|
594
|
-
|
|
595
|
-
```
|
|
596
|
-
|
|
597
|
-
type: ai
|
|
598
|
-
prompt: "Analyze performance issues..."
|
|
599
|
-
|
|
600
|
-
performance-optimization:
|
|
601
|
-
type: ai
|
|
602
|
-
prompt: "Building on our performance analysis, create an optimization roadmap..."
|
|
603
|
-
depends_on: [performance]
|
|
604
|
-
reuse_ai_session: true
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
#### Multi-step Code Review
|
|
608
|
-
```yaml
|
|
609
|
-
initial-review:
|
|
610
|
-
type: ai
|
|
611
|
-
prompt: "Perform comprehensive code review..."
|
|
612
|
-
|
|
613
|
-
clarification:
|
|
614
|
-
type: ai
|
|
615
|
-
prompt: "Let's dive deeper into the most critical issues we identified..."
|
|
616
|
-
depends_on: [initial-review]
|
|
617
|
-
reuse_ai_session: true
|
|
618
|
-
|
|
619
|
-
final-recommendations:
|
|
620
|
-
type: ai
|
|
621
|
-
prompt: "Summarize our discussion with prioritized action items..."
|
|
622
|
-
depends_on: [clarification]
|
|
623
|
-
reuse_ai_session: true
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
## 📋 Schema-Template System
|
|
627
|
-
|
|
628
|
-
Visor's new schema-template system provides structured output validation and customizable rendering, replacing the previous category-based approach with a more flexible, configuration-driven system.
|
|
629
|
-
|
|
630
|
-
### Overview
|
|
631
|
-
|
|
632
|
-
The schema-template system separates data structure (schemas) from presentation (templates), enabling:
|
|
633
|
-
|
|
634
|
-
- **JSON Schema Validation**: Runtime validation of check results using AJV
|
|
635
|
-
- **Liquid Templates**: Dynamic content rendering with conditional logic and loops
|
|
636
|
-
- **Multiple Output Formats**: Support for structured tables, free-form markdown, and custom formats
|
|
637
|
-
- **Group-Based Comments**: Create separate GitHub comments based on `group` configuration
|
|
638
|
-
- **Check-Focused Organization**: Group issues by check name rather than artificial categories
|
|
639
|
-
- **Extensible Design**: Easy to add new schemas and output formats
|
|
640
|
-
|
|
641
|
-
### Configuration
|
|
642
|
-
|
|
643
|
-
```yaml
|
|
644
|
-
version: "1.0"
|
|
645
|
-
|
|
646
|
-
checks:
|
|
647
|
-
security:
|
|
648
|
-
type: ai
|
|
649
|
-
group: code-review # Groups this check with others for commenting
|
|
650
|
-
schema: code-review # Uses built-in code-review schema
|
|
651
|
-
prompt: |
|
|
652
|
-
Perform comprehensive security analysis focusing on:
|
|
653
|
-
- SQL injection vulnerabilities
|
|
654
|
-
- XSS attack vectors
|
|
655
|
-
- Authentication/authorization issues
|
|
656
|
-
|
|
657
|
-
Return results in JSON format matching the code-review schema.
|
|
658
|
-
on: [pr_opened, pr_updated]
|
|
659
|
-
|
|
660
|
-
performance:
|
|
661
|
-
type: ai
|
|
662
|
-
group: code-review # Same group = combined in one comment
|
|
663
|
-
schema: code-review # Same schema = same table format
|
|
664
|
-
prompt: |
|
|
665
|
-
Analyze performance issues including:
|
|
666
|
-
- Algorithm complexity
|
|
667
|
-
- Memory usage patterns
|
|
668
|
-
- Database query optimization
|
|
669
|
-
on: [pr_opened, pr_updated]
|
|
670
|
-
|
|
671
|
-
full-review:
|
|
672
|
-
type: ai
|
|
673
|
-
group: pr-overview # Different group = separate comment
|
|
674
|
-
schema: text # Uses built-in text schema for markdown
|
|
675
|
-
prompt: |
|
|
676
|
-
Create a comprehensive pull request overview in markdown format with:
|
|
677
|
-
|
|
678
|
-
## 📋 Pull Request Overview
|
|
679
|
-
1. **Summary**: Brief description of changes
|
|
680
|
-
2. **Files Changed**: Table of modified files
|
|
681
|
-
3. **Architecture Impact**: Key architectural considerations
|
|
682
|
-
on: [pr_opened]
|
|
683
|
-
```
|
|
684
|
-
|
|
685
|
-
## 🎯 Enhanced Prompts
|
|
686
|
-
|
|
687
|
-
Visor supports advanced prompt features including Liquid templates, file-based prompts, and access to event context and previous check results.
|
|
688
|
-
|
|
689
|
-
### Smart Auto-Detection
|
|
690
|
-
|
|
691
|
-
Visor automatically detects whether your prompt is a file path or inline content:
|
|
692
|
-
|
|
693
|
-
```yaml
|
|
694
|
-
checks:
|
|
695
|
-
security:
|
|
696
|
-
type: ai
|
|
697
|
-
# File path - automatically detected
|
|
698
|
-
prompt: ./templates/security-analysis.liquid
|
|
699
|
-
|
|
700
|
-
performance:
|
|
701
|
-
type: ai
|
|
702
|
-
# Inline string - automatically detected
|
|
703
|
-
prompt: "Analyze this code for performance issues"
|
|
704
|
-
|
|
705
|
-
quality:
|
|
706
|
-
type: ai
|
|
707
|
-
# Multi-line string - automatically detected
|
|
708
|
-
prompt: |
|
|
709
|
-
Review this code for:
|
|
710
|
-
- Code quality issues
|
|
711
|
-
- Best practices violations
|
|
712
|
-
- Maintainability concerns
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
**Auto-detection rules:**
|
|
716
|
-
- ✅ **File paths**: `./file.liquid`, `../templates/prompt.md`, `/absolute/path/file.txt`
|
|
717
|
-
- ✅ **Inline content**: `Analyze this code`, `Review for security issues`
|
|
718
|
-
- ✅ **Multi-line**: Uses YAML `|` or `>` syntax for longer prompts
|
|
719
|
-
|
|
720
|
-
### Liquid Template Support
|
|
721
|
-
|
|
722
|
-
Prompts can use [Liquid templating](https://shopify.github.io/liquid/) with rich context data:
|
|
723
|
-
|
|
724
|
-
```yaml
|
|
725
|
-
checks:
|
|
726
|
-
context-aware-review:
|
|
727
|
-
type: ai
|
|
728
|
-
prompt: |
|
|
729
|
-
# Review for PR {{ pr.number }}: {{ pr.title }}
|
|
730
|
-
|
|
731
|
-
## PR Details
|
|
732
|
-
- Author: {{ pr.author }}
|
|
733
|
-
- Branch: {{ pr.headBranch }} → {{ pr.baseBranch }}
|
|
734
|
-
- Files changed: {{ files.size }}
|
|
735
|
-
- Total changes: +{{ pr.totalAdditions }}/-{{ pr.totalDeletions }}
|
|
736
|
-
|
|
737
|
-
## File Analysis
|
|
738
|
-
{% if utils.filesByExtension.ts %}
|
|
739
|
-
### TypeScript Files ({{ utils.filesByExtension.ts.size }})
|
|
740
|
-
{% for file in utils.filesByExtension.ts %}
|
|
741
|
-
- {{ file.filename }} (+{{ file.additions }}/-{{ file.deletions }})
|
|
742
|
-
{% endfor %}
|
|
743
|
-
{% endif %}
|
|
744
|
-
|
|
745
|
-
{% if utils.hasLargeChanges %}
|
|
746
|
-
⚠️ **Warning**: This PR contains large changes requiring careful review.
|
|
747
|
-
{% endif %}
|
|
748
|
-
|
|
749
|
-
## Previous Results
|
|
750
|
-
{% if outputs.security %}
|
|
751
|
-
Security check found {{ outputs.security.totalIssues }} issues:
|
|
752
|
-
{% for issue in outputs.security.securityIssues %}
|
|
753
|
-
- **{{ issue.severity | upcase }}**: {{ issue.message }} in {{ issue.file }}:{{ issue.line }}
|
|
754
|
-
{% endfor %}
|
|
755
|
-
{% endif %}
|
|
756
|
-
on: [pr_opened, pr_updated]
|
|
757
|
-
```
|
|
758
|
-
|
|
759
|
-
### File-Based Prompts
|
|
760
|
-
|
|
761
|
-
Store prompts in external files for better organization:
|
|
762
|
-
|
|
763
|
-
```yaml
|
|
764
|
-
checks:
|
|
765
|
-
security-review:
|
|
766
|
-
type: ai
|
|
767
|
-
prompt: ./prompts/security-detailed.liquid # Auto-detects file path
|
|
768
|
-
on: [pr_opened, pr_updated]
|
|
769
|
-
|
|
770
|
-
architecture-check:
|
|
771
|
-
type: ai
|
|
772
|
-
prompt: /absolute/path/to/architecture-prompt.liquid # Auto-detects file path
|
|
773
|
-
on: [pr_opened]
|
|
774
|
-
```
|
|
775
|
-
|
|
776
|
-
### Template Context Variables
|
|
777
|
-
|
|
778
|
-
#### PR Information (`pr`)
|
|
779
|
-
```liquid
|
|
780
|
-
{{ pr.number }} <!-- PR number -->
|
|
781
|
-
{{ pr.title }} <!-- PR title -->
|
|
782
|
-
{{ pr.author }} <!-- PR author -->
|
|
783
|
-
{{ pr.baseBranch }} <!-- Base branch name -->
|
|
784
|
-
{{ pr.headBranch }} <!-- Head branch name -->
|
|
785
|
-
{{ pr.totalAdditions }} <!-- Total lines added -->
|
|
786
|
-
{{ pr.totalDeletions }} <!-- Total lines deleted -->
|
|
787
|
-
{{ pr.isIncremental }} <!-- Boolean: incremental analysis -->
|
|
788
|
-
```
|
|
789
|
-
|
|
790
|
-
#### File Information (`files` and `utils`)
|
|
791
|
-
```liquid
|
|
792
|
-
{{ files.size }} <!-- Number of files changed -->
|
|
793
|
-
{{ utils.filesByExtension.ts.size }} <!-- TypeScript files count -->
|
|
794
|
-
{{ utils.filesByExtension.js.size }} <!-- JavaScript files count -->
|
|
795
|
-
{{ utils.addedFiles.size }} <!-- Newly added files -->
|
|
796
|
-
{{ utils.modifiedFiles.size }} <!-- Modified files -->
|
|
797
|
-
{{ utils.hasLargeChanges }} <!-- Boolean: large changes detected -->
|
|
798
|
-
{{ utils.totalFiles }} <!-- Total files changed -->
|
|
799
|
-
```
|
|
800
|
-
|
|
801
|
-
#### GitHub Event Context (`event`)
|
|
802
|
-
```liquid
|
|
803
|
-
{{ event.name }} <!-- Event name (pull_request, issue_comment, etc.) -->
|
|
804
|
-
{{ event.action }} <!-- Event action (opened, updated, etc.) -->
|
|
805
|
-
{{ event.repository.fullName }} <!-- Repository owner/name -->
|
|
806
|
-
|
|
807
|
-
<!-- For comment-triggered events -->
|
|
808
|
-
{% if event.comment %}
|
|
809
|
-
{{ event.comment.body }} <!-- Comment text -->
|
|
810
|
-
{{ event.comment.author }} <!-- Comment author -->
|
|
811
|
-
{% endif %}
|
|
162
|
+
CLI:
|
|
163
|
+
```bash
|
|
164
|
+
visor --tags local,fast
|
|
812
165
|
```
|
|
813
166
|
|
|
814
|
-
|
|
815
|
-
```liquid
|
|
816
|
-
{% if outputs.security %}
|
|
817
|
-
Security Results:
|
|
818
|
-
- Total issues: {{ outputs.security.totalIssues }}
|
|
819
|
-
- Critical: {{ outputs.security.criticalIssues }}
|
|
820
|
-
- Errors: {{ outputs.security.errorIssues }}
|
|
821
|
-
- Warnings: {{ outputs.security.warningIssues }}
|
|
822
|
-
|
|
823
|
-
Security Issues:
|
|
824
|
-
{% for issue in outputs.security.securityIssues %}
|
|
825
|
-
- {{ issue.severity | upcase }}: {{ issue.message }}
|
|
826
|
-
{% endfor %}
|
|
827
|
-
|
|
828
|
-
Suggestions:
|
|
829
|
-
{% for suggestion in outputs.security.suggestions %}
|
|
830
|
-
- {{ suggestion }}
|
|
831
|
-
{% endfor %}
|
|
832
|
-
{% endif %}
|
|
833
|
-
```
|
|
167
|
+
Learn more: [docs/tag-filtering.md](docs/tag-filtering.md)
|
|
834
168
|
|
|
835
|
-
|
|
169
|
+
## 💬 PR Comment Commands
|
|
836
170
|
|
|
837
|
-
|
|
171
|
+
Trigger reviews and assistant actions via comments on PRs/issues.
|
|
838
172
|
|
|
839
|
-
|
|
840
|
-
checks:
|
|
841
|
-
security-with-custom-output:
|
|
842
|
-
type: ai
|
|
843
|
-
prompt: "Analyze security vulnerabilities..."
|
|
844
|
-
template:
|
|
845
|
-
file: ./templates/security-report.liquid
|
|
846
|
-
# OR inline content:
|
|
847
|
-
# content: |
|
|
848
|
-
# # 🔒 Security Report
|
|
849
|
-
# {% for issue in issues %}
|
|
850
|
-
# - **{{ issue.severity }}**: {{ issue.message }}
|
|
851
|
-
# {% endfor %}
|
|
852
|
-
on: [pr_opened]
|
|
173
|
+
Examples:
|
|
853
174
|
```
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
```yaml
|
|
858
|
-
checks:
|
|
859
|
-
comprehensive-review:
|
|
860
|
-
type: ai
|
|
861
|
-
depends_on: [security, performance] # Run after these checks
|
|
862
|
-
prompt:
|
|
863
|
-
content: |
|
|
864
|
-
# Comprehensive Review for {{ event.repository.fullName }}#{{ pr.number }}
|
|
865
|
-
|
|
866
|
-
{% if event.comment %}
|
|
867
|
-
Triggered by comment: "{{ event.comment.body }}" from {{ event.comment.author }}
|
|
868
|
-
{% endif %}
|
|
869
|
-
|
|
870
|
-
## Previous Analysis Summary
|
|
871
|
-
{% if outputs.security %}
|
|
872
|
-
- **Security**: {{ outputs.security.totalIssues }} issues found
|
|
873
|
-
{% for issue in outputs.security.criticalIssues %}
|
|
874
|
-
- 🔴 **CRITICAL**: {{ issue.message }}
|
|
875
|
-
{% endfor %}
|
|
876
|
-
{% endif %}
|
|
877
|
-
|
|
878
|
-
{% if outputs.performance %}
|
|
879
|
-
- **Performance**: {{ outputs.performance.totalIssues }} issues found
|
|
880
|
-
{% endif %}
|
|
881
|
-
|
|
882
|
-
## New Focus Areas
|
|
883
|
-
Based on file changes in this PR:
|
|
884
|
-
{% for ext, files in utils.filesByExtension %}
|
|
885
|
-
- {{ ext | upcase }} files: {{ files.size }}
|
|
886
|
-
{% endfor %}
|
|
887
|
-
|
|
888
|
-
Please provide an architectural review focusing on:
|
|
889
|
-
1. Integration between modified components
|
|
890
|
-
2. Impact on existing security measures
|
|
891
|
-
3. Performance implications of changes
|
|
892
|
-
4. Maintainability and technical debt
|
|
893
|
-
on: [pr_opened, pr_updated]
|
|
175
|
+
/review
|
|
176
|
+
/review --check security
|
|
177
|
+
/visor how does caching work?
|
|
894
178
|
```
|
|
895
179
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
### Check-Level AI Configuration
|
|
180
|
+
Learn more: [docs/commands.md](docs/commands.md)
|
|
899
181
|
|
|
900
|
-
|
|
182
|
+
## 🔇 Suppressing Warnings
|
|
901
183
|
|
|
902
|
-
|
|
903
|
-
# Global AI settings (optional)
|
|
904
|
-
ai_model: gpt-3.5-turbo
|
|
905
|
-
ai_provider: openai
|
|
184
|
+
Suppress a specific issue by adding a nearby `visor-disable` comment.
|
|
906
185
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
prompt: "Perform advanced security analysis..."
|
|
911
|
-
# Override global settings for this check
|
|
912
|
-
ai_model: claude-3-opus
|
|
913
|
-
ai_provider: anthropic
|
|
914
|
-
on: [pr_opened]
|
|
915
|
-
|
|
916
|
-
performance-quick:
|
|
917
|
-
type: ai
|
|
918
|
-
prompt: "Quick performance check..."
|
|
919
|
-
# Use different model for performance checks
|
|
920
|
-
ai_model: gpt-4-turbo
|
|
921
|
-
# ai_provider will inherit global setting (openai)
|
|
922
|
-
on: [pr_updated]
|
|
923
|
-
|
|
924
|
-
quality-standard:
|
|
925
|
-
type: ai
|
|
926
|
-
prompt: "Standard quality review..."
|
|
927
|
-
# No overrides - uses global settings
|
|
928
|
-
on: [pr_opened]
|
|
186
|
+
Example (JS):
|
|
187
|
+
```js
|
|
188
|
+
const testPassword = "demo123"; // visor-disable
|
|
929
189
|
```
|
|
930
190
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
Use environment variables with GitHub Actions-like syntax:
|
|
934
|
-
|
|
935
|
-
```yaml
|
|
936
|
-
# Global environment variables
|
|
937
|
-
env:
|
|
938
|
-
DEFAULT_TIMEOUT: "30000"
|
|
939
|
-
LOG_LEVEL: "info"
|
|
940
|
-
SHARED_SECRET: "${{ env.GITHUB_TOKEN }}"
|
|
941
|
-
|
|
942
|
-
checks:
|
|
943
|
-
security-with-env:
|
|
944
|
-
type: ai
|
|
945
|
-
prompt: |
|
|
946
|
-
Security analysis using timeout: ${{ env.SECURITY_TIMEOUT }}ms
|
|
947
|
-
API endpoint: ${{ env.SECURITY_API_ENDPOINT }}
|
|
948
|
-
|
|
949
|
-
Analyze these files for security issues...
|
|
950
|
-
# Check-specific environment variables
|
|
951
|
-
env:
|
|
952
|
-
SECURITY_API_KEY: "${{ env.ANTHROPIC_API_KEY }}"
|
|
953
|
-
SECURITY_TIMEOUT: "${DEFAULT_TIMEOUT}" # Reference global env
|
|
954
|
-
ANALYSIS_MODE: "comprehensive"
|
|
955
|
-
CUSTOM_RULES: "security,auth,crypto"
|
|
956
|
-
# Use environment variable for AI model
|
|
957
|
-
ai_model: "${{ env.SECURITY_MODEL }}"
|
|
958
|
-
ai_provider: "${{ env.PREFERRED_AI_PROVIDER }}"
|
|
959
|
-
on: [pr_opened, pr_updated]
|
|
960
|
-
```
|
|
191
|
+
Learn more: [docs/suppressions.md](docs/suppressions.md)
|
|
961
192
|
|
|
962
|
-
|
|
193
|
+
## 📋 CLI Usage
|
|
963
194
|
|
|
964
|
-
|
|
195
|
+
Run locally in any CI or dev machine.
|
|
965
196
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
API_KEY: "${{ env.OPENAI_API_KEY }}"
|
|
970
|
-
|
|
971
|
-
# Shell style
|
|
972
|
-
MODEL_NAME: "${CUSTOM_MODEL}"
|
|
973
|
-
|
|
974
|
-
# Simple shell style
|
|
975
|
-
PROVIDER: "$AI_PROVIDER"
|
|
976
|
-
|
|
977
|
-
# Mixed usage
|
|
978
|
-
ENDPOINT: "https://${{ env.API_HOST }}/v1/${API_VERSION}"
|
|
979
|
-
|
|
980
|
-
# Static values
|
|
981
|
-
TIMEOUT: 45000
|
|
982
|
-
DEBUG_MODE: true
|
|
983
|
-
FEATURES: "security,performance"
|
|
197
|
+
Example:
|
|
198
|
+
```bash
|
|
199
|
+
npx @probelabs/visor --check all --output table
|
|
984
200
|
```
|
|
985
201
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
Visor supports configuration inheritance through the `extends` directive, allowing you to build upon existing configurations. This is useful for:
|
|
989
|
-
- Sharing common configurations across projects
|
|
990
|
-
- Building team/organization standards
|
|
991
|
-
- Creating environment-specific configs (dev, staging, prod)
|
|
202
|
+
See [docs/NPM_USAGE.md](docs/NPM_USAGE.md) for full options and examples.
|
|
992
203
|
|
|
993
|
-
|
|
204
|
+
## 🛠️ Troubleshooting
|
|
994
205
|
|
|
995
|
-
|
|
996
|
-
- **Local files**: Relative or absolute paths to YAML files
|
|
997
|
-
- **Remote URLs**: HTTPS URLs to configuration files (requires allowlist for security)
|
|
998
|
-
- **Default**: Built-in default configuration (`extends: default`)
|
|
999
|
-
|
|
1000
|
-
```yaml
|
|
1001
|
-
# .visor.yaml - Your project config
|
|
1002
|
-
extends: ./base-config.yaml # Single extend
|
|
1003
|
-
# OR multiple extends (merged left-to-right)
|
|
1004
|
-
extends:
|
|
1005
|
-
- default # Start with defaults
|
|
1006
|
-
- ./team-standards.yaml # Apply team standards
|
|
1007
|
-
- ./project-specific.yaml # Project overrides
|
|
206
|
+
If comments/annotations don’t appear, verify workflow permissions and run with `--debug`.
|
|
1008
207
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
prompt: "Project-specific analysis..."
|
|
208
|
+
Example:
|
|
209
|
+
```bash
|
|
210
|
+
node dist/index.js --cli --check all --debug
|
|
1013
211
|
```
|
|
1014
212
|
|
|
1015
|
-
|
|
213
|
+
Learn more: [docs/troubleshooting.md](docs/troubleshooting.md)
|
|
1016
214
|
|
|
1017
|
-
|
|
1018
|
-
```yaml
|
|
1019
|
-
version: "1.0"
|
|
1020
|
-
ai_provider: openai
|
|
1021
|
-
ai_model: gpt-4
|
|
215
|
+
## 🔐 Security Defaults
|
|
1022
216
|
|
|
1023
|
-
|
|
1024
|
-
security-scan:
|
|
1025
|
-
type: ai
|
|
1026
|
-
prompt: "Perform security analysis following OWASP guidelines"
|
|
1027
|
-
on: [pr_opened, pr_updated]
|
|
217
|
+
Prefer a GitHub App for production, and restrict remote extends unless explicitly allowed.
|
|
1028
218
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
219
|
+
Examples:
|
|
220
|
+
```bash
|
|
221
|
+
visor --no-remote-extends
|
|
222
|
+
visor --allowed-remote-patterns "https://raw.githubusercontent.com/myorg/"
|
|
1033
223
|
```
|
|
1034
224
|
|
|
1035
|
-
|
|
1036
|
-
```yaml
|
|
1037
|
-
extends: ./team-config.yaml
|
|
225
|
+
Learn more: [docs/security.md](docs/security.md)
|
|
1038
226
|
|
|
1039
|
-
|
|
1040
|
-
ai_model: gpt-4-turbo # Use newer model
|
|
227
|
+
## ⚡ Performance & Cost Controls
|
|
1041
228
|
|
|
1042
|
-
|
|
1043
|
-
# Disable code-quality by setting empty 'on' array
|
|
1044
|
-
code-quality:
|
|
1045
|
-
on: []
|
|
1046
|
-
|
|
1047
|
-
# Add project-specific check
|
|
1048
|
-
performance-check:
|
|
1049
|
-
type: ai
|
|
1050
|
-
prompt: "Analyze performance implications"
|
|
1051
|
-
on: [pr_opened]
|
|
1052
|
-
```
|
|
1053
|
-
|
|
1054
|
-
#### Remote Configuration (with Security)
|
|
1055
|
-
|
|
1056
|
-
For security, remote URLs must be explicitly allowed via CLI:
|
|
229
|
+
Use tags for fast lanes and raise parallelism cautiously.
|
|
1057
230
|
|
|
231
|
+
Example:
|
|
1058
232
|
```bash
|
|
1059
|
-
|
|
1060
|
-
visor --check all \
|
|
1061
|
-
--allowed-remote-patterns "https://github.com/myorg/,https://raw.githubusercontent.com/myorg/"
|
|
1062
|
-
```
|
|
1063
|
-
|
|
1064
|
-
Then use in your config:
|
|
1065
|
-
```yaml
|
|
1066
|
-
extends: https://raw.githubusercontent.com/myorg/configs/main/base.yaml
|
|
1067
|
-
|
|
1068
|
-
checks:
|
|
1069
|
-
# Your project-specific checks...
|
|
233
|
+
visor --tags local,fast --max-parallelism 5
|
|
1070
234
|
```
|
|
1071
235
|
|
|
1072
|
-
|
|
236
|
+
Learn more: [docs/performance.md](docs/performance.md)
|
|
1073
237
|
|
|
1074
|
-
|
|
1075
|
-
2. **URL Allowlist**: Remote URLs must match allowed patterns (empty by default)
|
|
1076
|
-
3. **No Remote by Default**: Use `--no-remote-extends` to completely disable remote configs
|
|
238
|
+
## 👀 Observability
|
|
1077
239
|
|
|
1078
|
-
|
|
240
|
+
Use JSON for pipelines or SARIF for code scanning.
|
|
1079
241
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
- **Checks**: Can be disabled by setting `on: []`
|
|
1085
|
-
|
|
1086
|
-
#### Appending to Prompts with `appendPrompt`
|
|
1087
|
-
|
|
1088
|
-
When extending configurations, you can append additional instructions to existing prompts using the `appendPrompt` field. This is useful for adding project-specific requirements without completely replacing the base prompt.
|
|
1089
|
-
|
|
1090
|
-
**base-config.yaml**:
|
|
1091
|
-
```yaml
|
|
1092
|
-
checks:
|
|
1093
|
-
security-review:
|
|
1094
|
-
type: ai
|
|
1095
|
-
prompt: "Perform basic security analysis"
|
|
1096
|
-
on: [pr_opened]
|
|
1097
|
-
```
|
|
1098
|
-
|
|
1099
|
-
**project-config.yaml**:
|
|
1100
|
-
```yaml
|
|
1101
|
-
extends: ./base-config.yaml
|
|
1102
|
-
|
|
1103
|
-
checks:
|
|
1104
|
-
security-review:
|
|
1105
|
-
# Appends to the parent prompt instead of replacing it
|
|
1106
|
-
appendPrompt: "Also check for SQL injection vulnerabilities and hardcoded secrets"
|
|
1107
|
-
# Result: "Perform basic security analysis\n\nAlso check for SQL injection vulnerabilities and hardcoded secrets"
|
|
242
|
+
Examples:
|
|
243
|
+
```bash
|
|
244
|
+
visor --check security --output json
|
|
245
|
+
visor --check security --output sarif > visor-results.sarif
|
|
1108
246
|
```
|
|
1109
247
|
|
|
1110
|
-
|
|
1111
|
-
- `appendPrompt` is combined with parent `prompt` using a double newline separator
|
|
1112
|
-
- If no parent prompt exists, `appendPrompt` becomes the prompt
|
|
1113
|
-
- Use `prompt` field to completely replace the parent prompt instead of appending
|
|
248
|
+
Learn more: [docs/observability.md](docs/observability.md)
|
|
1114
249
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
With extends, the full priority order becomes:
|
|
250
|
+
## 🤖 AI Configuration
|
|
1118
251
|
|
|
1119
|
-
|
|
1120
|
-
2. **Current file configuration**
|
|
1121
|
-
3. **Extended configurations** (merged in order)
|
|
1122
|
-
4. **Global configuration**
|
|
1123
|
-
5. **Environment variables**
|
|
1124
|
-
6. **Default values** (lowest priority)
|
|
252
|
+
Set one provider key (Google/Anthropic/OpenAI) via env.
|
|
1125
253
|
|
|
254
|
+
Example (Action):
|
|
1126
255
|
```yaml
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
env:
|
|
1131
|
-
GLOBAL_TIMEOUT: "30000"
|
|
1132
|
-
|
|
1133
|
-
checks:
|
|
1134
|
-
example-check:
|
|
1135
|
-
type: ai
|
|
1136
|
-
prompt: "Example analysis"
|
|
1137
|
-
# These override global settings
|
|
1138
|
-
ai_model: claude-3-opus # Overrides global ai_model
|
|
1139
|
-
# ai_provider: inherits openai from global
|
|
1140
|
-
|
|
1141
|
-
env:
|
|
1142
|
-
# Inherits GLOBAL_TIMEOUT from global env
|
|
1143
|
-
CHECK_TIMEOUT: "45000" # Check-specific setting
|
|
1144
|
-
API_KEY: "${{ env.ANTHROPIC_API_KEY }}" # From process env
|
|
256
|
+
- uses: probelabs/visor@v1
|
|
257
|
+
env:
|
|
258
|
+
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
1145
259
|
```
|
|
1146
260
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
For production deployments, set up environment variables:
|
|
261
|
+
Learn more: [docs/ai-configuration.md](docs/ai-configuration.md)
|
|
1150
262
|
|
|
1151
|
-
|
|
1152
|
-
# AI Provider API Keys
|
|
1153
|
-
export OPENAI_API_KEY="sk-your-openai-key"
|
|
1154
|
-
export ANTHROPIC_API_KEY="sk-ant-your-anthropic-key"
|
|
1155
|
-
export GOOGLE_API_KEY="your-google-api-key"
|
|
1156
|
-
|
|
1157
|
-
# GitHub Integration
|
|
1158
|
-
export GITHUB_TOKEN="ghp_your-github-token"
|
|
1159
|
-
|
|
1160
|
-
# Custom Configuration
|
|
1161
|
-
export SECURITY_MODEL="claude-3-opus"
|
|
1162
|
-
export PERFORMANCE_MODEL="gpt-4-turbo"
|
|
1163
|
-
export PREFERRED_AI_PROVIDER="anthropic"
|
|
1164
|
-
export ANALYSIS_TIMEOUT="60000"
|
|
1165
|
-
```
|
|
263
|
+
## 📊 Step Dependencies & Intelligent Execution
|
|
1166
264
|
|
|
1167
|
-
|
|
265
|
+
Define `depends_on` to enforce order; independent checks run in parallel.
|
|
1168
266
|
|
|
267
|
+
Example:
|
|
1169
268
|
```yaml
|
|
1170
|
-
env:
|
|
1171
|
-
# Production environment references
|
|
1172
|
-
OPENAI_KEY: "${{ env.OPENAI_API_KEY }}"
|
|
1173
|
-
ANTHROPIC_KEY: "${{ env.ANTHROPIC_API_KEY }}"
|
|
1174
|
-
GITHUB_ACCESS_TOKEN: "${{ env.GITHUB_TOKEN }}"
|
|
1175
|
-
|
|
1176
269
|
checks:
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
ai_model: "${{ env.SECURITY_MODEL }}"
|
|
1180
|
-
ai_provider: "${{ env.PREFERRED_AI_PROVIDER }}"
|
|
1181
|
-
env:
|
|
1182
|
-
API_KEY: "${{ env.ANTHROPIC_KEY }}"
|
|
1183
|
-
TIMEOUT: "${{ env.ANALYSIS_TIMEOUT }}"
|
|
1184
|
-
prompt: |
|
|
1185
|
-
Production security analysis with ${{ env.ANALYSIS_TIMEOUT }}ms timeout
|
|
1186
|
-
Using provider: ${{ env.PREFERRED_AI_PROVIDER }}
|
|
1187
|
-
Model: ${{ env.SECURITY_MODEL }}
|
|
1188
|
-
|
|
1189
|
-
Perform comprehensive security analysis...
|
|
1190
|
-
```
|
|
1191
|
-
|
|
1192
|
-
### Built-in Schemas
|
|
1193
|
-
|
|
1194
|
-
#### Code Review Schema (`code-review`)
|
|
1195
|
-
Structured format for code analysis results:
|
|
1196
|
-
```json
|
|
1197
|
-
{
|
|
1198
|
-
"issues": [
|
|
1199
|
-
{
|
|
1200
|
-
"file": "src/auth.ts",
|
|
1201
|
-
"line": 15,
|
|
1202
|
-
"ruleId": "security/hardcoded-secret",
|
|
1203
|
-
"message": "Hardcoded API key detected",
|
|
1204
|
-
"severity": "critical",
|
|
1205
|
-
"category": "security",
|
|
1206
|
-
"suggestion": "Use environment variables"
|
|
1207
|
-
}
|
|
1208
|
-
]
|
|
1209
|
-
}
|
|
270
|
+
security: { type: ai }
|
|
271
|
+
performance:{ type: ai, depends_on: [security] }
|
|
1210
272
|
```
|
|
1211
273
|
|
|
1212
|
-
|
|
1213
|
-
Free-form text/markdown content:
|
|
1214
|
-
```json
|
|
1215
|
-
{
|
|
1216
|
-
"content": "# PR Overview\n\nThis PR adds authentication features..."
|
|
1217
|
-
}
|
|
1218
|
-
```
|
|
1219
|
-
|
|
1220
|
-
### Output Templates
|
|
1221
|
-
|
|
1222
|
-
#### Code Review Template
|
|
1223
|
-
Renders structured data as HTML tables with:
|
|
1224
|
-
- Grouping by check name
|
|
1225
|
-
- Severity indicators with emojis (🔴 🟠 🟡 🟢)
|
|
1226
|
-
- Collapsible suggestion details
|
|
1227
|
-
- File and line information
|
|
274
|
+
Learn more: [docs/dependencies.md](docs/dependencies.md)
|
|
1228
275
|
|
|
1229
|
-
|
|
1230
|
-
Renders text/markdown content as-is for:
|
|
1231
|
-
- PR overviews and summaries
|
|
1232
|
-
- Architecture diagrams
|
|
1233
|
-
- Custom formatted content
|
|
1234
|
-
|
|
1235
|
-
### Comment Grouping
|
|
276
|
+
## 🤖 Claude Code Provider
|
|
1236
277
|
|
|
1237
|
-
|
|
278
|
+
Use the Claude Code SDK as a provider for deeper analysis.
|
|
1238
279
|
|
|
280
|
+
Example:
|
|
1239
281
|
```yaml
|
|
1240
282
|
checks:
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
group: code-review # /
|
|
1245
|
-
|
|
1246
|
-
overview:
|
|
1247
|
-
group: summary # Separate comment
|
|
1248
|
-
|
|
1249
|
-
issue-assistant:
|
|
1250
|
-
group: dynamic # Special group: creates NEW comment each time (never updates)
|
|
283
|
+
claude-review:
|
|
284
|
+
type: claude-code
|
|
285
|
+
prompt: "Analyze code complexity"
|
|
1251
286
|
```
|
|
1252
287
|
|
|
1253
|
-
|
|
1254
|
-
- Issue assistants that respond to user questions
|
|
1255
|
-
- Release notes generation
|
|
1256
|
-
- Changelog updates
|
|
1257
|
-
- Any check where you want to preserve the history of responses
|
|
288
|
+
Learn more: [docs/claude-code.md](docs/claude-code.md)
|
|
1258
289
|
|
|
1259
|
-
|
|
290
|
+
## 🔄 AI Session Reuse
|
|
1260
291
|
|
|
1261
|
-
|
|
292
|
+
Reuse context between dependent AI checks for smarter follow‑ups.
|
|
1262
293
|
|
|
294
|
+
Example:
|
|
1263
295
|
```yaml
|
|
1264
|
-
schemas:
|
|
1265
|
-
custom-metrics:
|
|
1266
|
-
file: ./schemas/metrics.json # Local file
|
|
1267
|
-
compliance:
|
|
1268
|
-
url: https://example.com/compliance.json # Remote URL
|
|
1269
|
-
|
|
1270
296
|
checks:
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
297
|
+
security: { type: ai }
|
|
298
|
+
remediation:
|
|
299
|
+
type: ai
|
|
300
|
+
depends_on: [security]
|
|
301
|
+
reuse_ai_session: true
|
|
1274
302
|
```
|
|
1275
303
|
|
|
1276
|
-
|
|
304
|
+
Learn more: [docs/advanced-ai.md](docs/advanced-ai.md)
|
|
1277
305
|
|
|
1278
|
-
|
|
1279
|
-
- ✅ **Group-Based Comments**: Multiple GitHub comments based on `group` property
|
|
1280
|
-
- ✅ **JSON Schema Validation**: Runtime validation with AJV library
|
|
1281
|
-
- ✅ **Liquid Templates**: Dynamic rendering with conditional logic
|
|
1282
|
-
- ✅ **Multiple Output Formats**: Structured tables vs free-form markdown
|
|
1283
|
-
- ✅ **Backwards Compatibility**: Existing configurations continue to work
|
|
1284
|
-
- ✅ **No False Categories**: Eliminates "logic" issues when no logic checks configured
|
|
1285
|
-
- ✅ **Type Safety**: Structured data validation prevents malformed output
|
|
1286
|
-
- ✅ **Extensible Design**: Easy to add custom schemas and templates
|
|
1287
|
-
|
|
1288
|
-
### Schema and Template Properties
|
|
1289
|
-
|
|
1290
|
-
The schema-template system introduces two new configuration properties:
|
|
1291
|
-
|
|
1292
|
-
#### Group Property
|
|
1293
|
-
Controls GitHub comment organization:
|
|
1294
|
-
```yaml
|
|
1295
|
-
checks:
|
|
1296
|
-
security:
|
|
1297
|
-
group: code-review # Groups with other code-review checks
|
|
1298
|
-
performance:
|
|
1299
|
-
group: code-review # Same group = combined in one comment
|
|
1300
|
-
overview:
|
|
1301
|
-
group: pr-summary # Different group = separate comment
|
|
1302
|
-
changelog:
|
|
1303
|
-
group: dynamic # Special: creates NEW comment each time
|
|
1304
|
-
```
|
|
306
|
+
## 📋 Schema-Template System
|
|
1305
307
|
|
|
1306
|
-
|
|
308
|
+
Schemas validate outputs; templates render GitHub‑friendly comments.
|
|
1307
309
|
|
|
1308
|
-
|
|
1309
|
-
Enforces structured output format:
|
|
310
|
+
Example:
|
|
1310
311
|
```yaml
|
|
1311
312
|
checks:
|
|
1312
313
|
security:
|
|
1313
|
-
|
|
314
|
+
type: ai
|
|
315
|
+
schema: code-review
|
|
1314
316
|
prompt: "Return JSON matching code-review schema"
|
|
1315
|
-
overview:
|
|
1316
|
-
schema: text # Free-form markdown
|
|
1317
|
-
prompt: "Return markdown content"
|
|
1318
|
-
```
|
|
1319
|
-
|
|
1320
|
-
#### Benefits
|
|
1321
|
-
- **Check-Based Organization**: Only configured checks appear in results
|
|
1322
|
-
- **Multiple Comments**: Separate GitHub comments based on `group` property
|
|
1323
|
-
- **Structured Output**: JSON Schema validation ensures consistent data
|
|
1324
|
-
- **Flexible Rendering**: Different templates for different output types
|
|
1325
|
-
|
|
1326
|
-
### GitHub Integration Schema Requirements
|
|
1327
|
-
|
|
1328
|
-
Visor is **fully schema-agnostic** - checks can return any structure and templates handle all formatting logic. However, for GitHub Checks API integration (status checks, outputs), specific structure may be required:
|
|
1329
|
-
|
|
1330
|
-
#### Unstructured Checks (No Schema / Plain Schema)
|
|
1331
|
-
```yaml
|
|
1332
|
-
# ✅ No-schema and plain schema behave identically
|
|
1333
|
-
overview:
|
|
1334
|
-
type: ai
|
|
1335
|
-
# No schema - returns raw markdown directly to PR comments
|
|
1336
|
-
prompt: "Analyze this PR and provide an overview"
|
|
1337
|
-
|
|
1338
|
-
documentation:
|
|
1339
|
-
type: ai
|
|
1340
|
-
schema: plain # Equivalent to no schema
|
|
1341
|
-
prompt: "Generate documentation for these changes"
|
|
1342
|
-
```
|
|
1343
|
-
|
|
1344
|
-
**Behavior**: AI returns raw text/markdown → Posted as-is to PR comments → GitHub integration reports 0 issues
|
|
1345
|
-
|
|
1346
|
-
#### Structured Checks (GitHub Checks API Compatible)
|
|
1347
|
-
```yaml
|
|
1348
|
-
security:
|
|
1349
|
-
type: ai
|
|
1350
|
-
schema: code-review # Built-in schema, works out of the box
|
|
1351
|
-
prompt: "Review for security issues and return findings as JSON"
|
|
1352
|
-
|
|
1353
|
-
# Custom schema example
|
|
1354
|
-
custom-check:
|
|
1355
|
-
type: ai
|
|
1356
|
-
schema: |
|
|
1357
|
-
{
|
|
1358
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
1359
|
-
"type": "object",
|
|
1360
|
-
"required": ["issues"],
|
|
1361
|
-
"properties": {
|
|
1362
|
-
"issues": {
|
|
1363
|
-
"type": "array",
|
|
1364
|
-
"items": {
|
|
1365
|
-
"type": "object",
|
|
1366
|
-
"required": ["file", "line", "message", "severity"],
|
|
1367
|
-
"properties": {
|
|
1368
|
-
"file": { "type": "string" },
|
|
1369
|
-
"line": { "type": "integer" },
|
|
1370
|
-
"ruleId": { "type": "string" },
|
|
1371
|
-
"message": { "type": "string" },
|
|
1372
|
-
"severity": { "enum": ["critical", "error", "warning", "info"] },
|
|
1373
|
-
"category": { "type": "string" }
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
prompt: "Review the code and return JSON matching the schema"
|
|
1380
|
-
```
|
|
1381
|
-
|
|
1382
|
-
**Required Structure for GitHub Checks API Integration**:
|
|
1383
|
-
- `issues`: Array of issue objects (required for GitHub status checks)
|
|
1384
|
-
- `issues[].severity`: Must be `"critical"`, `"error"`, `"warning"`, or `"info"`
|
|
1385
|
-
- `issues[].file`: File path (required for GitHub annotations)
|
|
1386
|
-
- `issues[].line`: Line number (required for GitHub annotations)
|
|
1387
|
-
- `issues[].message`: Issue description (required for GitHub annotations)
|
|
1388
|
-
|
|
1389
|
-
#### GitHub Checks API Features
|
|
1390
|
-
When checks return the structured format above:
|
|
1391
|
-
- ✅ **GitHub Status Checks**: Pass/fail based on severity thresholds
|
|
1392
|
-
- ✅ **GitHub Annotations**: Issues appear as file annotations in PR
|
|
1393
|
-
- ✅ **Action Outputs**: `issues-found`, `critical-issues-found` outputs
|
|
1394
|
-
- ✅ **PR Comments**: Structured table format with issue details
|
|
1395
|
-
|
|
1396
|
-
#### Schema Behavior Summary
|
|
1397
|
-
| Schema Type | AI Output | Comment Rendering | GitHub Checks API |
|
|
1398
|
-
|-------------|-----------|-------------------|-------------------|
|
|
1399
|
-
| **None/Plain** | Raw text/markdown | ✅ Posted as-is | ❌ No status checks, 0 issues |
|
|
1400
|
-
| **Structured** | JSON with `issues[]` | ✅ Table format | ✅ Full GitHub integration |
|
|
1401
|
-
|
|
1402
|
-
**Key Design**: Use unstructured (none/plain) for narrative content like overviews and documentation. Use structured schemas for actionable code review findings that integrate with GitHub's checking system.
|
|
1403
|
-
|
|
1404
|
-
## 🧠 Advanced AI Features
|
|
1405
|
-
|
|
1406
|
-
### XML-Formatted Analysis
|
|
1407
|
-
Visor uses structured XML formatting when sending data to AI providers, enabling precise and context-aware analysis for both pull requests and issues.
|
|
1408
|
-
|
|
1409
|
-
#### Pull Request Context
|
|
1410
|
-
For PR events, Visor provides comprehensive code review context:
|
|
1411
|
-
|
|
1412
|
-
```xml
|
|
1413
|
-
<pull_request>
|
|
1414
|
-
<metadata>
|
|
1415
|
-
<number>123</number> <!-- PR number -->
|
|
1416
|
-
<title>Add user authentication</title> <!-- PR title -->
|
|
1417
|
-
<author>developer</author> <!-- PR author username -->
|
|
1418
|
-
<base_branch>main</base_branch> <!-- Target branch (where changes will be merged) -->
|
|
1419
|
-
<target_branch>feature-auth</target_branch> <!-- Source branch (contains the changes) -->
|
|
1420
|
-
<total_additions>250</total_additions> <!-- Total lines added across all files -->
|
|
1421
|
-
<total_deletions>50</total_deletions> <!-- Total lines removed across all files -->
|
|
1422
|
-
<files_changed_count>3</files_changed_count> <!-- Number of files modified -->
|
|
1423
|
-
</metadata>
|
|
1424
|
-
|
|
1425
|
-
<description>
|
|
1426
|
-
<!-- PR description/body text provided by the author -->
|
|
1427
|
-
This PR implements JWT-based authentication with refresh token support
|
|
1428
|
-
</description>
|
|
1429
|
-
|
|
1430
|
-
<full_diff>
|
|
1431
|
-
<!-- Complete unified diff of all changes (present for all PR analyses) -->
|
|
1432
|
-
--- src/auth.ts
|
|
1433
|
-
+++ src/auth.ts
|
|
1434
|
-
@@ -1,3 +1,10 @@
|
|
1435
|
-
+import jwt from 'jsonwebtoken';
|
|
1436
|
-
...
|
|
1437
|
-
</full_diff>
|
|
1438
|
-
|
|
1439
|
-
<commit_diff>
|
|
1440
|
-
<!-- Only present for incremental analysis (pr_updated events) -->
|
|
1441
|
-
<!-- Contains diff of just the latest commit pushed -->
|
|
1442
|
-
</commit_diff>
|
|
1443
|
-
|
|
1444
|
-
<files_summary>
|
|
1445
|
-
<!-- List of all modified files with change statistics -->
|
|
1446
|
-
<file index="1">
|
|
1447
|
-
<filename>src/auth.ts</filename>
|
|
1448
|
-
<status>modified</status> <!-- added/modified/removed/renamed -->
|
|
1449
|
-
<additions>120</additions> <!-- Lines added in this file -->
|
|
1450
|
-
<deletions>10</deletions> <!-- Lines removed from this file -->
|
|
1451
|
-
</file>
|
|
1452
|
-
</files_summary>
|
|
1453
|
-
|
|
1454
|
-
<!-- Only present for issue_comment events on PRs -->
|
|
1455
|
-
<triggering_comment>
|
|
1456
|
-
<author>reviewer1</author>
|
|
1457
|
-
<created_at>2024-01-16T15:30:00Z</created_at>
|
|
1458
|
-
<body>/review --check security</body>
|
|
1459
|
-
</triggering_comment>
|
|
1460
|
-
|
|
1461
|
-
<!-- Historical comments on the PR (excludes triggering comment) -->
|
|
1462
|
-
<comment_history>
|
|
1463
|
-
<comment index="1">
|
|
1464
|
-
<author>reviewer2</author>
|
|
1465
|
-
<created_at>2024-01-15T11:00:00Z</created_at>
|
|
1466
|
-
<body>Please add unit tests for the authentication logic</body>
|
|
1467
|
-
</comment>
|
|
1468
|
-
<comment index="2">
|
|
1469
|
-
<author>developer</author>
|
|
1470
|
-
<created_at>2024-01-15T14:30:00Z</created_at>
|
|
1471
|
-
<body>Tests added in latest commit</body>
|
|
1472
|
-
</comment>
|
|
1473
|
-
</comment_history>
|
|
1474
|
-
</pull_request>
|
|
1475
|
-
```
|
|
1476
|
-
|
|
1477
|
-
#### Issue Context
|
|
1478
|
-
For issue events, Visor provides issue-specific context for intelligent assistance:
|
|
1479
|
-
|
|
1480
|
-
```xml
|
|
1481
|
-
<issue>
|
|
1482
|
-
<metadata>
|
|
1483
|
-
<number>456</number> <!-- Issue number -->
|
|
1484
|
-
<title>Feature request: Add dark mode</title> <!-- Issue title -->
|
|
1485
|
-
<author>user123</author> <!-- Issue author username -->
|
|
1486
|
-
<state>open</state> <!-- Issue state: open/closed -->
|
|
1487
|
-
<created_at>2024-01-15T10:30:00Z</created_at> <!-- When issue was created -->
|
|
1488
|
-
<updated_at>2024-01-16T14:20:00Z</updated_at> <!-- Last update timestamp -->
|
|
1489
|
-
<comments_count>5</comments_count> <!-- Total number of comments -->
|
|
1490
|
-
</metadata>
|
|
1491
|
-
|
|
1492
|
-
<description>
|
|
1493
|
-
<!-- Issue body/description text provided by the author -->
|
|
1494
|
-
I would like to request a dark mode feature for better accessibility...
|
|
1495
|
-
</description>
|
|
1496
|
-
|
|
1497
|
-
<labels>
|
|
1498
|
-
<!-- GitHub labels applied to categorize the issue -->
|
|
1499
|
-
<label>enhancement</label>
|
|
1500
|
-
<label>good first issue</label>
|
|
1501
|
-
<label>ui/ux</label>
|
|
1502
|
-
</labels>
|
|
1503
|
-
|
|
1504
|
-
<assignees>
|
|
1505
|
-
<!-- Users assigned to work on this issue -->
|
|
1506
|
-
<assignee>developer1</assignee>
|
|
1507
|
-
<assignee>developer2</assignee>
|
|
1508
|
-
</assignees>
|
|
1509
|
-
|
|
1510
|
-
<milestone>
|
|
1511
|
-
<!-- Project milestone this issue is part of (if any) -->
|
|
1512
|
-
<title>v2.0 Release</title>
|
|
1513
|
-
<state>open</state> <!-- Milestone state: open/closed -->
|
|
1514
|
-
<due_on>2024-03-01T00:00:00Z</due_on> <!-- Milestone due date -->
|
|
1515
|
-
</milestone>
|
|
1516
|
-
|
|
1517
|
-
<!-- Only present for issue_comment events -->
|
|
1518
|
-
<triggering_comment>
|
|
1519
|
-
<author>user456</author> <!-- User who posted the triggering comment -->
|
|
1520
|
-
<created_at>2024-01-16T15:30:00Z</created_at> <!-- When comment was posted -->
|
|
1521
|
-
<body>/review security --focus authentication</body> <!-- The comment text -->
|
|
1522
|
-
</triggering_comment>
|
|
1523
|
-
|
|
1524
|
-
<!-- Historical comments on the issue (excludes triggering comment) -->
|
|
1525
|
-
<comment_history>
|
|
1526
|
-
<comment index="1"> <!-- Comments ordered by creation time -->
|
|
1527
|
-
<author>developer1</author>
|
|
1528
|
-
<created_at>2024-01-15T11:00:00Z</created_at>
|
|
1529
|
-
<body>This is a great idea! I'll start working on it.</body>
|
|
1530
|
-
</comment>
|
|
1531
|
-
<comment index="2">
|
|
1532
|
-
<author>user123</author>
|
|
1533
|
-
<created_at>2024-01-15T14:30:00Z</created_at>
|
|
1534
|
-
<body>Thanks! Please consider accessibility standards.</body>
|
|
1535
|
-
</comment>
|
|
1536
|
-
</comment_history>
|
|
1537
|
-
</issue>
|
|
1538
|
-
```
|
|
1539
|
-
|
|
1540
|
-
### Incremental Commit Analysis
|
|
1541
|
-
When new commits are pushed to a PR, Visor performs incremental analysis:
|
|
1542
|
-
- **Full Analysis**: Reviews the entire PR on initial creation
|
|
1543
|
-
- **Incremental Analysis**: On new commits, focuses only on the latest changes
|
|
1544
|
-
- **Smart Updates**: Updates existing review comments instead of creating duplicates
|
|
1545
|
-
|
|
1546
|
-
### Intelligent Comment Management
|
|
1547
|
-
- **Unique Comment IDs**: Each PR gets a unique review comment that persists across updates
|
|
1548
|
-
- **Collision Detection**: Prevents conflicts when multiple reviews run simultaneously
|
|
1549
|
-
- **Context-Aware Updates**: Comments are updated with relevant context (PR opened, updated, synchronized)
|
|
1550
|
-
|
|
1551
|
-
## 🌐 HTTP Integration & Scheduling
|
|
1552
|
-
|
|
1553
|
-
Visor provides comprehensive HTTP integration capabilities including webhook reception, HTTP outputs, scheduled executions via cron, and TLS/HTTPS support.
|
|
1554
|
-
|
|
1555
|
-
### HTTP Server for Webhook Reception
|
|
1556
|
-
|
|
1557
|
-
Configure an HTTP/HTTPS server to receive webhooks and trigger checks:
|
|
1558
|
-
|
|
1559
|
-
```yaml
|
|
1560
|
-
version: "1.0"
|
|
1561
|
-
|
|
1562
|
-
http_server:
|
|
1563
|
-
enabled: true
|
|
1564
|
-
port: 8080
|
|
1565
|
-
host: "0.0.0.0"
|
|
1566
|
-
|
|
1567
|
-
# Optional TLS/HTTPS configuration
|
|
1568
|
-
tls:
|
|
1569
|
-
enabled: true
|
|
1570
|
-
cert: "${TLS_CERT}" # From environment variable
|
|
1571
|
-
key: "${TLS_KEY}"
|
|
1572
|
-
ca: "${TLS_CA}" # Optional CA certificate
|
|
1573
|
-
rejectUnauthorized: true
|
|
1574
|
-
|
|
1575
|
-
# Authentication
|
|
1576
|
-
auth:
|
|
1577
|
-
type: bearer_token
|
|
1578
|
-
secret: "${WEBHOOK_SECRET}"
|
|
1579
|
-
|
|
1580
|
-
# Webhook endpoints
|
|
1581
|
-
endpoints:
|
|
1582
|
-
- path: "/webhook/github"
|
|
1583
|
-
name: "github-events"
|
|
1584
|
-
- path: "/webhook/jenkins"
|
|
1585
|
-
name: "jenkins-builds"
|
|
1586
|
-
```
|
|
1587
|
-
|
|
1588
|
-
**Note**: The HTTP server is automatically disabled when running in GitHub Actions to avoid conflicts.
|
|
1589
|
-
|
|
1590
|
-
### Check Types for HTTP Integration
|
|
1591
|
-
|
|
1592
|
-
#### 1. HTTP Input (Webhook Receiver)
|
|
1593
|
-
Receive data from configured webhook endpoints:
|
|
1594
|
-
|
|
1595
|
-
```yaml
|
|
1596
|
-
checks:
|
|
1597
|
-
github-webhook:
|
|
1598
|
-
type: http_input
|
|
1599
|
-
endpoint: "/webhook/github"
|
|
1600
|
-
on: [webhook_received]
|
|
1601
|
-
transform: |
|
|
1602
|
-
{
|
|
1603
|
-
"event": "{{ webhook.action }}",
|
|
1604
|
-
"repository": "{{ webhook.repository.full_name }}"
|
|
1605
|
-
}
|
|
1606
317
|
```
|
|
1607
318
|
|
|
1608
|
-
|
|
1609
|
-
Send check results to external services:
|
|
319
|
+
Learn more: [docs/schema-templates.md](docs/schema-templates.md)
|
|
1610
320
|
|
|
1611
|
-
|
|
1612
|
-
checks:
|
|
1613
|
-
notify-external:
|
|
1614
|
-
type: http
|
|
1615
|
-
depends_on: [security-check]
|
|
1616
|
-
url: "https://api.example.com/notify"
|
|
1617
|
-
method: POST
|
|
1618
|
-
headers:
|
|
1619
|
-
Content-Type: "application/json"
|
|
1620
|
-
Authorization: "Bearer ${API_TOKEN}"
|
|
1621
|
-
body: |
|
|
1622
|
-
{
|
|
1623
|
-
"results": {{ outputs['security-check'] | json }},
|
|
1624
|
-
"timestamp": "{{ 'now' | date: '%Y-%m-%d %H:%M:%S' }}"
|
|
1625
|
-
}
|
|
1626
|
-
```
|
|
1627
|
-
|
|
1628
|
-
#### 3. HTTP Client (Fetch Data)
|
|
1629
|
-
Fetch data from external APIs:
|
|
1630
|
-
|
|
1631
|
-
```yaml
|
|
1632
|
-
checks:
|
|
1633
|
-
fetch-config:
|
|
1634
|
-
type: http_client
|
|
1635
|
-
url: "https://api.example.com/config"
|
|
1636
|
-
method: GET
|
|
1637
|
-
headers:
|
|
1638
|
-
Authorization: "Bearer ${API_TOKEN}"
|
|
1639
|
-
transform: |
|
|
1640
|
-
{
|
|
1641
|
-
"settings": {{ response.data | json }},
|
|
1642
|
-
"fetched_at": "{{ 'now' | date: '%Y-%m-%d' }}"
|
|
1643
|
-
}
|
|
1644
|
-
```
|
|
1645
|
-
|
|
1646
|
-
### Cron Scheduling
|
|
321
|
+
## 🎯 Enhanced Prompts
|
|
1647
322
|
|
|
1648
|
-
|
|
323
|
+
Write prompts inline or in files; Liquid variables provide PR context.
|
|
1649
324
|
|
|
325
|
+
Example:
|
|
1650
326
|
```yaml
|
|
1651
327
|
checks:
|
|
1652
|
-
|
|
1653
|
-
type: ai
|
|
1654
|
-
prompt: "Perform comprehensive security audit"
|
|
1655
|
-
schedule: "0 2 * * *" # Run at 2 AM daily
|
|
1656
|
-
|
|
1657
|
-
hourly-metrics:
|
|
1658
|
-
type: http_client
|
|
1659
|
-
url: "https://metrics.example.com/latest"
|
|
1660
|
-
schedule: "0 * * * *" # Every hour
|
|
1661
|
-
|
|
1662
|
-
weekly-report:
|
|
328
|
+
overview:
|
|
1663
329
|
type: ai
|
|
1664
|
-
prompt:
|
|
1665
|
-
schedule: "0 9 * * MON" # Every Monday at 9 AM
|
|
330
|
+
prompt: ./prompts/overview.liquid
|
|
1666
331
|
```
|
|
1667
332
|
|
|
1668
|
-
|
|
1669
|
-
```
|
|
1670
|
-
┌────────────── minute (0-59)
|
|
1671
|
-
│ ┌──────────── hour (0-23)
|
|
1672
|
-
│ │ ┌────────── day of month (1-31)
|
|
1673
|
-
│ │ │ ┌──────── month (1-12)
|
|
1674
|
-
│ │ │ │ ┌────── day of week (0-6, Sunday=0)
|
|
1675
|
-
│ │ │ │ │
|
|
1676
|
-
* * * * *
|
|
1677
|
-
```
|
|
1678
|
-
|
|
1679
|
-
### TLS/HTTPS Configuration
|
|
1680
|
-
|
|
1681
|
-
Support for various TLS certificate configurations:
|
|
333
|
+
Learn more: [docs/schema-templates.md](docs/schema-templates.md)
|
|
1682
334
|
|
|
1683
|
-
|
|
1684
|
-
```yaml
|
|
1685
|
-
tls:
|
|
1686
|
-
enabled: true
|
|
1687
|
-
cert: "${TLS_CERT}" # Certificate from env var
|
|
1688
|
-
key: "${TLS_KEY}" # Private key from env var
|
|
1689
|
-
```
|
|
1690
|
-
|
|
1691
|
-
#### File Paths
|
|
1692
|
-
```yaml
|
|
1693
|
-
tls:
|
|
1694
|
-
enabled: true
|
|
1695
|
-
cert: "/etc/ssl/certs/server.crt"
|
|
1696
|
-
key: "/etc/ssl/private/server.key"
|
|
1697
|
-
ca: "/etc/ssl/certs/ca-bundle.crt"
|
|
1698
|
-
```
|
|
1699
|
-
|
|
1700
|
-
#### Let's Encrypt
|
|
1701
|
-
```yaml
|
|
1702
|
-
tls:
|
|
1703
|
-
enabled: true
|
|
1704
|
-
cert: "/etc/letsencrypt/live/example.com/fullchain.pem"
|
|
1705
|
-
key: "/etc/letsencrypt/live/example.com/privkey.pem"
|
|
1706
|
-
```
|
|
1707
|
-
|
|
1708
|
-
### HTTP Security Features
|
|
335
|
+
## 🔧 Advanced Configuration
|
|
1709
336
|
|
|
1710
|
-
|
|
337
|
+
Extend shared configs and override per‑repo settings.
|
|
1711
338
|
|
|
1712
|
-
|
|
339
|
+
Example:
|
|
1713
340
|
```yaml
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
secret: "${WEBHOOK_SECRET}"
|
|
1718
|
-
|
|
1719
|
-
# HMAC-SHA256 Signature Verification
|
|
1720
|
-
auth:
|
|
1721
|
-
type: hmac
|
|
1722
|
-
secret: "${WEBHOOK_SECRET}"
|
|
1723
|
-
|
|
1724
|
-
# Basic Authentication
|
|
1725
|
-
auth:
|
|
1726
|
-
type: basic
|
|
1727
|
-
username: "${HTTP_USERNAME}"
|
|
1728
|
-
password: "${HTTP_PASSWORD}"
|
|
341
|
+
extends:
|
|
342
|
+
- default
|
|
343
|
+
- ./team-standards.yaml
|
|
1729
344
|
```
|
|
1730
345
|
|
|
1731
|
-
|
|
1732
|
-
For `hmac` authentication, webhooks must include the `x-webhook-signature` header:
|
|
1733
|
-
- Signature format: `sha256={hash}`
|
|
1734
|
-
- Uses HMAC-SHA256 with the configured secret
|
|
1735
|
-
- Implements timing-safe comparison to prevent timing attacks
|
|
1736
|
-
- Compatible with GitHub webhook signatures
|
|
346
|
+
Learn more: [docs/configuration.md](docs/configuration.md)
|
|
1737
347
|
|
|
1738
|
-
|
|
1739
|
-
- **Request size limits**: Maximum 1MB request body size
|
|
1740
|
-
- **Early rejection**: Validates `Content-Length` header before processing
|
|
1741
|
-
- **Graceful error handling**: Returns proper HTTP status codes (413 Payload Too Large)
|
|
1742
|
-
|
|
1743
|
-
#### Security Best Practices
|
|
1744
|
-
- **Environment detection**: Automatically disables in GitHub Actions
|
|
1745
|
-
- **TLS support**: Full HTTPS configuration with custom certificates
|
|
1746
|
-
- **Input validation**: Validates all webhook payloads before processing
|
|
1747
|
-
- **Error isolation**: Security failures don't affect independent checks
|
|
348
|
+
## 🌐 HTTP Integration & Scheduling
|
|
1748
349
|
|
|
1749
|
-
|
|
350
|
+
Receive webhooks, call APIs, and schedule checks.
|
|
1750
351
|
|
|
352
|
+
Examples:
|
|
1751
353
|
```yaml
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
# HTTP server configuration
|
|
1755
|
-
http_server:
|
|
1756
|
-
enabled: true
|
|
1757
|
-
port: 8443
|
|
1758
|
-
tls:
|
|
1759
|
-
enabled: true
|
|
1760
|
-
cert: "${TLS_CERT}"
|
|
1761
|
-
key: "${TLS_KEY}"
|
|
1762
|
-
auth:
|
|
1763
|
-
type: bearer_token
|
|
1764
|
-
secret: "${WEBHOOK_SECRET}"
|
|
1765
|
-
endpoints:
|
|
1766
|
-
- path: "/webhook/deployment"
|
|
1767
|
-
name: "deployment-trigger"
|
|
1768
|
-
|
|
354
|
+
http_server: { enabled: true, port: 8080 }
|
|
1769
355
|
checks:
|
|
1770
|
-
|
|
1771
|
-
deployment-webhook:
|
|
1772
|
-
type: http_input
|
|
1773
|
-
endpoint: "/webhook/deployment"
|
|
1774
|
-
on: [webhook_received]
|
|
1775
|
-
transform: |
|
|
1776
|
-
{
|
|
1777
|
-
"version": "{{ webhook.version }}",
|
|
1778
|
-
"environment": "{{ webhook.environment }}"
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
# 2. Analyze deployment
|
|
1782
|
-
deployment-analysis:
|
|
1783
|
-
type: ai
|
|
1784
|
-
depends_on: [deployment-webhook]
|
|
1785
|
-
prompt: |
|
|
1786
|
-
Analyze deployment for version {{ outputs['deployment-webhook'].suggestions | first }}
|
|
1787
|
-
Check for potential issues and risks
|
|
1788
|
-
|
|
1789
|
-
# 3. Fetch current status
|
|
1790
|
-
current-status:
|
|
1791
|
-
type: http_client
|
|
1792
|
-
depends_on: [deployment-webhook]
|
|
1793
|
-
url: "https://api.example.com/status"
|
|
1794
|
-
method: GET
|
|
1795
|
-
|
|
1796
|
-
# 4. Send results
|
|
1797
|
-
notify-team:
|
|
1798
|
-
type: http
|
|
1799
|
-
depends_on: [deployment-analysis, current-status]
|
|
1800
|
-
url: "https://slack.example.com/webhook"
|
|
1801
|
-
body: |
|
|
1802
|
-
{
|
|
1803
|
-
"text": "Deployment Analysis Complete",
|
|
1804
|
-
"analysis": {{ outputs['deployment-analysis'] | json }},
|
|
1805
|
-
"current_status": {{ outputs['current-status'] | json }}
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
# 5. Scheduled health check
|
|
1809
|
-
health-check:
|
|
1810
|
-
type: http_client
|
|
1811
|
-
url: "https://api.example.com/health"
|
|
1812
|
-
schedule: "*/5 * * * *" # Every 5 minutes
|
|
1813
|
-
transform: |
|
|
1814
|
-
{
|
|
1815
|
-
"status": "{{ response.status }}",
|
|
1816
|
-
"checked_at": "{{ 'now' | date: '%Y-%m-%d %H:%M:%S' }}"
|
|
1817
|
-
}
|
|
356
|
+
nightly: { type: ai, schedule: "0 2 * * *" }
|
|
1818
357
|
```
|
|
1819
358
|
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
All HTTP configurations support Liquid templating for dynamic content:
|
|
1823
|
-
|
|
1824
|
-
- Access webhook data: `{{ webhook.field }}`
|
|
1825
|
-
- Access headers: `{{ headers['x-custom-header'] }}`
|
|
1826
|
-
- Access previous outputs: `{{ outputs['check-name'].suggestions | first }}`
|
|
1827
|
-
- Date formatting: `{{ 'now' | date: '%Y-%m-%d' }}`
|
|
1828
|
-
- JSON encoding: `{{ data | json }}`
|
|
359
|
+
Learn more: [docs/http.md](docs/http.md)
|
|
1829
360
|
|
|
1830
361
|
## 🔧 Pluggable Architecture
|
|
1831
362
|
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
### Supported Check Types
|
|
1835
|
-
- **AI Provider**: Intelligent analysis using LLMs (Google Gemini, Anthropic Claude, OpenAI GPT)
|
|
1836
|
-
- **Claude Code Provider**: Advanced AI analysis using Claude Code SDK with MCP tools and subagents
|
|
1837
|
-
- **Tool Provider**: Integration with external tools (ESLint, Prettier, SonarQube)
|
|
1838
|
-
- **HTTP Provider**: Send data to external HTTP endpoints
|
|
1839
|
-
- **HTTP Input Provider**: Receive data from webhooks
|
|
1840
|
-
- **HTTP Client Provider**: Fetch data from external APIs
|
|
1841
|
-
- **Script Provider**: Custom shell scripts and commands
|
|
1842
|
-
|
|
1843
|
-
### Adding Custom Providers
|
|
1844
|
-
```typescript
|
|
1845
|
-
// Custom provider implementation
|
|
1846
|
-
export class CustomCheckProvider extends CheckProvider {
|
|
1847
|
-
getName(): string {
|
|
1848
|
-
return 'custom-security-scan';
|
|
1849
|
-
}
|
|
1850
|
-
|
|
1851
|
-
async execute(prInfo: PRInfo, config: CheckProviderConfig): Promise<ReviewSummary> {
|
|
1852
|
-
// Your custom analysis logic
|
|
1853
|
-
return {
|
|
1854
|
-
issues: [...],
|
|
1855
|
-
suggestions: [...]
|
|
1856
|
-
};
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
// Register your provider
|
|
1861
|
-
CheckProviderRegistry.getInstance().registerProvider(new CustomCheckProvider());
|
|
1862
|
-
```
|
|
1863
|
-
|
|
1864
|
-
## ⚙️ Configuration
|
|
1865
|
-
|
|
1866
|
-
Create `visor.config.yaml` in your project root:
|
|
1867
|
-
|
|
1868
|
-
```yaml
|
|
1869
|
-
# .visor.yaml
|
|
1870
|
-
version: "1.0"
|
|
363
|
+
Mix providers (`ai`, `http`, `http_client`, `log`, `tool`, `script`, `claude-code`) or add your own.
|
|
1871
364
|
|
|
1872
|
-
|
|
1873
|
-
project:
|
|
1874
|
-
name: "My Project"
|
|
1875
|
-
description: "My awesome project"
|
|
1876
|
-
language: "typescript" # primary language
|
|
1877
|
-
frameworks: # frameworks in use
|
|
1878
|
-
- "react"
|
|
1879
|
-
- "nodejs"
|
|
1880
|
-
|
|
1881
|
-
# Analysis configuration
|
|
1882
|
-
analysis:
|
|
1883
|
-
# File patterns to include/exclude
|
|
1884
|
-
include:
|
|
1885
|
-
- "src/**/*" # Include all files in src
|
|
1886
|
-
- "lib/**/*" # Include all files in lib
|
|
1887
|
-
exclude:
|
|
1888
|
-
- "node_modules/**" # Exclude node_modules
|
|
1889
|
-
- "dist/**" # Exclude build output
|
|
1890
|
-
- "**/*.test.ts" # Exclude test files
|
|
1891
|
-
|
|
1892
|
-
# Limits
|
|
1893
|
-
maxFileSize: 500000 # Max file size in bytes (500KB)
|
|
1894
|
-
maxFiles: 1000 # Max number of files to analyze
|
|
1895
|
-
|
|
1896
|
-
# Check-specific settings
|
|
1897
|
-
checks:
|
|
1898
|
-
security:
|
|
1899
|
-
enabled: true # Enable/disable this check
|
|
1900
|
-
severity: warning # Minimum severity: info, warning, error, critical
|
|
1901
|
-
rules: # Specific rules to apply
|
|
1902
|
-
- detect-secrets
|
|
1903
|
-
- xss-prevention
|
|
1904
|
-
- sql-injection
|
|
1905
|
-
|
|
1906
|
-
performance:
|
|
1907
|
-
enabled: true
|
|
1908
|
-
severity: info
|
|
1909
|
-
rules:
|
|
1910
|
-
- complexity-analysis
|
|
1911
|
-
- memory-leaks
|
|
1912
|
-
- algorithm-efficiency
|
|
1913
|
-
depends_on: [security] # Run after security check completes
|
|
1914
|
-
|
|
1915
|
-
style:
|
|
1916
|
-
enabled: true
|
|
1917
|
-
severity: info
|
|
1918
|
-
extends: "eslint:recommended" # Extend from ESLint config
|
|
1919
|
-
rules:
|
|
1920
|
-
- naming-conventions
|
|
1921
|
-
- formatting
|
|
1922
|
-
depends_on: [security] # Ensure secure coding style
|
|
1923
|
-
|
|
1924
|
-
architecture:
|
|
1925
|
-
enabled: true
|
|
1926
|
-
severity: warning
|
|
1927
|
-
rules:
|
|
1928
|
-
- circular-dependencies
|
|
1929
|
-
- design-patterns
|
|
1930
|
-
depends_on: [security, performance] # Build on foundational checks
|
|
1931
|
-
|
|
1932
|
-
# Thresholds for pass/fail
|
|
1933
|
-
thresholds:
|
|
1934
|
-
minScore: 70 # Minimum overall score (0-100)
|
|
1935
|
-
maxIssues: 100 # Maximum total issues
|
|
1936
|
-
maxCriticalIssues: 0 # Maximum critical issues
|
|
1937
|
-
|
|
1938
|
-
# Output settings
|
|
1939
|
-
reporting:
|
|
1940
|
-
format: markdown # Default output format
|
|
1941
|
-
verbose: false # Show detailed output
|
|
1942
|
-
includeFixSuggestions: true # Include fix suggestions
|
|
1943
|
-
groupByFile: true # Group issues by file
|
|
1944
|
-
```
|
|
365
|
+
Learn more: [docs/pluggable.md](docs/pluggable.md)
|
|
1945
366
|
|
|
1946
367
|
## 🎯 GitHub Action Reference
|
|
1947
368
|
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
| Input | Description | Default | Required |
|
|
1951
|
-
|-------|-------------|---------|----------|
|
|
1952
|
-
| `github-token` | GitHub token for API access | `${{ github.token }}` | Yes |
|
|
1953
|
-
| `auto-review` | Auto-review on PR open/update | `true` | No |
|
|
1954
|
-
| `checks` | Checks to run (comma-separated) | `all` | No |
|
|
1955
|
-
| `output-format` | Output format | `markdown` | No |
|
|
1956
|
-
| `config-path` | Path to config file | `visor.config.yaml` | No |
|
|
1957
|
-
| `max-parallelism` | Maximum number of checks to run in parallel | `3` | No |
|
|
1958
|
-
| `fail-fast` | Stop execution when any check fails | `false` | No |
|
|
1959
|
-
| `comment-on-pr` | Post review as PR comment | `true` | No |
|
|
1960
|
-
| `create-check` | Create GitHub check run | `true` | No |
|
|
1961
|
-
| `add-labels` | Add quality labels to PR | `true` | No |
|
|
1962
|
-
| `fail-on-critical` | Fail if critical issues found | `false` | No |
|
|
1963
|
-
| `min-score` | Minimum score to pass (0-100) | `0` | No |
|
|
1964
|
-
|
|
1965
|
-
### Outputs
|
|
1966
|
-
|
|
1967
|
-
| Output | Description |
|
|
1968
|
-
|--------|-------------|
|
|
1969
|
-
| `review-score` | Overall code quality score (0-100) |
|
|
1970
|
-
| `total-issues` | Total number of issues found |
|
|
1971
|
-
| `critical-issues` | Number of critical issues |
|
|
1972
|
-
| `auto-review-completed` | Whether auto-review was completed (true/false) |
|
|
1973
|
-
| `pr-action` | The PR action that triggered the review (opened/synchronize/edited) |
|
|
1974
|
-
| `incremental-analysis` | Whether incremental analysis was used (true/false) |
|
|
1975
|
-
| `issues-found` | Total number of issues found (alias for total-issues) |
|
|
1976
|
-
| `review-url` | URL to the review comment |
|
|
1977
|
-
|
|
1978
|
-
### Example Workflows
|
|
1979
|
-
|
|
1980
|
-
#### Basic Review with Incremental Analysis
|
|
1981
|
-
```yaml
|
|
1982
|
-
name: PR Review
|
|
1983
|
-
on:
|
|
1984
|
-
pull_request:
|
|
1985
|
-
types: [opened, synchronize, edited] # Enable incremental analysis on new commits
|
|
1986
|
-
|
|
1987
|
-
jobs:
|
|
1988
|
-
review:
|
|
1989
|
-
runs-on: ubuntu-latest
|
|
1990
|
-
steps:
|
|
1991
|
-
- uses: actions/checkout@v4
|
|
1992
|
-
- uses: ./
|
|
1993
|
-
with:
|
|
1994
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
1995
|
-
auto-review: true # Enable automatic review
|
|
1996
|
-
env:
|
|
1997
|
-
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
1998
|
-
MODEL_NAME: gemini-2.0-flash-exp
|
|
1999
|
-
```
|
|
2000
|
-
|
|
2001
|
-
#### Security Focus with SARIF Upload
|
|
2002
|
-
```yaml
|
|
2003
|
-
name: Security Scan
|
|
2004
|
-
on: [push, pull_request]
|
|
2005
|
-
|
|
2006
|
-
jobs:
|
|
2007
|
-
security:
|
|
2008
|
-
runs-on: ubuntu-latest
|
|
2009
|
-
steps:
|
|
2010
|
-
- uses: actions/checkout@v4
|
|
2011
|
-
- name: Run Visor Security Scan
|
|
2012
|
-
uses: ./
|
|
2013
|
-
with:
|
|
2014
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
2015
|
-
checks: security
|
|
2016
|
-
output-format: sarif
|
|
2017
|
-
|
|
2018
|
-
- name: Upload SARIF
|
|
2019
|
-
uses: github/codeql-action/upload-sarif@v2
|
|
2020
|
-
if: always()
|
|
2021
|
-
with:
|
|
2022
|
-
sarif_file: visor-results.sarif
|
|
2023
|
-
```
|
|
369
|
+
Common inputs include `max-parallelism`, `fail-fast`, and `config-path`.
|
|
2024
370
|
|
|
2025
|
-
|
|
371
|
+
Example:
|
|
2026
372
|
```yaml
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
jobs:
|
|
2031
|
-
quality:
|
|
2032
|
-
runs-on: ubuntu-latest
|
|
2033
|
-
steps:
|
|
2034
|
-
- uses: actions/checkout@v4
|
|
2035
|
-
- uses: ./
|
|
2036
|
-
with:
|
|
2037
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
2038
|
-
min-score: 80
|
|
2039
|
-
fail-on-critical: true
|
|
373
|
+
- uses: probelabs/visor@v1
|
|
374
|
+
with:
|
|
375
|
+
max-parallelism: 5
|
|
2040
376
|
```
|
|
2041
377
|
|
|
2042
|
-
|
|
2043
|
-
```yaml
|
|
2044
|
-
name: Manual Review
|
|
2045
|
-
on:
|
|
2046
|
-
issue_comment:
|
|
2047
|
-
types: [created]
|
|
2048
|
-
|
|
2049
|
-
jobs:
|
|
2050
|
-
review:
|
|
2051
|
-
if: |
|
|
2052
|
-
github.event.issue.pull_request &&
|
|
2053
|
-
startsWith(github.event.comment.body, '/review')
|
|
2054
|
-
runs-on: ubuntu-latest
|
|
2055
|
-
steps:
|
|
2056
|
-
- uses: actions/checkout@v4
|
|
2057
|
-
- uses: ./
|
|
2058
|
-
with:
|
|
2059
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
2060
|
-
```
|
|
378
|
+
Learn more: [docs/action-reference.md](docs/action-reference.md)
|
|
2061
379
|
|
|
2062
380
|
## 📊 Output Formats
|
|
2063
381
|
|
|
2064
|
-
|
|
2065
|
-
```
|
|
2066
|
-
╔════════════════════════════════════════════════════════════════╗
|
|
2067
|
-
║ Analysis Summary ║
|
|
2068
|
-
╠════════════════════════════════════════════════════════════════╣
|
|
2069
|
-
║ Overall Score: 85/100 Issues Found: 12 ║
|
|
2070
|
-
╟────────────────────────────────────────────────────────────────╢
|
|
2071
|
-
║ ✓ Security: 92/100 ⚠ Performance: 78/100 ║
|
|
2072
|
-
║ ✓ Style: 88/100 ✓ Architecture: 82/100 ║
|
|
2073
|
-
╚════════════════════════════════════════════════════════════════╝
|
|
2074
|
-
```
|
|
2075
|
-
|
|
2076
|
-
### JSON
|
|
2077
|
-
```json
|
|
2078
|
-
{
|
|
2079
|
-
"summary": {
|
|
2080
|
-
"overallScore": 85,
|
|
2081
|
-
"totalIssues": 12,
|
|
2082
|
-
"criticalIssues": 1
|
|
2083
|
-
},
|
|
2084
|
-
"issues": [
|
|
2085
|
-
{
|
|
2086
|
-
"file": "src/api.ts",
|
|
2087
|
-
"line": 45,
|
|
2088
|
-
"severity": "critical",
|
|
2089
|
-
"category": "security",
|
|
2090
|
-
"message": "Potential SQL injection"
|
|
2091
|
-
}
|
|
2092
|
-
]
|
|
2093
|
-
}
|
|
2094
|
-
```
|
|
2095
|
-
|
|
2096
|
-
### SARIF
|
|
2097
|
-
Compatible with GitHub Security tab and other SARIF consumers.
|
|
2098
|
-
|
|
2099
|
-
## 🛠️ Development
|
|
382
|
+
Emit `table`, `json`, `markdown`, or `sarif`.
|
|
2100
383
|
|
|
2101
|
-
|
|
384
|
+
Example:
|
|
2102
385
|
```bash
|
|
2103
|
-
|
|
2104
|
-
git clone https://github.com/your-org/visor.git
|
|
2105
|
-
cd visor
|
|
2106
|
-
npm install
|
|
2107
|
-
|
|
2108
|
-
# Build
|
|
2109
|
-
npm run build
|
|
2110
|
-
|
|
2111
|
-
# Test
|
|
2112
|
-
npm test
|
|
386
|
+
visor --check security --output json
|
|
2113
387
|
```
|
|
2114
388
|
|
|
2115
|
-
|
|
2116
|
-
```
|
|
2117
|
-
visor/
|
|
2118
|
-
├── src/
|
|
2119
|
-
│ ├── cli-main.ts # CLI entry point
|
|
2120
|
-
│ ├── index.ts # GitHub Action entry
|
|
2121
|
-
│ ├── reviewer.ts # Core review logic
|
|
2122
|
-
│ └── output-formatters.ts # Output formatting
|
|
2123
|
-
├── tests/ # Test suites
|
|
2124
|
-
├── .github/workflows/ # GitHub workflows
|
|
2125
|
-
├── action.yml # Action metadata
|
|
2126
|
-
└── visor.config.yaml # Default config
|
|
2127
|
-
```
|
|
2128
|
-
|
|
2129
|
-
### Available Scripts
|
|
2130
|
-
|
|
2131
|
-
| Command | Description |
|
|
2132
|
-
|---------|-------------|
|
|
2133
|
-
| `npm run build` | Build TypeScript |
|
|
2134
|
-
| `npm test` | Run tests |
|
|
2135
|
-
| `npm run test:watch` | Test watch mode |
|
|
2136
|
-
| `npm run test:coverage` | Coverage report |
|
|
389
|
+
Learn more: [docs/output-formats.md](docs/output-formats.md)
|
|
2137
390
|
|
|
2138
391
|
## 🤝 Contributing
|
|
2139
392
|
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
1. Fork the repository
|
|
2143
|
-
2. Create a feature branch
|
|
2144
|
-
3. Make your changes
|
|
2145
|
-
4. Add tests
|
|
2146
|
-
5. Submit a PR
|
|
393
|
+
Learn more: [docs/contributing.md](docs/contributing.md)
|
|
2147
394
|
|
|
2148
395
|
## 📄 License
|
|
2149
396
|
|
|
2150
|
-
MIT License
|
|
397
|
+
MIT License — see [LICENSE](LICENSE)
|
|
2151
398
|
|
|
2152
399
|
---
|
|
2153
400
|
|