patchpilots 0.5.1 → 0.5.3
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 +51 -4
- package/action/format-comment.cjs +243 -0
- package/action/run.sh +76 -0
- package/action.yml +61 -0
- package/dist/src/utils/logger.js +5 -5
- package/dist/src/utils/logger.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -29,18 +29,28 @@ A team of AI agents that reviews and improves your code automatically.
|
|
|
29
29
|
|
|
30
30
|
Built for solo developers and hobby projects — when you don't have a team to review your PRs, PatchPilots is your crew.
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## Use it 3 ways
|
|
33
33
|
|
|
34
|
+
### `npx` — no install, one-off
|
|
34
35
|
```bash
|
|
35
36
|
npx patchpilots audit ./src
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
### Global install — your machine, any project
|
|
40
40
|
```bash
|
|
41
41
|
npm install -g patchpilots
|
|
42
|
+
patchpilots audit ./src
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### GitHub Action — automatic on every PR
|
|
46
|
+
```yaml
|
|
47
|
+
- uses: alavesa/patchpilots@main
|
|
48
|
+
with:
|
|
49
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
42
50
|
```
|
|
43
51
|
|
|
52
|
+
All three use the same package. The CLI runs locally, the Action runs on GitHub's servers. Same agents, same output.
|
|
53
|
+
|
|
44
54
|
## The Killer Feature
|
|
45
55
|
|
|
46
56
|
**`patchpilots audit`** — run all 7 agents in one command. No other tool does this.
|
|
@@ -262,6 +272,43 @@ Config resolution order: CLI flags > project `.patchpilots.json` > global `~/.pa
|
|
|
262
272
|
|
|
263
273
|
TypeScript, JavaScript, JSX/TSX, Python, Go, Rust, Java, Ruby, PHP, C/C++, C#, Swift, Kotlin, HTML, CSS, SCSS, Vue, Svelte.
|
|
264
274
|
|
|
275
|
+
## GitHub Action
|
|
276
|
+
|
|
277
|
+
Auto-review every PR with one workflow file:
|
|
278
|
+
|
|
279
|
+
```yaml
|
|
280
|
+
# .github/workflows/patchpilots.yml
|
|
281
|
+
name: PatchPilots Review
|
|
282
|
+
on:
|
|
283
|
+
pull_request:
|
|
284
|
+
types: [opened, synchronize]
|
|
285
|
+
|
|
286
|
+
permissions:
|
|
287
|
+
contents: read
|
|
288
|
+
pull-requests: write
|
|
289
|
+
|
|
290
|
+
jobs:
|
|
291
|
+
review:
|
|
292
|
+
runs-on: ubuntu-latest
|
|
293
|
+
steps:
|
|
294
|
+
- uses: actions/checkout@v4
|
|
295
|
+
- uses: alavesa/patchpilots@v1
|
|
296
|
+
with:
|
|
297
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
298
|
+
path: './src'
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The action posts findings as a PR comment (updated on each push, no spam). Critical findings fail the check by default.
|
|
302
|
+
|
|
303
|
+
| Input | Default | Description |
|
|
304
|
+
|-------|---------|-------------|
|
|
305
|
+
| `anthropic_api_key` | (required) | Your Anthropic API key |
|
|
306
|
+
| `path` | `./src` | Path to review |
|
|
307
|
+
| `model` | `claude-sonnet-4-6` | Claude model to use |
|
|
308
|
+
| `skip` | | Agents to skip (e.g. `plan,test,docs`) |
|
|
309
|
+
| `severity` | `info` | Minimum severity to report |
|
|
310
|
+
| `fail_on_critical` | `true` | Fail the check on critical findings |
|
|
311
|
+
|
|
265
312
|
## Powered by Claude API
|
|
266
313
|
|
|
267
314
|
- **Structured outputs** — guaranteed schema compliance via JSON schema enforcement
|
|
@@ -300,7 +347,7 @@ Adding a new agent is one file + three methods.
|
|
|
300
347
|
- [x] 18 file types supported
|
|
301
348
|
|
|
302
349
|
### Next up
|
|
303
|
-
- [
|
|
350
|
+
- [x] **GitHub Action** — auto-review PRs and post findings as comments
|
|
304
351
|
- [ ] **Parallel file review** — review in batches instead of one giant prompt
|
|
305
352
|
- [ ] **Smart model routing** — Haiku for Docs/Tester, Sonnet for Reviewer/Coder
|
|
306
353
|
- [x] **Custom agents** — define your own agents via `.patchpilots.json`
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts PatchPilots AuditResult JSON into a GitHub markdown comment.
|
|
5
|
+
* Zero dependencies — runs on any Node.js 18+.
|
|
6
|
+
*
|
|
7
|
+
* Usage: node format-comment.js /path/to/result.json
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
|
|
13
|
+
const MAX_FINDINGS = 50;
|
|
14
|
+
const MAX_PATCHES = 30;
|
|
15
|
+
|
|
16
|
+
const SEVERITY_EMOJI = {
|
|
17
|
+
critical: ":red_circle:",
|
|
18
|
+
high: ":orange_circle:",
|
|
19
|
+
warning: ":yellow_circle:",
|
|
20
|
+
medium: ":yellow_circle:",
|
|
21
|
+
info: ":blue_circle:",
|
|
22
|
+
low: ":blue_circle:",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function severityEmoji(severity) {
|
|
26
|
+
return SEVERITY_EMOJI[severity] || ":white_circle:";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function escapeMarkdown(text) {
|
|
30
|
+
if (!text) return "";
|
|
31
|
+
return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function truncate(text, max = 120) {
|
|
35
|
+
if (!text) return "";
|
|
36
|
+
const clean = text.replace(/\n/g, " ");
|
|
37
|
+
return clean.length > max ? clean.slice(0, max) + "..." : clean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- Sections ---
|
|
41
|
+
|
|
42
|
+
function formatHeader(result) {
|
|
43
|
+
const lines = [];
|
|
44
|
+
lines.push("<!-- patchpilots-report -->");
|
|
45
|
+
lines.push("# PatchPilots Audit Report");
|
|
46
|
+
lines.push("");
|
|
47
|
+
lines.push(
|
|
48
|
+
`**Risk Score:** ${result.riskScore?.toUpperCase() || "N/A"} | ` +
|
|
49
|
+
`**Findings:** ${result.totalFindings || 0} | ` +
|
|
50
|
+
`**Patches:** ${result.totalPatches || 0}`
|
|
51
|
+
);
|
|
52
|
+
lines.push("");
|
|
53
|
+
return lines.join("\n");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function formatPlan(plan) {
|
|
57
|
+
if (!plan || !plan.tasks || plan.tasks.length === 0) return "";
|
|
58
|
+
const lines = [];
|
|
59
|
+
lines.push("## :brain: Plan");
|
|
60
|
+
lines.push("");
|
|
61
|
+
if (plan.goal) {
|
|
62
|
+
lines.push(`> ${plan.goal}`);
|
|
63
|
+
lines.push("");
|
|
64
|
+
}
|
|
65
|
+
for (const task of plan.tasks) {
|
|
66
|
+
const complexity =
|
|
67
|
+
task.estimatedComplexity === "complex"
|
|
68
|
+
? ":red_circle:"
|
|
69
|
+
: task.estimatedComplexity === "moderate"
|
|
70
|
+
? ":yellow_circle:"
|
|
71
|
+
: ":green_circle:";
|
|
72
|
+
lines.push(
|
|
73
|
+
`${task.id}. ${complexity} **${task.title}** \\[${task.priority}\\]`
|
|
74
|
+
);
|
|
75
|
+
if (task.description) lines.push(` ${truncate(task.description, 200)}`);
|
|
76
|
+
}
|
|
77
|
+
lines.push("");
|
|
78
|
+
return lines.join("\n");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function formatReview(review) {
|
|
82
|
+
if (!review || !review.findings || review.findings.length === 0) {
|
|
83
|
+
return "## :mag: Code Review\n\n:white_check_mark: No issues found.\n\n";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const lines = [];
|
|
87
|
+
lines.push(`## :mag: Code Review (${review.findings.length} findings)`);
|
|
88
|
+
lines.push("");
|
|
89
|
+
lines.push("| Severity | File | Finding | Suggestion |");
|
|
90
|
+
lines.push("|----------|------|---------|------------|");
|
|
91
|
+
|
|
92
|
+
const shown = review.findings.slice(0, MAX_FINDINGS);
|
|
93
|
+
for (const f of shown) {
|
|
94
|
+
const loc = f.line ? `\`${f.file}:${f.line}\`` : `\`${f.file}\``;
|
|
95
|
+
lines.push(
|
|
96
|
+
`| ${severityEmoji(f.severity)} ${f.severity} | ${loc} | ${escapeMarkdown(f.title)} | ${escapeMarkdown(truncate(f.suggestion || f.description, 100))} |`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (review.findings.length > MAX_FINDINGS) {
|
|
101
|
+
lines.push("");
|
|
102
|
+
lines.push(
|
|
103
|
+
`*... and ${review.findings.length - MAX_FINDINGS} more findings*`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
lines.push("");
|
|
108
|
+
return lines.join("\n");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function formatSecurity(security) {
|
|
112
|
+
if (!security || !security.findings || security.findings.length === 0) {
|
|
113
|
+
return "## :lock: Security Audit\n\n:white_check_mark: No security issues found.\n\n";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const lines = [];
|
|
117
|
+
lines.push(
|
|
118
|
+
`## :lock: Security Audit (${security.findings.length} findings)`
|
|
119
|
+
);
|
|
120
|
+
lines.push("");
|
|
121
|
+
lines.push("| Severity | File | Category | Finding | Remediation |");
|
|
122
|
+
lines.push("|----------|------|----------|---------|-------------|");
|
|
123
|
+
|
|
124
|
+
const shown = security.findings.slice(0, MAX_FINDINGS);
|
|
125
|
+
for (const f of shown) {
|
|
126
|
+
const loc = f.line ? `\`${f.file}:${f.line}\`` : `\`${f.file}\``;
|
|
127
|
+
const cat = f.cwe ? `${f.category} (${f.cwe})` : f.category;
|
|
128
|
+
lines.push(
|
|
129
|
+
`| ${severityEmoji(f.severity)} ${f.severity} | ${loc} | ${escapeMarkdown(cat)} | ${escapeMarkdown(f.title)} | ${escapeMarkdown(truncate(f.remediation, 100))} |`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (security.findings.length > MAX_FINDINGS) {
|
|
134
|
+
lines.push("");
|
|
135
|
+
lines.push(
|
|
136
|
+
`*... and ${security.findings.length - MAX_FINDINGS} more findings*`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
lines.push("");
|
|
141
|
+
return lines.join("\n");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function formatPatches(coder) {
|
|
145
|
+
if (
|
|
146
|
+
!coder ||
|
|
147
|
+
!coder.improvedFiles ||
|
|
148
|
+
coder.improvedFiles.length === 0
|
|
149
|
+
) {
|
|
150
|
+
return "";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const lines = [];
|
|
154
|
+
let totalPatches = 0;
|
|
155
|
+
for (const f of coder.improvedFiles) totalPatches += f.patches.length;
|
|
156
|
+
|
|
157
|
+
lines.push(`## :sparkles: Suggested Improvements (${totalPatches} patches)`);
|
|
158
|
+
lines.push("");
|
|
159
|
+
|
|
160
|
+
let patchCount = 0;
|
|
161
|
+
for (const file of coder.improvedFiles) {
|
|
162
|
+
if (patchCount >= MAX_PATCHES) {
|
|
163
|
+
lines.push(
|
|
164
|
+
`*... and more patches across remaining files*`
|
|
165
|
+
);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
lines.push(
|
|
170
|
+
`<details>\n<summary><strong>${file.path}</strong> (${file.patches.length} patches)</summary>\n`
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
for (const patch of file.patches) {
|
|
174
|
+
if (patchCount >= MAX_PATCHES) break;
|
|
175
|
+
lines.push(`**${escapeMarkdown(patch.description)}**`);
|
|
176
|
+
lines.push("```diff");
|
|
177
|
+
for (const line of patch.find.split("\n")) {
|
|
178
|
+
lines.push(`- ${line}`);
|
|
179
|
+
}
|
|
180
|
+
for (const line of patch.replace.split("\n")) {
|
|
181
|
+
lines.push(`+ ${line}`);
|
|
182
|
+
}
|
|
183
|
+
lines.push("```");
|
|
184
|
+
lines.push("");
|
|
185
|
+
patchCount++;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
lines.push("</details>\n");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
lines.push("");
|
|
192
|
+
return lines.join("\n");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function formatTests(tests) {
|
|
196
|
+
if (!tests || !tests.testFiles || tests.testFiles.length === 0) return "";
|
|
197
|
+
const totalTests = tests.testFiles.reduce((s, f) => s + f.testCount, 0);
|
|
198
|
+
return `## :test_tube: Tests\n\n${totalTests} tests generated across ${tests.testFiles.length} file(s).\n\n`;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function formatDocs(docs) {
|
|
202
|
+
if (!docs || !docs.docs || docs.docs.length === 0) return "";
|
|
203
|
+
return `## :memo: Documentation\n\n${docs.docs.length} file(s) documented.\n\n`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function formatFooter(result) {
|
|
207
|
+
const lines = [];
|
|
208
|
+
lines.push("---");
|
|
209
|
+
lines.push(
|
|
210
|
+
`<sub>Generated by <a href="https://github.com/alavesa/patchpilots">PatchPilots</a> ` +
|
|
211
|
+
`| ${result.totalFindings || 0} findings | ${result.totalPatches || 0} patches | risk: ${result.riskScore || "none"}</sub>`
|
|
212
|
+
);
|
|
213
|
+
lines.push("");
|
|
214
|
+
lines.push(
|
|
215
|
+
`<sub>Add <a href="https://github.com/alavesa/patchpilots"><img src="https://img.shields.io/badge/reviewed%20by-PatchPilots-blue" alt="Reviewed by PatchPilots" /></a> to your README</sub>`
|
|
216
|
+
);
|
|
217
|
+
return lines.join("\n");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// --- Main ---
|
|
221
|
+
|
|
222
|
+
function formatComment(result) {
|
|
223
|
+
return [
|
|
224
|
+
formatHeader(result),
|
|
225
|
+
formatPlan(result.plan),
|
|
226
|
+
formatReview(result.review),
|
|
227
|
+
formatSecurity(result.security),
|
|
228
|
+
formatPatches(result.coder),
|
|
229
|
+
formatTests(result.tests),
|
|
230
|
+
formatDocs(result.docs),
|
|
231
|
+
formatFooter(result),
|
|
232
|
+
].join("");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const filePath = process.argv[2];
|
|
236
|
+
if (!filePath) {
|
|
237
|
+
console.error("Usage: node format-comment.js <result.json>");
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const raw = fs.readFileSync(path.resolve(filePath), "utf-8");
|
|
242
|
+
const result = JSON.parse(raw);
|
|
243
|
+
process.stdout.write(formatComment(result));
|
package/action/run.sh
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Build CLI flags
|
|
5
|
+
FLAGS="--json --severity ${INPUT_SEVERITY}"
|
|
6
|
+
if [ -n "${INPUT_MODEL}" ]; then FLAGS="${FLAGS} --model ${INPUT_MODEL}"; fi
|
|
7
|
+
if [ -n "${INPUT_SKIP}" ]; then FLAGS="${FLAGS} --skip ${INPUT_SKIP}"; fi
|
|
8
|
+
|
|
9
|
+
echo "::group::Running PatchPilots audit"
|
|
10
|
+
echo "Path: ${INPUT_PATH}"
|
|
11
|
+
echo "Model: ${INPUT_MODEL}"
|
|
12
|
+
echo "Severity: ${INPUT_SEVERITY}"
|
|
13
|
+
echo "Skip: ${INPUT_SKIP:-none}"
|
|
14
|
+
|
|
15
|
+
# Run patchpilots audit — JSON goes to stdout, logs to stderr
|
|
16
|
+
# shellcheck disable=SC2086
|
|
17
|
+
RESULT=$(patchpilots audit "${INPUT_PATH}" ${FLAGS} 2>/dev/null) || true
|
|
18
|
+
|
|
19
|
+
echo "::endgroup::"
|
|
20
|
+
|
|
21
|
+
# If no output, warn and exit
|
|
22
|
+
if [ -z "${RESULT}" ] || ! echo "${RESULT}" | jq empty 2>/dev/null; then
|
|
23
|
+
echo "::warning::PatchPilots produced no valid JSON output"
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Save raw JSON
|
|
28
|
+
echo "${RESULT}" > /tmp/patchpilots-result.json
|
|
29
|
+
|
|
30
|
+
# Format as markdown comment
|
|
31
|
+
COMMENT=$(node "${GITHUB_ACTION_PATH}/action/format-comment.cjs" /tmp/patchpilots-result.json)
|
|
32
|
+
|
|
33
|
+
# Post or update PR comment
|
|
34
|
+
PR_NUMBER=$(jq -r '.pull_request.number // empty' "${GITHUB_EVENT_PATH}" 2>/dev/null || echo "")
|
|
35
|
+
|
|
36
|
+
if [ -n "${PR_NUMBER}" ]; then
|
|
37
|
+
# Look for existing PatchPilots comment to update (avoid spam)
|
|
38
|
+
EXISTING=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
|
|
39
|
+
--jq '.[] | select(.body | startswith("<!-- patchpilots-report -->")) | .id' \
|
|
40
|
+
| head -1 || echo "")
|
|
41
|
+
|
|
42
|
+
if [ -n "${EXISTING}" ]; then
|
|
43
|
+
echo "Updating existing PatchPilots comment..."
|
|
44
|
+
gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${EXISTING}" \
|
|
45
|
+
-X PATCH -f body="${COMMENT}"
|
|
46
|
+
else
|
|
47
|
+
echo "Posting PatchPilots comment..."
|
|
48
|
+
gh pr comment "${PR_NUMBER}" --body "${COMMENT}"
|
|
49
|
+
fi
|
|
50
|
+
else
|
|
51
|
+
echo "::warning::Not running in a PR context — printing results to log"
|
|
52
|
+
echo "${COMMENT}"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Set outputs
|
|
56
|
+
TOTAL_FINDINGS=$(echo "${RESULT}" | jq -r '.totalFindings // 0')
|
|
57
|
+
TOTAL_PATCHES=$(echo "${RESULT}" | jq -r '.totalPatches // 0')
|
|
58
|
+
RISK_SCORE=$(echo "${RESULT}" | jq -r '.riskScore // "none"')
|
|
59
|
+
|
|
60
|
+
echo "total_findings=${TOTAL_FINDINGS}" >> "${GITHUB_OUTPUT}"
|
|
61
|
+
echo "total_patches=${TOTAL_PATCHES}" >> "${GITHUB_OUTPUT}"
|
|
62
|
+
echo "risk_score=${RISK_SCORE}" >> "${GITHUB_OUTPUT}"
|
|
63
|
+
|
|
64
|
+
# Fail on critical findings if configured
|
|
65
|
+
if [ "${INPUT_FAIL_ON_CRITICAL}" = "true" ]; then
|
|
66
|
+
REVIEW_CRITICAL=$(echo "${RESULT}" | jq '[(.review.findings // [])[] | select(.severity == "critical")] | length')
|
|
67
|
+
SECURITY_CRITICAL=$(echo "${RESULT}" | jq '[(.security.findings // [])[] | select(.severity == "critical")] | length')
|
|
68
|
+
TOTAL_CRITICAL=$((REVIEW_CRITICAL + SECURITY_CRITICAL))
|
|
69
|
+
|
|
70
|
+
if [ "${TOTAL_CRITICAL}" -gt 0 ]; then
|
|
71
|
+
echo "::error::PatchPilots found ${TOTAL_CRITICAL} critical finding(s)"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
echo "PatchPilots audit complete: ${TOTAL_FINDINGS} findings, ${TOTAL_PATCHES} patches, risk=${RISK_SCORE}"
|
package/action.yml
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: 'PatchPilots Code Review'
|
|
2
|
+
description: 'AI-powered code review with 7 specialized agents — review, security, improve, test, docs in one command'
|
|
3
|
+
author: 'Piia Alavesa'
|
|
4
|
+
|
|
5
|
+
branding:
|
|
6
|
+
icon: 'shield'
|
|
7
|
+
color: 'blue'
|
|
8
|
+
|
|
9
|
+
inputs:
|
|
10
|
+
anthropic_api_key:
|
|
11
|
+
description: 'Anthropic API key'
|
|
12
|
+
required: true
|
|
13
|
+
path:
|
|
14
|
+
description: 'Path to review (relative to repo root)'
|
|
15
|
+
required: false
|
|
16
|
+
default: './src'
|
|
17
|
+
model:
|
|
18
|
+
description: 'Claude model to use'
|
|
19
|
+
required: false
|
|
20
|
+
default: 'claude-sonnet-4-6'
|
|
21
|
+
skip:
|
|
22
|
+
description: 'Agents to skip (comma-separated: plan,test,docs)'
|
|
23
|
+
required: false
|
|
24
|
+
default: ''
|
|
25
|
+
severity:
|
|
26
|
+
description: 'Minimum severity to report (critical, warning, info)'
|
|
27
|
+
required: false
|
|
28
|
+
default: 'info'
|
|
29
|
+
fail_on_critical:
|
|
30
|
+
description: 'Fail the check if critical findings exist'
|
|
31
|
+
required: false
|
|
32
|
+
default: 'true'
|
|
33
|
+
|
|
34
|
+
outputs:
|
|
35
|
+
total_findings:
|
|
36
|
+
description: 'Total number of findings'
|
|
37
|
+
total_patches:
|
|
38
|
+
description: 'Total number of suggested patches'
|
|
39
|
+
risk_score:
|
|
40
|
+
description: 'Overall risk score (critical, high, medium, low, none)'
|
|
41
|
+
|
|
42
|
+
runs:
|
|
43
|
+
using: 'composite'
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/setup-node@v4
|
|
46
|
+
with:
|
|
47
|
+
node-version: '20'
|
|
48
|
+
- name: Install PatchPilots
|
|
49
|
+
run: npm install -g patchpilots
|
|
50
|
+
shell: bash
|
|
51
|
+
- name: Run audit and post results
|
|
52
|
+
run: bash ${{ github.action_path }}/action/run.sh
|
|
53
|
+
shell: bash
|
|
54
|
+
env:
|
|
55
|
+
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
|
56
|
+
INPUT_PATH: ${{ inputs.path }}
|
|
57
|
+
INPUT_MODEL: ${{ inputs.model }}
|
|
58
|
+
INPUT_SKIP: ${{ inputs.skip }}
|
|
59
|
+
INPUT_SEVERITY: ${{ inputs.severity }}
|
|
60
|
+
INPUT_FAIL_ON_CRITICAL: ${{ inputs.fail_on_critical }}
|
|
61
|
+
GITHUB_TOKEN: ${{ github.token }}
|
package/dist/src/utils/logger.js
CHANGED
|
@@ -5,24 +5,24 @@ export function setVerbose(enabled) {
|
|
|
5
5
|
}
|
|
6
6
|
export const log = {
|
|
7
7
|
info(message) {
|
|
8
|
-
console.
|
|
8
|
+
console.error(chalk.blue("ℹ"), message);
|
|
9
9
|
},
|
|
10
10
|
success(message) {
|
|
11
|
-
console.
|
|
11
|
+
console.error(chalk.green("✓"), message);
|
|
12
12
|
},
|
|
13
13
|
warn(message) {
|
|
14
|
-
console.
|
|
14
|
+
console.error(chalk.yellow("⚠"), message);
|
|
15
15
|
},
|
|
16
16
|
error(message) {
|
|
17
17
|
console.error(chalk.red("✗"), message);
|
|
18
18
|
},
|
|
19
19
|
verbose(message) {
|
|
20
20
|
if (verboseMode) {
|
|
21
|
-
console.
|
|
21
|
+
console.error(chalk.gray("→"), chalk.gray(message));
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
step(message) {
|
|
25
|
-
console.
|
|
25
|
+
console.error(chalk.cyan("●"), message);
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
//# sourceMappingURL=logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,MAAM,UAAU,UAAU,CAAC,OAAgB;IACzC,WAAW,GAAG,OAAO,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,MAAM,UAAU,UAAU,CAAC,OAAgB;IACzC,WAAW,GAAG,OAAO,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,CAAC,OAAe;QACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,OAAe;QACnB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,CAAC,OAAe;QACrB,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchpilots",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "A team of AI agents that reviews and improves your code automatically",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
"types": "./dist/src/index.d.ts",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
+
"action",
|
|
14
|
+
"action.yml",
|
|
13
15
|
"README.md",
|
|
14
16
|
"LICENSE"
|
|
15
17
|
],
|