Metadata-Version: 2.5
Name: diffly-cli
Version: 1.0.0
Summary: Deterministic triage for large GitHub pull requests
Author: Vivaan Dhawan
License: MIT License — diffly
        
        Copyright (c) 2026 Vivaan Dhawan
        
        ================================================================================
        PART 1 — THE LICENSE GRANT (standard MIT text)
        ================================================================================
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        ================================================================================
        PART 2 — DEFINITIONS AND CLARIFICATIONS
        ================================================================================
        
        These clarifications are part of this license. Where Part 1 and Part 2 could
        be read differently, Part 1 controls; Part 2 explains intent.
        
        1. "Software" means the diffly source code, its bundled GitHub Action, its
           install scripts, its documentation, and any object code or distributions
           built from them, in whole or in part.
        
        2. "Contribution" means any work submitted to the project — including pull
           requests, patches, and documentation — that is intentionally offered for
           inclusion in the Software. By submitting a Contribution you agree it is
           licensed under this same license, with no additional terms or conditions,
           to the maximum extent permitted by law. You confirm you have the right to
           license what you submit.
        
        3. Verdicts are opinions, not guarantees. The PASS, QUARANTINE, BLOCK, and
           related outputs produced by the Software are deterministic heuristics
           applied at a point in time against data available at that moment. They are
           review aids only. They do not certify correctness, security, safety,
           fitness for production, compliance with any law, regulation, or standard,
           or the absence of defects in any analyzed code, repository, or change.
           You remain solely responsible for all decisions about the software you
           review, merge, ship, or operate.
        
        4. Network services. The Software may contact third-party services you direct
           it to (for example the GitHub REST API) and, only when explicitly enabled
           by you, an OpenAI-compatible model endpoint you configure. Those services
           are governed by their own terms. The project authors neither operate those
           services nor are party to your relationship with them.
        
        5. Trademarks. This license grants no rights in the names "diffly",
           "diffly-cli", or any related marks, logos, or trade dress, except as
           strictly required for reasonable attribution or nominative fair use.
        
        ================================================================================
        PART 3 — WARRANTY AND LIABILITY (extended statement)
        ================================================================================
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, ACCURACY OF OUTPUT,
        AND UNINTERRUPTED OR ERROR-FREE OPERATION. SOME JURISDICTIONS DO NOT ALLOW THE
        EXCLUSION OF CERTAIN IMPLIED WARRANTIES, SO SOME OF THE ABOVE MAY NOT APPLY TO
        YOU TO THE EXTENT LAW REQUIRES IT.
        
        IN NO EVENT AND UNDER NO LEGAL THEORY — WHETHER IN CONTRACT, TORT (INCLUDING
        NEGLIGENCE), STRICT LIABILITY, STATUTE, OR OTHERWISE — SHALL THE AUTHORS,
        COPYRIGHT HOLDERS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL DAMAGES (INCLUDING,
        BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        DATA, PROFITS, GOODWILL, OR REPUTATION; BUSINESS INTERRUPTION; SECURITY
        INCIDENTS; BUILD FAILURES; OR RELEASED DEFECTS) HOWEVER CAUSED AND ON ANY
        THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF OR IN CONNECTION WITH THE
        SOFTWARE OR ITS USE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        
        TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE TOTAL AGGREGATE
        LIABILITY OF THE AUTHORS AND COPYRIGHT HOLDERS FOR ALL CLAIMS RELATING TO THE
        SOFTWARE SHALL BE LIMITED TO THE GREATER OF ONE HUNDRED UNITED STATES DOLLARS
        (USD 100) OR THE AMOUNT YOU PAID FOR THE SOFTWARE, WHICH BY DEFAULT IS ZERO.
        
        ================================================================================
        PART 4 — GENERAL TERMS
        ================================================================================
        
        1. Compliance with law. Your use of the Software must comply with applicable
           export-control, sanctions, privacy, and other laws.
        
        2. Severability. If any provision of this license is held unenforceable, it
           will be modified to the minimum extent necessary, and the remaining
           provisions stay in force.
        
        3. No waiver. Failure to enforce any provision is not a waiver of it.
        
        4. Termination. The licenses granted here terminate automatically if you
           breach this license. They otherwise survive as long as the copyright law
           of your jurisdiction requires, and are perpetual where permitted.
        
        5. Entire agreement. This license is the entire agreement between you and the
           copyright holders concerning the Software, superseding any other terms
           communicated alongside copies of it.
        
        6. Language. This license is written in English; translations are for
           convenience only, and the English text controls.
        
        THIS LICENSE FOLLOWS THE MIT LICENSE TEMPLATE AND ADDS CLARIFYING MATERIAL.
        THE GRANT IN PART 1 REMAINS THE GOVERNING PERMISSION.
License-File: LICENSE
Keywords: blast-radius,cli,code-review,github,pull-request,tree-sitter
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.10
Requires-Dist: openai>=1.0
Requires-Dist: rich>=13.9
Requires-Dist: tree-sitter-language-pack>=1.10
Requires-Dist: tree-sitter>=0.25
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: pyyaml>=6; extra == 'dev'
Description-Content-Type: text/markdown

<p align="center">
  <img src="assets/logo-v2.svg" alt="diffly logo" width="280">
</p>

# ⚡ diffly

<p align="center">
  <b>Your PR is 4,000 lines long. Nobody wants to review it.</b><br>
  diffly reads it for you — files, symbols, checks, tests, blast radius —<br>
  and hands you one page and one verdict: <b>PASS</b>, <b>QUARANTINE</b>, or <b>BLOCK</b>.
</p>

<p align="center">
  <a href="https://github.com/VIVAAN-DHAWAN/diffly-cli/actions/workflows/ci.yml"><img src="https://img.shields.io/badge/CI-passing-brightgreen?style=for-the-badge&logo=githubactions" alt="CI"></a>
  <a href="https://github.com/VIVAAN-DHAWAN/diffly-cli/releases/latest"><img src="https://img.shields.io/badge/release-v1.0.0-blue?style=for-the-badge" alt="Release"></a>
  <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.10%2B-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python 3.10+"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="License: MIT"></a>
</p>

---

## Install

Pick whichever fits your setup:

**curl (recommended)**
```bash
curl -fsSL https://raw.githubusercontent.com/VIVAAN-DHAWAN/diffly-cli/main/install.sh | sh
```

**pip**
```bash
pip install diffly-cli
```
**uv**
```bash
uv tool install diffly-cli
```

**Homebrew**
```bash
brew install VIVAAN-DHAWAN/diffly-cli/diffly-cli
```

That's it. If `diffly` isn't found, add `~/.local/bin` to your `PATH` (curl/pip/uv) and open a new shell.

### Upgrading from pre-0.4.0

If you already have diffly installed but are on a version before 0.4.0 (which introduced the built-in update system), run the one-time upgrade script:

```bash
curl -fsSL https://raw.githubusercontent.com/VIVAAN-DHAWAN/diffly-cli/main/upgrade.sh | sh
```

This pulls in 0.4.0+, which has `diffly update` built in. From that point on, diffly will automatically check for new releases every time you run it and prompt you to update — no more manual upgrades needed.

## Updating

From 0.4.0 onwards, just run:

```bash
diffly update
```

Or simply start diffly normally — it will check for updates on launch and ask if you'd like to install the latest version. You can also choose to enable automatic updates so future versions install silently.

## Try it in 10 seconds

```bash
diffly pr https://github.com/astral-sh/ruff/pull/27808
```

Paste any pull-request URL — or run bare `diffly` for a guided flow. You'll get a keyboard-driven, one-page review: verdict, risk flags, checks, and a per-file blast-radius map. Arrow keys move, space toggles sections, Enter renders, `q` quits.

![diffly-cli animated demonstration](assets/diffly-cli-demo.gif)

---

## What diffly actually does

Large AI-generated pull requests are hard to review because file-by-file diffs hide what matters: which symbols changed, which tests cover them, whether dependencies moved, whether a security-sensitive file was touched. diffly makes the deterministic part of that review visible **before** any LLM gets involved.

It fetches the PR metadata, changed files, unified diff, commits, status checks, and repository tree; parses source changes with Tree-sitter; maps the blast radius; applies fixed risk rules; and emits a one-page Markdown report with a verdict.

<table>
<tr><td><b>One-page verdicts</b></td><td><code>PASS</code>, <code>QUARANTINE</code>, or <code>BLOCK</code> from fixed, documented rules. Same PR data in, same verdict out — every time.</td></tr>
<tr><td><b>Blast-radius map</b></td><td>Per file: status, additions/deletions, touched symbols, direct callers visible in changed hunks, and related test files discovered from the repository tree.</td></tr>
<tr><td><b>Risk flags</b></td><td>Auth/secrets touches, database changes, new dependencies, missing test coverage, failed or pending checks — each with severity and evidence.</td></tr>
<tr><td><b>Works offline</b></td><td><code>diffly local</code> triages git changes in any folder on disk — private, archived, or removed repositories included.</td></tr>
<tr><td><b>CI-native</b></td><td>Bundled GitHub Action posts one self-updating verdict comment on every PR. Stable JSON output for scripts.</td></tr>
<tr><td><b>Optional AI explainer</b></td><td>Bring your own OpenAI-compatible key for a generated narrative — sandboxed, redacted, strictly validated, and never allowed to change the verdict.</td></tr>
</table>

## Local mode — no GitHub required

Analyze git changes on your own disk. No token, no network:

```bash
diffly local                      # uncommitted working-tree changes in the current folder
diffly local ~/code/private-repo  # any checkout — even repos deleted from GitHub
diffly local --base main          # compare your branch against main instead
```

Untracked files are included, so brand-new work is never silently ignored. CI checks don't exist locally, so check-derived flags are skipped; everything else behaves exactly as it does for pull requests.

## GitHub Action

Add this to analyze every pull request automatically:

```yaml
name: Diffly
on: pull_request
permissions:
  contents: read
  pull-requests: write
jobs:
  diffly:
    runs-on: ubuntu-latest
    steps:
      - uses: VIVAAN-DHAWAN/diffly-cli@main
```

To enable the optional explainer in CI, add `DIFFLY_LLM_API_KEY: ${{ secrets.DIFFLY_LLM_API_KEY }}` under the step's `env`. Without a key, the Action runs deterministic-only.

## Everyday commands

```bash
diffly                                          # guided wizard
diffly pr astral-sh/ruff 27808                  # owner/repo + number
diffly pr https://github.com/astral-sh/ruff/pull/27808   # just paste the URL
diffly pr astral-sh/ruff 27808 --interactive    # keyboard-driven review
diffly pr astral-sh/ruff 27808 --output triage.md
diffly pr astral-sh/ruff 27808 --json           # stable JSON for scripts
diffly setup                                    # guided tutorial
diffly doctor                                   # environment diagnostics
diffly update                                   # check for and install the latest release
```

For automation prefer `--json`: successful triage exits `0` regardless of verdict — enforce policy by reading the `verdict` field. Operational errors exit `2`.

### Optional AI explanation

Every opted-in explanation is shown in the review. With an AI key, Diffly produces a bounded, redacted AI narrative; without one—or if the provider is unavailable—it creates a clearly labelled local explanation from deterministic review facts instead. Neither path can alter the verdict.

```bash
export DIFFLY_LLM_API_KEY="your-key"
export DIFFLY_LLM_BASE_URL="https://api.openai.com/v1"  # omit for the default endpoint
diffly pr OWNER/REPO NUMBER --explain
```

Default model is `gpt-5-mini`; override with `DIFFLY_LLM_MODEL` or `--llm-model`. The explainer sends bounded, redacted context, requires strict JSON output, rejects citations to files outside the changed-file set, and fails safely back to deterministic triage when anything is off.

## The verdict policy

| Verdict | Rule |
| --- | --- |
| **BLOCK** | A required check failed, or the changed hunk appears to add a credential-like value. |
| **QUARANTINE** | Security-sensitive code, database schema/migrations, dependency changes, or still-pending checks need focused review. |
| **PASS** | No blocking or quarantine rule fired. Missing obvious tests and unavailable checks stay visible as review notes, but do not turn an otherwise healthy PR into `QUARANTINE`. `SHIP` remains accepted as a legacy alias. |

`PASS` is the normal healthy outcome. A verdict is a review signal, not a claim that a PR is correct or safe in every context.

## Real examples

Captured from live terminal sessions against public pull requests:

| Pull request | Files | Lines | Verdict | Why |
| --- | --- | --- | --- | --- |
| [`microsoft/vscode#330848`](demo/vscode-330848.md) | 25 | +2,557 / -251 | QUARANTINE | production files without obvious test coverage |
| [`kubernetes/kubernetes#141413`](demo/kubernetes-141413.md) | 41 | +708 / -740 | QUARANTINE | missing coverage + pending `tide` check |
| [`astral-sh/ruff#27808`](demo/ruff-27808.md) | 53 | +1,845 / -274 | BLOCK | `CodSpeed Performance Analysis` check failed |

Standalone screenshots: [vscode](assets/screenshots/vscode-330848.png) · [kubernetes](assets/screenshots/kubernetes-141413.png) · [ruff](assets/screenshots/ruff-27808.png)

Live AI-explainer reports (deterministic verdict preserved): [ruff phase 2](demo/ruff-27808-phase2.md) · [kubernetes phase 2](demo/kubernetes-141413-phase2.md)

## Current limitations

Tree-sitter parsing covers symbols and direct calls visible in changed hunks, not a full repository-wide call graph. Test-coverage detection is heuristic (filenames + repository tree), so it is presented as a review note rather than a verdict gate. AI model context is bounded and may truncate on very large PRs. A local explanation is used when AI generation is not available.

## Roadmap

- repository-wide symbol resolution and import-aware blast radius;
- configurable policy files for org-specific risk rules and thresholds;
- GitHub annotations and check-run output alongside the PR comment;
- baseline mode reporting only risks introduced vs the target branch;
- coverage-artifact-based test mapping;
- SARIF output for code-scanning integrations.

Details: [`docs/phase-2-contract.md`](docs/phase-2-contract.md) · [`docs/benchmarks.md`](docs/benchmarks.md)

## Development

```bash
git clone https://github.com/VIVAAN-DHAWAN/diffly-cli.git
cd diffly-cli
python -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[dev]'
pytest -q
```

Keep changes focused, include regression tests, and record user-facing changes in [`CHANGELOG.md`](CHANGELOG.md). See [`CONTRIBUTING.md`](CONTRIBUTING.md).

## Security & privacy

Diffly talks to the GitHub API only for the repo and PR you point it at. Deterministic mode sends no code to any LLM. With `--explain`, bounded redacted context goes to your configured endpoint — read [`docs/phase-2-contract.md`](docs/phase-2-contract.md) before enabling it on sensitive repositories. Prefer environment variables over command-line tokens.

Report vulnerabilities privately via [GitHub security advisories](https://github.com/VIVAAN-DHAWAN/diffly-cli/security/advisories/new).

## License

Released under the [MIT License](LICENSE).
