repopilot 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -28
- package/package.json +39 -36
- package/scripts/smoke-product.sh +264 -0
- package/scripts/verify-release.sh +84 -0
package/README.md
CHANGED
|
@@ -2,33 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://crates.io/crates/repopilot)
|
|
4
4
|
[](https://www.npmjs.com/package/repopilot)
|
|
5
|
-
[](https://docs.rs/repopilot)
|
|
6
5
|
[](https://github.com/MykytaStel/repopilot/actions)
|
|
7
6
|
[](https://github.com/MykytaStel/repopilot/releases)
|
|
8
7
|
[](LICENSE)
|
|
8
|
+
[](https://github.com/MykytaStel/repopilot)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Audit your repository locally, turn the results into AI-ready remediation context,
|
|
11
|
+
and ship safer changes without sending source code to a hosted scanner.
|
|
11
12
|
|
|
12
|
-
RepoPilot
|
|
13
|
+
RepoPilot is a local-first CLI for architecture, security, code quality, testing,
|
|
14
|
+
and framework health checks. It gives developers useful terminal reports, CI gates,
|
|
15
|
+
SARIF for GitHub Code Scanning, and Markdown briefs that can be pasted into Claude
|
|
16
|
+
Code, ChatGPT, Cursor, or another coding assistant.
|
|
13
17
|
|
|
14
18
|
## Why RepoPilot?
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
Most linters and audit tools stop at the terminal. RepoPilot bridges the gap to your AI assistant:
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
| | SonarQube / CodeClimate | ESLint / language linters | **RepoPilot** |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| Runs offline | ❌ | ✅ | ✅ |
|
|
25
|
+
| No code upload | ❌ | ✅ | ✅ |
|
|
26
|
+
| Cross-language architecture analysis | ✅ | ❌ | ✅ |
|
|
27
|
+
| LLM-ready output | ❌ | ❌ | ✅ |
|
|
28
|
+
| Fits in a model context window | ❌ | ❌ | ✅ |
|
|
29
|
+
| CI gate on new findings only | ✅ | partial | ✅ |
|
|
19
30
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- which findings already existed;
|
|
24
|
-
- where to review first.
|
|
25
|
-
|
|
26
|
-
RepoPilot runs locally and does not upload your repository.
|
|
31
|
+
```bash
|
|
32
|
+
repopilot ai context . | pbcopy # macOS: paste into your coding assistant
|
|
33
|
+
```
|
|
27
34
|
|
|
28
35
|
## Features
|
|
29
36
|
|
|
30
37
|
- Repository scanning for projects, folders, and individual files
|
|
31
|
-
- Gitignore-aware walking with built-in ignores for common build and
|
|
38
|
+
- Gitignore-aware walking with built-in ignores for common build, cache, vendor, and native platform directories
|
|
32
39
|
- Architecture findings: oversized files, deep nesting, too many modules per directory
|
|
33
40
|
- Coupling analysis: excessive fan-out, high-instability hubs, circular dependencies
|
|
34
41
|
- Code quality findings: cyclomatic complexity density, long functions, TODO/FIXME/HACK markers
|
|
@@ -36,20 +43,24 @@ RepoPilot runs locally and does not upload your repository.
|
|
|
36
43
|
- Testing findings: missing test folder, source files without test counterparts
|
|
37
44
|
- Framework findings for JavaScript, React, React Native, and Expo projects
|
|
38
45
|
- React Native architecture profile: project kind, New Architecture, Hermes, Codegen, platform mismatch, and package manager signals
|
|
39
|
-
- Workspace scanning (`--workspace`) for npm, yarn, pnpm, and Cargo workspaces with per-package risk summary
|
|
46
|
+
- Workspace scanning (`--workspace`) for npm, yarn, pnpm, and Cargo workspaces with per-package risk summary — parallel per-package scans
|
|
40
47
|
- Evidence-backed findings with stable rule IDs, severity, file paths, line numbers, and snippets
|
|
41
48
|
- 36 built-in rules with titles, descriptions, recommendations, and docs links
|
|
42
49
|
- `repopilot.toml` configuration generated by `repopilot init`
|
|
50
|
+
- Configuration presets (`--preset strict|balanced|lenient`) for quick threshold tuning
|
|
43
51
|
- Baseline workflow for accepting existing findings in legacy repositories
|
|
44
52
|
- CI-friendly failure thresholds with `--fail-on`
|
|
45
53
|
- Git diff-aware review mode for prioritizing findings introduced by changed lines
|
|
46
54
|
- Console, JSON, Markdown, HTML, and SARIF (2.1.0) scan output — SARIF includes per-result category and workspace package properties
|
|
47
|
-
- First-party GitHub Action wrapper with optional SARIF upload
|
|
55
|
+
- First-party GitHub Action wrapper for `scan`, `review`, `compare`, and `ai` workflows, with optional SARIF upload for scans
|
|
48
56
|
- Compare mode for diffing two JSON scan reports
|
|
57
|
+
- **`repopilot ai context`** — formats scan output as LLM-ready markdown, paste into Claude Code or ChatGPT to start remediating
|
|
58
|
+
- **`repopilot ai plan`** — turns findings into a prioritized remediation plan
|
|
59
|
+
- **`repopilot ai prompt`** — exports an AI-ready remediation prompt with RepoPilot context
|
|
49
60
|
|
|
50
61
|
See [docs/rulesets.md](docs/rulesets.md) for the full list of rules and severity levels.
|
|
51
62
|
|
|
52
|
-
##
|
|
63
|
+
## Install
|
|
53
64
|
|
|
54
65
|
```bash
|
|
55
66
|
cargo install repopilot
|
|
@@ -61,11 +72,27 @@ Install with npm:
|
|
|
61
72
|
npm install -g repopilot
|
|
62
73
|
```
|
|
63
74
|
|
|
75
|
+
Install with Homebrew:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
brew tap mykytastel/repopilot
|
|
79
|
+
brew install repopilot
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Install with curl (Linux/macOS):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
curl -fsSL https://raw.githubusercontent.com/MykytaStel/repopilot/main/install.sh | bash
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The curl installer verifies the GitHub Release SHA256 checksum and aborts if the checksum cannot be downloaded or verified.
|
|
89
|
+
|
|
64
90
|
Upgrade:
|
|
65
91
|
|
|
66
92
|
```bash
|
|
67
93
|
cargo install repopilot --force
|
|
68
94
|
npm update -g repopilot
|
|
95
|
+
brew update && brew upgrade repopilot
|
|
69
96
|
```
|
|
70
97
|
|
|
71
98
|
Build from source:
|
|
@@ -81,13 +108,14 @@ cargo build --release
|
|
|
81
108
|
```bash
|
|
82
109
|
repopilot init
|
|
83
110
|
repopilot scan .
|
|
111
|
+
repopilot ai context .
|
|
112
|
+
repopilot review . --base origin/main --fail-on new-high
|
|
84
113
|
```
|
|
85
114
|
|
|
86
|
-
|
|
115
|
+
Save a shareable report:
|
|
87
116
|
|
|
88
117
|
```bash
|
|
89
118
|
repopilot scan . --format markdown --output repopilot-report.md
|
|
90
|
-
repopilot review . --base origin/main --baseline .repopilot/baseline.json --fail-on new-high
|
|
91
119
|
```
|
|
92
120
|
|
|
93
121
|
Reduce scan noise while iterating:
|
|
@@ -95,27 +123,91 @@ Reduce scan noise while iterating:
|
|
|
95
123
|
```bash
|
|
96
124
|
repopilot scan . --min-severity high
|
|
97
125
|
repopilot scan . --workspace --min-severity medium
|
|
126
|
+
repopilot scan . --exclude fixtures --max-file-size 1mb --max-files 500
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
By default, RepoPilot skips low-signal audit paths such as tests, fixtures, examples, generated files, and benchmarks. Use `--include-low-signal` when you want those paths analyzed too.
|
|
130
|
+
|
|
131
|
+
## Local-First AI Workflow
|
|
132
|
+
|
|
133
|
+
RepoPilot does not call LLM APIs. AI commands scan local files and produce Markdown
|
|
134
|
+
that you decide where to paste.
|
|
135
|
+
|
|
136
|
+
`repopilot ai context` scans a project and formats all findings as structured markdown ready to paste into Claude Code, Cursor, ChatGPT, or any LLM assistant. It includes a risk level, tech stack summary, findings grouped by category with evidence snippets and fix recommendations, and a token-count estimate.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Paste into Claude Code or ChatGPT
|
|
140
|
+
repopilot ai context .
|
|
141
|
+
|
|
142
|
+
# Focus on security only, keep it short
|
|
143
|
+
repopilot ai context . --focus security --budget 2k
|
|
144
|
+
|
|
145
|
+
# Save to file
|
|
146
|
+
repopilot ai context . --output repopilot-context.md
|
|
147
|
+
|
|
148
|
+
# Pipe directly into clipboard (macOS)
|
|
149
|
+
repopilot ai context . --no-header | pbcopy
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Example Output
|
|
153
|
+
|
|
98
154
|
```
|
|
155
|
+
$ repopilot ai context .
|
|
156
|
+
|
|
157
|
+
# RepoPilot Vibe Check — my-app
|
|
158
|
+
|
|
159
|
+
**Risk Level:** 🟠 ELEVATED
|
|
160
|
+
**Tech Stack:** React Native (New Arch), Expo, TypeScript
|
|
161
|
+
**Size:** 94 files · 8,340 LOC · ~42k tokens
|
|
162
|
+
**Health:** 18 findings · 2.2/kloc — 4 high, 9 medium
|
|
163
|
+
|
|
164
|
+
## Security (2 high)
|
|
165
|
+
1. [HIGH] Possible secret detected — `src/config/api.ts:12`
|
|
166
|
+
```
|
|
167
|
+
const API_KEY = "sk_live_…"
|
|
168
|
+
```
|
|
169
|
+
> **Fix:** Move to environment variables or a secrets manager.
|
|
99
170
|
|
|
100
|
-
##
|
|
171
|
+
## Architecture (2 high)
|
|
172
|
+
1. [HIGH] Circular dependency detected — `src/store/index.ts`
|
|
173
|
+
> **Fix:** Extract shared types to a separate module to break the cycle.
|
|
174
|
+
|
|
175
|
+
## Top Recommendations
|
|
176
|
+
1. **Move hardcoded API key** (src/config/api.ts:12) — use process.env or a vault
|
|
177
|
+
2. **Break circular dependency** (src/store/index.ts) — extract shared types
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
*~3.8k tokens (budget: 4k) · scanned in 312ms — paste into Claude Code, Cursor, or ChatGPT*
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Paste this into a coding assistant and ask for a focused patch. For larger
|
|
184
|
+
repositories, start with one focus area instead of asking for every finding at
|
|
185
|
+
once.
|
|
186
|
+
|
|
187
|
+
## Recommended Remediation Loop
|
|
101
188
|
|
|
102
189
|
RepoPilot is a local-first safety layer for AI-assisted and vibe-coded changes. Run it after generating or refactoring code to catch newly introduced high-risk findings, workspace hotspots, missing tests, and architecture drift without uploading source code to an external service.
|
|
103
190
|
|
|
104
191
|
```bash
|
|
192
|
+
repopilot ai context . --focus security # get an LLM brief for Claude Code
|
|
193
|
+
repopilot ai plan . --focus security # get a prioritized hardening plan
|
|
194
|
+
repopilot ai prompt . --budget 8k # generate a paste-ready remediation prompt
|
|
105
195
|
repopilot review . --base origin/main --baseline .repopilot/baseline.json --fail-on new-high
|
|
106
196
|
repopilot scan . --workspace --min-severity medium --format markdown --output repopilot-report.md
|
|
107
197
|
```
|
|
108
198
|
|
|
109
|
-
The v0.7.0 release does not add new `vibe`, `harden`, or AI prompt commands. Those are planned as deterministic post-0.7 workflows built on the existing scan and review data.
|
|
110
|
-
|
|
111
199
|
## Commands
|
|
112
200
|
|
|
113
201
|
| Command | Alias | Description |
|
|
114
202
|
|---------|-------|-------------|
|
|
115
203
|
| `repopilot scan <path>` | `s` | Scan a project, folder, or file for findings |
|
|
116
204
|
| `repopilot review [path]` | `r` | Review findings that touch changed Git diff lines |
|
|
205
|
+
| `repopilot ai context <path>` | — | LLM-ready context from a scan |
|
|
206
|
+
| `repopilot ai plan <path>` | — | Prioritized remediation plan |
|
|
207
|
+
| `repopilot ai prompt <path>` | — | AI-ready remediation prompt |
|
|
117
208
|
| `repopilot compare <before> <after>` | `cmp` | Compare two JSON scan reports and show what changed |
|
|
118
209
|
| `repopilot baseline create <path>` | `bl` | Scan a path and store current findings as accepted debt |
|
|
210
|
+
| `repopilot doctor [path]` | `d` | Diagnose audit readiness |
|
|
119
211
|
| `repopilot init` | — | Generate a default `repopilot.toml` configuration file |
|
|
120
212
|
|
|
121
213
|
Use `--help` on any command for the full description and examples:
|
|
@@ -164,7 +256,12 @@ ignore = [
|
|
|
164
256
|
"dist",
|
|
165
257
|
"build",
|
|
166
258
|
".next",
|
|
167
|
-
"
|
|
259
|
+
".nuxt",
|
|
260
|
+
".cache",
|
|
261
|
+
"coverage",
|
|
262
|
+
"vendor",
|
|
263
|
+
"Pods",
|
|
264
|
+
"DerivedData"
|
|
168
265
|
]
|
|
169
266
|
max_file_bytes = 2097152
|
|
170
267
|
|
|
@@ -194,8 +291,16 @@ CLI threshold overrides:
|
|
|
194
291
|
repopilot scan . --max-file-loc 500
|
|
195
292
|
repopilot scan . --max-directory-modules 25
|
|
196
293
|
repopilot scan . --max-directory-depth 6
|
|
294
|
+
repopilot scan . --max-file-size 1mb
|
|
295
|
+
repopilot scan . --max-files 1000
|
|
296
|
+
repopilot scan . --exclude generated
|
|
297
|
+
repopilot scan . --include-low-signal
|
|
197
298
|
```
|
|
198
299
|
|
|
300
|
+
`--max-file-size` accepts raw bytes or `kb`, `mb`, and `gb` suffixes. `--exclude` matches an exact path relative to the scan root or a file/directory name; repeat it for multiple paths.
|
|
301
|
+
|
|
302
|
+
JSON output includes scan input accounting fields: `files_discovered` for files found after ignore/exclude filters, `files_count` for analyzed text files, `files_skipped_low_signal` for default low-signal skips, and `binary_files_skipped` for unreadable/binary files.
|
|
303
|
+
|
|
199
304
|
## Baseline Workflow
|
|
200
305
|
|
|
201
306
|
Existing repositories often have findings that cannot all be fixed before adopting a new audit tool. A baseline stores accepted existing findings so future scans can distinguish new findings from existing ones.
|
|
@@ -251,7 +356,7 @@ If your installed RepoPilot version does not support `--output`, redirect stdout
|
|
|
251
356
|
repopilot scan . --format sarif > repopilot.sarif
|
|
252
357
|
```
|
|
253
358
|
|
|
254
|
-
Use JSON when custom scripts need to parse RepoPilot results.
|
|
359
|
+
Use JSON when custom scripts need to parse RepoPilot results. Console, Markdown, and HTML reports include the RepoPilot version, risk summary, top rules, and grouped findings for human review. Use SARIF for CI and code scanning integrations, including GitHub Code Scanning.
|
|
255
360
|
|
|
256
361
|
See [docs/integrations/github-code-scanning.md](docs/integrations/github-code-scanning.md) for a copy-paste GitHub Actions workflow, required permissions, and local validation commands.
|
|
257
362
|
|
|
@@ -272,6 +377,7 @@ Use `--fail-on new-high` to fail CI only when new high or critical findings are
|
|
|
272
377
|
When `--fail-on new-*` is used without `--baseline`, RepoPilot treats all current findings as new. For baseline-based adoption, commit an accepted baseline and scan against it in CI.
|
|
273
378
|
|
|
274
379
|
To upload RepoPilot findings to GitHub Code Scanning, generate SARIF and use `github/codeql-action/upload-sarif`. The workflow must include `security-events: write`.
|
|
380
|
+
The first-party action can also run `command: ai-context`, `command: ai-plan`, or `command: ai-prompt`; those commands emit Markdown and do not produce SARIF. Prefer typed action inputs such as `path`, `config`, `baseline`, `fail-on`, `focus`, `budget`, and `output`; `args` remains available for advanced flags.
|
|
275
381
|
|
|
276
382
|
```yaml
|
|
277
383
|
name: RepoPilot
|
|
@@ -279,12 +385,16 @@ name: RepoPilot
|
|
|
279
385
|
on:
|
|
280
386
|
pull_request:
|
|
281
387
|
|
|
388
|
+
permissions:
|
|
389
|
+
contents: read
|
|
390
|
+
security-events: write
|
|
391
|
+
|
|
282
392
|
jobs:
|
|
283
393
|
repopilot:
|
|
284
394
|
runs-on: ubuntu-latest
|
|
285
395
|
|
|
286
396
|
steps:
|
|
287
|
-
- uses: actions/checkout@
|
|
397
|
+
- uses: actions/checkout@v5
|
|
288
398
|
|
|
289
399
|
- name: Install Rust
|
|
290
400
|
uses: dtolnay/rust-toolchain@stable
|
|
@@ -299,7 +409,7 @@ jobs:
|
|
|
299
409
|
run: repopilot scan . --format sarif --output repopilot.sarif
|
|
300
410
|
|
|
301
411
|
- name: Upload to GitHub Code Scanning
|
|
302
|
-
uses: github/codeql-action/upload-sarif@
|
|
412
|
+
uses: github/codeql-action/upload-sarif@v4
|
|
303
413
|
if: always()
|
|
304
414
|
with:
|
|
305
415
|
sarif_file: repopilot.sarif
|
|
@@ -309,9 +419,6 @@ jobs:
|
|
|
309
419
|
|
|
310
420
|
These are planned ideas, not current features:
|
|
311
421
|
|
|
312
|
-
- Vibe Check command for AI-assisted codebase readiness
|
|
313
|
-
- Hardening Plan output based on existing findings
|
|
314
|
-
- AI-agent prompt/context export
|
|
315
422
|
- Change Risk Map
|
|
316
423
|
- Better architecture drift detection
|
|
317
424
|
- Optional per-platform npm binary packages for faster installs
|
|
@@ -320,12 +427,18 @@ These are planned ideas, not current features:
|
|
|
320
427
|
|
|
321
428
|
| Document | Description |
|
|
322
429
|
|---|---|
|
|
430
|
+
| [docs/install.md](docs/install.md) | Installation options for Cargo, npm, Homebrew, curl, and source builds |
|
|
431
|
+
| [docs/ai-workflows.md](docs/ai-workflows.md) | Claude Code, ChatGPT, Cursor, and AI remediation workflows |
|
|
432
|
+
| [docs/security.md](docs/security.md) | Local-first trust model, installer security, and vulnerability reporting |
|
|
433
|
+
| [docs/configuration.md](docs/configuration.md) | `repopilot.toml`, presets, ignore files, and baseline adoption |
|
|
434
|
+
| [docs/language-support.md](docs/language-support.md) | Supported language/framework tiers, rule families, and limitations |
|
|
323
435
|
| [docs/cli.md](docs/cli.md) | Complete CLI reference — all commands, flags, and exit codes |
|
|
324
436
|
| [docs/commands.md](docs/commands.md) | Task-oriented command guide and common patterns |
|
|
325
437
|
| [docs/rulesets.md](docs/rulesets.md) | Implemented audit rules, categories, and severity levels |
|
|
326
438
|
| [docs/react-native.md](docs/react-native.md) | React Native and Expo detection, findings, and limitations |
|
|
327
439
|
| [docs/integrations/github-code-scanning.md](docs/integrations/github-code-scanning.md) | GitHub Code Scanning SARIF workflow |
|
|
328
440
|
| [docs/release.md](docs/release.md) | Manual release process |
|
|
441
|
+
| [docs/release-checklist-0.9.md](docs/release-checklist-0.9.md) | 0.9.0 release readiness checklist |
|
|
329
442
|
| [docs/distribution.md](docs/distribution.md) | Distribution channels |
|
|
330
443
|
| [docs/github-ruleset.md](docs/github-ruleset.md) | GitHub branch ruleset configuration |
|
|
331
444
|
| [CHANGELOG.md](CHANGELOG.md) | Version history |
|
package/package.json
CHANGED
|
@@ -1,38 +1,41 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
2
|
+
"name": "repopilot",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Local-first CLI for repository audit, architecture risk detection, baseline tracking, and CI-friendly code review.",
|
|
5
|
+
"license": "MIT OR Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/MykytaStel/repopilot.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/MykytaStel/repopilot#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/MykytaStel/repopilot/issues"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"repopilot": "bin/repopilot.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"postinstall": "node scripts/install.js",
|
|
19
|
+
"test": "npm run test:npm",
|
|
20
|
+
"test:npm": "node --test tests/npm_wrapper.test.js",
|
|
21
|
+
"release:check": "bash scripts/verify-release.sh",
|
|
22
|
+
"product:smoke": "bash scripts/smoke-product.sh"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"bin",
|
|
26
|
+
"scripts",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"keywords": [
|
|
31
|
+
"cli",
|
|
32
|
+
"audit",
|
|
33
|
+
"code-review",
|
|
34
|
+
"static-analysis",
|
|
35
|
+
"architecture",
|
|
36
|
+
"react-native"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
}
|
|
38
41
|
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
|
|
6
|
+
BINARY=""
|
|
7
|
+
REPO_PATH="$ROOT_DIR"
|
|
8
|
+
TMP_DIR=""
|
|
9
|
+
TMP_CREATED=0
|
|
10
|
+
KEEP_TMP=0
|
|
11
|
+
RUN_LEGACY=1
|
|
12
|
+
|
|
13
|
+
usage() {
|
|
14
|
+
cat <<'EOF'
|
|
15
|
+
Usage: scripts/smoke-product.sh [OPTIONS]
|
|
16
|
+
|
|
17
|
+
Run product-readiness smoke checks against RepoPilot.
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
--binary PATH Use an already built repopilot binary.
|
|
21
|
+
--repo PATH Repository or project path to smoke test. Defaults to this repo.
|
|
22
|
+
--tmp-dir PATH Directory for generated smoke artifacts. Defaults to mktemp.
|
|
23
|
+
--keep-tmp Keep generated smoke artifacts when using a temporary directory.
|
|
24
|
+
--skip-legacy Skip hidden 0.x compatibility command checks.
|
|
25
|
+
-h, --help Show this help message.
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
scripts/smoke-product.sh
|
|
29
|
+
scripts/smoke-product.sh --binary ./target/release/repopilot
|
|
30
|
+
scripts/smoke-product.sh --repo /path/to/project --keep-tmp
|
|
31
|
+
EOF
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
while [[ $# -gt 0 ]]; do
|
|
35
|
+
case "$1" in
|
|
36
|
+
--binary)
|
|
37
|
+
BINARY="${2:-}"
|
|
38
|
+
shift 2
|
|
39
|
+
;;
|
|
40
|
+
--repo)
|
|
41
|
+
REPO_PATH="${2:-}"
|
|
42
|
+
shift 2
|
|
43
|
+
;;
|
|
44
|
+
--tmp-dir)
|
|
45
|
+
TMP_DIR="${2:-}"
|
|
46
|
+
shift 2
|
|
47
|
+
;;
|
|
48
|
+
--keep-tmp)
|
|
49
|
+
KEEP_TMP=1
|
|
50
|
+
shift
|
|
51
|
+
;;
|
|
52
|
+
--skip-legacy)
|
|
53
|
+
RUN_LEGACY=0
|
|
54
|
+
shift
|
|
55
|
+
;;
|
|
56
|
+
-h|--help)
|
|
57
|
+
usage
|
|
58
|
+
exit 0
|
|
59
|
+
;;
|
|
60
|
+
*)
|
|
61
|
+
echo "Unknown argument: $1" >&2
|
|
62
|
+
usage >&2
|
|
63
|
+
exit 2
|
|
64
|
+
;;
|
|
65
|
+
esac
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
if [[ -z "$REPO_PATH" ]]; then
|
|
69
|
+
echo "--repo cannot be empty" >&2
|
|
70
|
+
exit 2
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
REPO_PATH="$(cd "$REPO_PATH" && pwd)"
|
|
74
|
+
|
|
75
|
+
if [[ -z "$BINARY" ]]; then
|
|
76
|
+
if [[ ! -x "$ROOT_DIR/target/debug/repopilot" ]]; then
|
|
77
|
+
echo "==> Building debug binary for product smoke checks" >&2
|
|
78
|
+
cargo build --manifest-path "$ROOT_DIR/Cargo.toml"
|
|
79
|
+
fi
|
|
80
|
+
BINARY="$ROOT_DIR/target/debug/repopilot"
|
|
81
|
+
else
|
|
82
|
+
case "$BINARY" in
|
|
83
|
+
/*) ;;
|
|
84
|
+
*)
|
|
85
|
+
BINARY="$(cd "$(dirname "$BINARY")" && pwd)/$(basename "$BINARY")"
|
|
86
|
+
;;
|
|
87
|
+
esac
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
if [[ ! -x "$BINARY" ]]; then
|
|
91
|
+
echo "RepoPilot binary is not executable: $BINARY" >&2
|
|
92
|
+
exit 3
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
if [[ -z "$TMP_DIR" ]]; then
|
|
96
|
+
TMP_DIR="$(mktemp -d)"
|
|
97
|
+
TMP_CREATED=1
|
|
98
|
+
else
|
|
99
|
+
rm -rf "$TMP_DIR"
|
|
100
|
+
mkdir -p "$TMP_DIR"
|
|
101
|
+
TMP_DIR="$(cd "$TMP_DIR" && pwd)"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
cleanup() {
|
|
105
|
+
if [[ "$TMP_CREATED" -eq 1 && "$KEEP_TMP" -eq 0 ]]; then
|
|
106
|
+
rm -rf "$TMP_DIR"
|
|
107
|
+
fi
|
|
108
|
+
}
|
|
109
|
+
trap cleanup EXIT
|
|
110
|
+
|
|
111
|
+
run_repopilot() {
|
|
112
|
+
echo "==> repopilot $*" >&2
|
|
113
|
+
(
|
|
114
|
+
cd "$REPO_PATH"
|
|
115
|
+
"$BINARY" "$@"
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
assert_non_empty() {
|
|
120
|
+
local file="$1"
|
|
121
|
+
if [[ ! -s "$file" ]]; then
|
|
122
|
+
echo "Expected non-empty file: $file" >&2
|
|
123
|
+
exit 3
|
|
124
|
+
fi
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
assert_contains() {
|
|
128
|
+
local file="$1"
|
|
129
|
+
local expected="$2"
|
|
130
|
+
|
|
131
|
+
if ! grep -Fq "$expected" "$file"; then
|
|
132
|
+
echo "Expected '$file' to contain: $expected" >&2
|
|
133
|
+
echo "---- file content ----" >&2
|
|
134
|
+
cat "$file" >&2 || true
|
|
135
|
+
echo "----------------------" >&2
|
|
136
|
+
exit 3
|
|
137
|
+
fi
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
validate_json_if_possible() {
|
|
141
|
+
local file="$1"
|
|
142
|
+
|
|
143
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
144
|
+
python3 -m json.tool "$file" >/dev/null
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
find_explain_file() {
|
|
149
|
+
local preferred="$REPO_PATH/src/main.rs"
|
|
150
|
+
|
|
151
|
+
if [[ -f "$preferred" ]]; then
|
|
152
|
+
printf '%s\n' "$preferred"
|
|
153
|
+
return 0
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
local discovered=""
|
|
157
|
+
while IFS= read -r candidate; do
|
|
158
|
+
discovered="$candidate"
|
|
159
|
+
break
|
|
160
|
+
done < <(
|
|
161
|
+
find "$REPO_PATH" \
|
|
162
|
+
-path "$REPO_PATH/.git" -prune -o \
|
|
163
|
+
-path "$REPO_PATH/target" -prune -o \
|
|
164
|
+
-path "$REPO_PATH/node_modules" -prune -o \
|
|
165
|
+
-type f \( \
|
|
166
|
+
-name '*.rs' -o \
|
|
167
|
+
-name '*.ts' -o \
|
|
168
|
+
-name '*.tsx' -o \
|
|
169
|
+
-name '*.js' -o \
|
|
170
|
+
-name '*.jsx' -o \
|
|
171
|
+
-name '*.py' -o \
|
|
172
|
+
-name '*.go' \
|
|
173
|
+
\) \
|
|
174
|
+
-print
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
if [[ -n "$discovered" && -f "$discovered" ]]; then
|
|
178
|
+
printf '%s\n' "$discovered"
|
|
179
|
+
return 0
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
printf '%s\n' "$REPO_PATH/Cargo.toml"
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
EXPLAIN_FILE="$(find_explain_file)"
|
|
186
|
+
|
|
187
|
+
echo "==> RepoPilot product smoke suite"
|
|
188
|
+
echo "Binary: $BINARY"
|
|
189
|
+
echo "Repo: $REPO_PATH"
|
|
190
|
+
echo "Tmp: $TMP_DIR"
|
|
191
|
+
echo
|
|
192
|
+
|
|
193
|
+
run_repopilot --version > "$TMP_DIR/version.txt"
|
|
194
|
+
assert_non_empty "$TMP_DIR/version.txt"
|
|
195
|
+
|
|
196
|
+
run_repopilot --help > "$TMP_DIR/help.txt"
|
|
197
|
+
assert_non_empty "$TMP_DIR/help.txt"
|
|
198
|
+
assert_contains "$TMP_DIR/help.txt" "scan"
|
|
199
|
+
assert_contains "$TMP_DIR/help.txt" "review"
|
|
200
|
+
assert_contains "$TMP_DIR/help.txt" "ai"
|
|
201
|
+
assert_contains "$TMP_DIR/help.txt" "inspect"
|
|
202
|
+
|
|
203
|
+
run_repopilot init --force --path "$TMP_DIR/repopilot.toml"
|
|
204
|
+
assert_non_empty "$TMP_DIR/repopilot.toml"
|
|
205
|
+
|
|
206
|
+
run_repopilot doctor . --format markdown --output "$TMP_DIR/doctor.md"
|
|
207
|
+
assert_non_empty "$TMP_DIR/doctor.md"
|
|
208
|
+
|
|
209
|
+
run_repopilot scan . --format json --output "$TMP_DIR/scan.json"
|
|
210
|
+
assert_non_empty "$TMP_DIR/scan.json"
|
|
211
|
+
validate_json_if_possible "$TMP_DIR/scan.json"
|
|
212
|
+
|
|
213
|
+
run_repopilot scan . --format markdown --output "$TMP_DIR/scan.md"
|
|
214
|
+
assert_non_empty "$TMP_DIR/scan.md"
|
|
215
|
+
|
|
216
|
+
if git -C "$REPO_PATH" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
217
|
+
run_repopilot review . --format markdown --output "$TMP_DIR/review.md"
|
|
218
|
+
assert_non_empty "$TMP_DIR/review.md"
|
|
219
|
+
else
|
|
220
|
+
echo "==> Skipping review smoke check because repo path is not inside a Git worktree" >&2
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
run_repopilot ai context . --focus security --budget 2k --output "$TMP_DIR/ai-context.md"
|
|
224
|
+
assert_non_empty "$TMP_DIR/ai-context.md"
|
|
225
|
+
|
|
226
|
+
run_repopilot ai plan . --focus all --budget 2k --output "$TMP_DIR/ai-plan.md"
|
|
227
|
+
assert_non_empty "$TMP_DIR/ai-plan.md"
|
|
228
|
+
|
|
229
|
+
run_repopilot ai prompt . --focus quality --budget 2k --output "$TMP_DIR/ai-prompt.md"
|
|
230
|
+
assert_non_empty "$TMP_DIR/ai-prompt.md"
|
|
231
|
+
|
|
232
|
+
run_repopilot inspect knowledge --format json --output "$TMP_DIR/inspect-knowledge.json"
|
|
233
|
+
assert_non_empty "$TMP_DIR/inspect-knowledge.json"
|
|
234
|
+
validate_json_if_possible "$TMP_DIR/inspect-knowledge.json"
|
|
235
|
+
|
|
236
|
+
run_repopilot inspect knowledge --section rules --format markdown --output "$TMP_DIR/inspect-knowledge-rules.md"
|
|
237
|
+
assert_non_empty "$TMP_DIR/inspect-knowledge-rules.md"
|
|
238
|
+
|
|
239
|
+
run_repopilot inspect explain "$EXPLAIN_FILE" --format json --output "$TMP_DIR/inspect-explain.json"
|
|
240
|
+
assert_non_empty "$TMP_DIR/inspect-explain.json"
|
|
241
|
+
validate_json_if_possible "$TMP_DIR/inspect-explain.json"
|
|
242
|
+
|
|
243
|
+
if [[ "$RUN_LEGACY" -eq 1 ]]; then
|
|
244
|
+
run_repopilot vibe . --focus security --budget 2k --output "$TMP_DIR/legacy-vibe.md"
|
|
245
|
+
assert_non_empty "$TMP_DIR/legacy-vibe.md"
|
|
246
|
+
|
|
247
|
+
run_repopilot harden . --focus all --budget 2k --output "$TMP_DIR/legacy-harden.md"
|
|
248
|
+
assert_non_empty "$TMP_DIR/legacy-harden.md"
|
|
249
|
+
|
|
250
|
+
run_repopilot prompt . --focus quality --budget 2k --output "$TMP_DIR/legacy-prompt.md"
|
|
251
|
+
assert_non_empty "$TMP_DIR/legacy-prompt.md"
|
|
252
|
+
|
|
253
|
+
run_repopilot knowledge --format json --output "$TMP_DIR/legacy-knowledge.json"
|
|
254
|
+
assert_non_empty "$TMP_DIR/legacy-knowledge.json"
|
|
255
|
+
validate_json_if_possible "$TMP_DIR/legacy-knowledge.json"
|
|
256
|
+
|
|
257
|
+
run_repopilot explain "$EXPLAIN_FILE" --format json --output "$TMP_DIR/legacy-explain.json"
|
|
258
|
+
assert_non_empty "$TMP_DIR/legacy-explain.json"
|
|
259
|
+
validate_json_if_possible "$TMP_DIR/legacy-explain.json"
|
|
260
|
+
fi
|
|
261
|
+
|
|
262
|
+
echo
|
|
263
|
+
echo "==> Product smoke suite passed"
|
|
264
|
+
echo "Artifacts: $TMP_DIR"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
cd "$ROOT_DIR"
|
|
6
|
+
|
|
7
|
+
echo "==> RepoPilot release verification"
|
|
8
|
+
|
|
9
|
+
echo "==> Rust formatting"
|
|
10
|
+
cargo fmt --all -- --check
|
|
11
|
+
|
|
12
|
+
echo "==> Rust clippy"
|
|
13
|
+
cargo clippy --all-targets --all-features -- -D warnings
|
|
14
|
+
|
|
15
|
+
echo "==> Rust tests"
|
|
16
|
+
cargo test --all
|
|
17
|
+
|
|
18
|
+
echo "==> Rust dependency security audit"
|
|
19
|
+
cargo audit
|
|
20
|
+
|
|
21
|
+
echo "==> Cargo dependency policy"
|
|
22
|
+
cargo deny check advisories licenses
|
|
23
|
+
|
|
24
|
+
echo "==> Shell script syntax"
|
|
25
|
+
scripts=()
|
|
26
|
+
if [[ -f install.sh ]]; then
|
|
27
|
+
scripts+=(install.sh)
|
|
28
|
+
fi
|
|
29
|
+
if [[ -d scripts ]]; then
|
|
30
|
+
while IFS= read -r -d '' script; do
|
|
31
|
+
scripts+=("$script")
|
|
32
|
+
done < <(find scripts -maxdepth 1 -type f -name '*.sh' -print0)
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if ((${#scripts[@]} > 0)); then
|
|
36
|
+
for script in "${scripts[@]}"; do
|
|
37
|
+
bash -n "$script"
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
echo "==> ShellCheck"
|
|
41
|
+
shellcheck "${scripts[@]}"
|
|
42
|
+
else
|
|
43
|
+
echo "==> No shell scripts found"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
echo "==> GitHub Actions validation"
|
|
47
|
+
workflows=()
|
|
48
|
+
if [[ -d .github/workflows ]]; then
|
|
49
|
+
while IFS= read -r -d '' workflow; do
|
|
50
|
+
workflows+=("$workflow")
|
|
51
|
+
done < <(find .github/workflows -maxdepth 1 -type f \( -name '*.yml' -o -name '*.yaml' \) -print0)
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if ((${#workflows[@]} > 0)); then
|
|
55
|
+
actionlint "${workflows[@]}"
|
|
56
|
+
else
|
|
57
|
+
echo "==> No GitHub Actions workflows found"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo "==> CLI release smoke tests"
|
|
61
|
+
cargo test --test cli_release_smoke
|
|
62
|
+
|
|
63
|
+
echo "==> Cargo package contents"
|
|
64
|
+
cargo package --list
|
|
65
|
+
|
|
66
|
+
echo "==> Cargo publish dry-run"
|
|
67
|
+
cargo publish --dry-run
|
|
68
|
+
|
|
69
|
+
echo "==> npm wrapper tests"
|
|
70
|
+
npm run test:npm
|
|
71
|
+
|
|
72
|
+
echo "==> npm package dry-run"
|
|
73
|
+
npm pack --dry-run
|
|
74
|
+
|
|
75
|
+
echo "==> Build release binary"
|
|
76
|
+
cargo build --release
|
|
77
|
+
|
|
78
|
+
echo "==> Product readiness smoke suite"
|
|
79
|
+
./scripts/smoke-product.sh \
|
|
80
|
+
--binary ./target/release/repopilot \
|
|
81
|
+
--repo . \
|
|
82
|
+
--tmp-dir /tmp/repopilot-release-smoke
|
|
83
|
+
|
|
84
|
+
echo "==> Release verification passed"
|