Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes will be documented here. This project follows Semantic Versi

- Added strict versioned `.agentskit-review.json` policy with lens coverage, budgets, thresholds, context, and safe CI precedence; incomplete profiles require explicit local opt-in.
- Hardened the shared local CLI worker with cancellation, process-tree cleanup, isolated temporary environments, bounded output, and redacted diagnostics.
- Added bounded source snapshots with infrastructure/configuration file support, denylisted sensitive paths, symlink checks, input limits, and data-boundary-aware secret redaction.
- Made reviews fail closed when any reviewable file has no successful primary lens or cannot be ingested; advisory mode now suppresses finding-based failures only, never source/provider/execution failures.
- Added primary-lens execution coverage to review summaries so partial provider degradation is visible.
- Repositioned the CLI and GitHub Action as provider-neutral.
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ In shortened examples, replace `...` with `npx --yes github:AgentsKit-io/code-re
| `--no-fail` | Keep findings advisory |
| `--conventions <path>` | Inject project conventions |
| `--allow-incomplete` | Local-only exception for a config that declares incomplete lens coverage |
| `--allow-unredacted` | Local-only exception; rejected in CI |
| `--api` | Back-compatible alias for `--provider anthropic` |
| `doctor --provider <name>` | Offline provider diagnostics; no model request |
| `doctor --live` | Explicit provider smoke-test mode |
Expand Down Expand Up @@ -295,6 +296,9 @@ never accepted in CI.
Provider, model, transport, context trust, redaction, and permissions are
trusted execution inputs; a project config cannot set them in CI. Put provider
credentials only in the environment or provider login, never in this file.
Remote and unknown provider boundaries redact high-confidence credential
patterns before the model sees source. Unsafe, oversized, binary, or excluded
paths are reported as `UNREVIEWED`; content is never silently truncated.

### Doctor

Expand Down
16 changes: 13 additions & 3 deletions agents/code-review/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export interface ReviewTarget {
isChanged: boolean
/** Head commit SHA, for github-pr (needed to anchor inline comments). */
commitId?: string
/** Source normalization could not safely review this path. */
reviewStatus?: 'UNREVIEWED'
unreviewedReason?: string
}

export interface Finding {
Expand Down Expand Up @@ -106,6 +109,7 @@ export interface ReviewResult {
droppedNote?: string
/** Provider execution coverage for primary review lenses. */
execution: LensExecutionStats
unreviewed?: Array<{ file: string; reason: string }>
summary: string
}

Expand Down Expand Up @@ -420,6 +424,7 @@ export function createCodeReviewAgent(config: CodeReviewConfig) {
reviewed: number,
droppedFiles: number,
execution: LensExecutionStats,
unreviewedCount: number,
): ReviewResult {
const counts = (['blocker', 'high', 'med', 'nit'] as Severity[]).map((s) => ({ s, n: kept.filter((f) => f.severity === s).length }))
const worst = kept.length ? Math.min(...kept.map((f) => SEV_RANK[f.severity])) : 3
Expand All @@ -432,6 +437,7 @@ export function createCodeReviewAgent(config: CodeReviewConfig) {
const summary =
`${kept.length} finding(s) (${breakdown}) across ${reviewed} file(s)` +
(config.incompleteProfile ? ' Incomplete profile; this review is not an approval.' : '') +
(unreviewedCount ? ` ${unreviewedCount} file(s) UNREVIEWED.` : '') +
(droppedFiles ? `, ${droppedFiles} file(s) skipped for budget` : '') +
`. ${executionSummary}.`
return { verdict, blocking, findings: kept, dropped, execution, summary }
Expand All @@ -444,8 +450,10 @@ export function createCodeReviewAgent(config: CodeReviewConfig) {
emit('ingest', 'start')
const t0 = Date.now()
const all = await loadTargets(config.source)
const unreviewed = all.filter((target) => target.reviewStatus === 'UNREVIEWED')
for (const target of unreviewed) emit('ingest', 'skip', `${target.file}: ${target.unreviewedReason ?? 'unreviewed'}`)
// Prioritise: changed first, then by amount of change, then size.
const ranked = [...all].sort(
const ranked = all.filter((target) => target.reviewStatus !== 'UNREVIEWED').sort(
(a, b) =>
Number(b.isChanged) - Number(a.isChanged) ||
(b.changedRanges?.length ?? 0) - (a.changedRanges?.length ?? 0) ||
Expand All @@ -462,7 +470,8 @@ export function createCodeReviewAgent(config: CodeReviewConfig) {
findings: [],
dropped: [],
execution: { attempted: 0, succeeded: 0, failed: 0 },
summary: 'Nothing to review.',
unreviewed: unreviewed.map((target) => ({ file: target.file, reason: target.unreviewedReason ?? 'unreviewed' })),
summary: unreviewed.length ? `${unreviewed.length} file(s) UNREVIEWED; nothing else to review.` : 'Nothing to review.',
}
}

Expand Down Expand Up @@ -518,7 +527,8 @@ export function createCodeReviewAgent(config: CodeReviewConfig) {
emit('validate-patch', 'ok', undefined, Date.now() - t3)
}

const result = synthesize(kept, dropped, targets.length, droppedFiles, execution)
const result = synthesize(kept, dropped, targets.length, droppedFiles, execution, unreviewed.length)
result.unreviewed = unreviewed.map((target) => ({ file: target.file, reason: target.unreviewedReason ?? 'unreviewed' }))
result.droppedNote =
`${refuted.length} refuted by skeptics; ${belowThreshold.length} below threshold` +
(thresholded.length - kept.length ? `; ${thresholded.length - kept.length} merged as duplicates` : '') + '.'
Expand Down
Loading