CI-friendly CLI that opens PRs with passing Jest unit tests.
npm install phantom-prphantom-pr is a CI-friendly CLI that opens PRs with passing Jest/Vitest/pytest unit tests (bounded + deterministic, PR-only, no auto-merge).
bash
npm install -g phantom-pr
`
Or use directly with npx:
`bash
npx phantom-pr --help
`
Quick Start
`bash
1. Create config file
cat > phantom-pr.yml << EOF
baseBranch: main
github:
owner: your-org
repo: your-repo
tokenEnvVar: GITHUB_TOKEN
mode:
dryRun: true
test:
command: npm test
EOF
2. Index your codebase
phantom-pr index --root .
3. Generate a plan
phantom-pr plan --root .
4. Run in dry mode first
phantom-pr full --root . --dryRun
`
Features
$3
Generate unit tests for any file:
`bash
phantom-pr tests src/components/Button.tsx --local
`
$3
The test generator now uses AST analysis to:
- Detect branches - Finds if, ternary, switch, and &&/|| operators
- Identify effects - Detects useEffect, useLayoutEffect with cleanup detection
- Map child components - Finds components that need mocking
- Track external calls - Identifies imported functions being called
This enables smarter test generation with better branch coverage.
$3
When tests fail, the retry system now:
- Parses Jest/Vitest error output
- Identifies specific error types (mock not called, assertion mismatch, import errors)
- Generates targeted fix suggestions
- Creates focused retry prompts
$3
After generating tests, validation checks:
- Branch coverage completeness
- Effect cleanup testing (for useEffect with cleanup)
- Child component mocking
- Returns specific llm_reject_* codes for failures
Commands
| Command | Description |
|---------|-------------|
| phantom-pr status | Show config and status |
| phantom-pr index | Index the codebase |
| phantom-pr plan | Generate test plan |
| phantom-pr tests | Generate tests for a file |
| phantom-pr full | Full orchestration (CI mode) |
| phantom-pr pr --prNumber | PR companion mode |
| phantom-pr testability | Add data-testid attributes |
Configuration
Create phantom-pr.yml at repo root:
`yaml
baseBranch: main
github:
owner: your-org
repo: your-repo
tokenEnvVar: GITHUB_TOKEN
allowForkPrs: false # Safety default
limits:
maxFilesChanged: 50
maxLinesChanged: 5000
maxIterations: 5
maxOpenBotPRs: 3
maxPRsPerRun: 1
mode:
dryRun: true # Set false for real PRs
test:
command: npm test
`
$3
| Option | Description | Default |
|--------|-------------|---------|
| baseBranch | Target branch for PRs | main |
| limits.maxIterations | Max test retry attempts | 5 |
| limits.maxPRsPerRun | Max PRs per CI run | 1 |
| mode.dryRun | Disable real Git/GitHub operations | true |
| test.command | Test command to run | npm test |
CI Integration
$3
`yaml
GitHub Actions example
on:
schedule:
- cron: '0 1,7,13,19 *'
jobs:
phantom-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npx phantom-pr full --root .
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
`
$3
See docs/jenkins.md for Pipeline examples.
Understanding Reports
$3
See docs/report-json.md for schema details.
Key fields:
- finalOutcome: pass | fail | timeout
- attempts: Array of test run attempts
- generatorWarnings: Any validation issues
$3
- caps: Open PR count and limits
- chosenTarget: What file was selected
- lane: tests | testability | skipped
Contributing
$3
`bash
git clone https://github.com/norralak/blacksand-phantom-pr.git
cd blacksand-phantom-pr
npm install
npm run build
npm test
`
$3
`
src/
โโโ cli.ts # CLI entrypoint
โโโ commands/ # Command implementations
โโโ adapters/ # IO boundaries (git, github, fs)
โโโ core/
โโโ analysis/ # AST extraction (NEW)
โโโ context/ # Context packing & selection
โโโ validation/ # Post-generation validation (NEW)
โโโ retry/ # Error parsing & feedback (NEW)
โโโ generator/ # Test generators (LLM, smoke)
โโโ testRunner/ # Test execution
โโโ ...
`
$3
`bash
All tests
npm test
Specific test file
npm test -- tests/ast-extractor.test.mjs
With verbose output
npm test -- --test-reporter=spec
`
$3
- TypeScript: Strict mode enabled
- Formatting: Prettier (run npm run format)
- Linting: TypeScript compiler (npm run lint)
$3
1. Create types first in types.ts
2. Implement with tests - follow TDD
3. Add barrel export in index.ts
4. Update README if user-facing
$3
When adding features with heuristics (parsing, detection), document risks:
| When to add risk | Example |
|------------------|---------|
| Regex-based parsing | Error parser patterns |
| Static lists | External package detection |
| Heuristic detection | Branch/effect identification |
$3
- One feature per PR
- Include tests for new functionality
- Update documentation
- Run npm test before submitting
Required Permissions
$3
- Create branches
- Push commits
$3
- Contents: Read & Write
- Pull requests: Read & Write
- Issues: Read & Write (for comments)
- Metadata: Read
Troubleshooting
$3
The test generator mocks child components. If you see import errors:
`typescript
// Add to test file
jest.mock('./ChildComponent');
`
$3
- Check for async operations without proper await
- Use waitFor() from testing-library
- Increase timeout in jest config
$3
Check .phantom-pr/report.json for:
- llm.allowed: Must be true
- generatorWarnings`: Shows rejection reasons