Streamlined GitHub PR automation for modern applications in Typescript. Hypersonic is a high-level API for creating and managing Pull Requests, designed specifically for AI and SaaS applications that need to propose changes to user repositories.
For the Python version, check out supersonic.
- 🚀 Simple, High-Level API: Create PRs with a single function call
- 🛡️ Safe Defaults: All changes go through PRs for review
- 🏢 Enterprise Ready: Full GitHub Enterprise support
- ⚙️ Excessively Customizable: Complete control over PR creation
- 📦 Multiple File Support: Update any number of files in one PR
- 🎯 Perfect for Apps & Scripts: From SaaS features to internal tools
- 🤖 Automation Ready: Auto-merge, labels, reviewers, and more
Common use cases:
- AI applications and agents suggesting code improvements
- Documentation generators keeping docs in sync with code
- Configuration management tools proposing config updates
- Any service that needs to propose changes to user repositories
npm install @runcased/hypersonic
import { Hypersonic } from '@runcased/hypersonic';
const hypersonic = new Hypersonic('your-github-token');
// Create a PR from a local file
await hypersonic.createPrFromFile(
'owner/repo',
'local/path.txt',
'remote/path.txt',
{
title: 'Update documentation',
description: 'Updated API docs with new endpoints',
labels: ['documentation']
}
);
import { Hypersonic, MergeStrategy } from '@runcased/hypersonic';
// Initialize with just a token
const hypersonic = new Hypersonic('your-github-token');
// Or with full configuration: passing token, an optional baseUrl,
// and a defaultPrConfig object with whatever you want.
// This is useful if you want to set your own defaults for all PRs.
const hypersonic = new Hypersonic({
githubToken: 'your-github-token',
baseUrl: 'https://api.github.com', // Optional, useful for GitHub Enterprise
defaultPrConfig: {
title: 'Update files',
description: 'Automated update',
baseBranch: 'main',
draft: false,
labels: ['automated'],
reviewers: ['teammate'],
teamReviewers: ['team-name'],
mergeStrategy: MergeStrategy.SQUASH, // Or simply 'squash'
deleteBranchOnMerge: true,
autoMerge: true
}
});
Each PR creation method is designed for different use cases:
Create or update a single file using a content string:
await hypersonic.createPrFromContent(
'owner/repo', // Repository in format "owner/repo"
'file content', // The actual content to write
'path/to/file.txt' // Path where file will be created/updated in the repo
{ // Optional config. Will override any defaults or instance config.
title: 'Add new documentation',
description: 'Added API documentation for new endpoints',
baseBranch: 'develop',
labels: ['documentation'],
reviewers: ['teammate1', 'teammate2'],
teamReviewers: ['api-team'],
mergeStrategy: 'squash',
autoMerge: true
}
);
Use Cases:
- Adding documentation files
- Updating configuration files
- Creating new source files
- Programmatically generating content
Upload or update a file from your local filesystem:
await hypersonic.createPrFromFile(
'owner/repo', // Repository in format "owner/repo"
'local/path.txt', // Path to file on your local system
'remote/path.txt', // Path where file will be placed in the repo
{ // Optional config
title: 'Update configuration',
commitMessage: 'chore: update config file',
labels: ['config'],
draft: true
}
);
Use Cases:
- Uploading built/compiled files
- Syncing local changes to remote
- Updating files from CI/CD pipelines
- Working with local development files
Update multiple files using content strings. You're passing in an object where the keys are the target paths and the values are the content strings.
await hypersonic.createPrFromMultipleContents(
'owner/repo', // Repository in format "owner/repo"
{ // Object mapping paths to content
'config/settings.json': '{"new setting": "new value"}',
'docs/README.md': '# Updated Docs',
'src/index.ts': 'export const version = "2.0.0";'
},
{ // Optional config
title: 'Update multiple files',
description: 'Batch update of configuration and documentation',
baseBranch: 'main',
reviewers: ['tech-lead'],
teamReviewers: ['platform-team']
}
);
Use Cases:
- Updating version numbers across multiple files
- Making coordinated changes to related files
- Bulk content updates from external sources
- API-driven file updates
Upload multiple files from your local filesystem. You're passing in an object where the keys are the local paths and the values are the remote paths.
await hypersonic.createPrFromFiles(
'owner/repo', // Repository in format "owner/repo"
{ // Object mapping local paths to remote paths
'local/dist/bundle.js': 'dist/bundle.js',
'local/dist/styles.css': 'dist/styles.css',
'local/README.md': 'README.md'
},
{ // Optional config
title: 'Deploy latest build',
description: 'Update production bundle and documentation',
labels: ['deploy', 'production'],
autoMerge: true,
mergeStrategy: MergeStrategy.SQUASH
}
);
Use Cases:
- Deploying build artifacts
- Syncing multiple local changes
- Updating sets of related files
- Batch file migrations
All methods accept the same configuration options:
interface PRConfig {
// Required
title: string; // PR title
// Optional
description?: string; // PR description/body
baseBranch: string; // Target branch (default: 'main')
draft: boolean; // Create as draft PR
labels: string[]; // Labels to add
reviewers: string[]; // Individual reviewers
teamReviewers: string[]; // Team reviewers
mergeStrategy: MergeStrategy | 'merge' | 'squash' | 'rebase';
deleteBranchOnMerge: boolean; // Delete branch after merge
autoMerge: boolean; // Enable auto-merge
commitMessage?: string; // Custom commit message
}
For complete working examples, check out:
- Basic Usage - Shows all PR creation methods and configuration options
There are two levels of configuration:
- Instance Configuration - When creating a Hypersonic instance, you can provide a defaultPrConfig. All fields are optional and will use these defaults:
const DEFAULT_PR_CONFIG = {
title: 'Automated changes',
description: undefined,
baseBranch: 'main',
draft: false,
labels: [],
reviewers: [],
teamReviewers: [],
mergeStrategy: MergeStrategy.SQUASH,
deleteBranchOnMerge: true,
autoMerge: false,
commitMessage: undefined
};
- Per-Request Configuration - When calling PR creation methods, you need to provide:
interface PRRequestConfig {
// Required
title: string; // PR title
// All other fields are optional and will use defaults if not specified
description?: string;
baseBranch?: string;
draft?: boolean;
labels?: string[];
reviewers?: string[];
teamReviewers?: string[];
mergeStrategy?: MergeStrategy | 'merge' | 'squash' | 'rebase';
deleteBranchOnMerge?: boolean;
autoMerge?: boolean;
commitMessage?: string;
}
When using any of the PR creation methods, you only need to provide a title
. All other fields
will use their default values if not specified.
Example configuration:
const config: Partial<PRConfig> = {
// Required
title: 'Update API documentation',
// Optional - these will use defaults if not specified
description: 'Updated endpoint documentation',
baseBranch: 'main',
draft: false,
labels: ['documentation'],
reviewers: ['teammate'],
teamReviewers: [],
mergeStrategy: 'squash',
deleteBranchOnMerge: true,
autoMerge: true
};
Hypersonic merges configuration in the following order (later sources override earlier ones):
- Default configuration (built-in defaults)
- Instance configuration (passed to constructor)
- Per-request configuration (passed to individual methods)
// 1. Built-in defaults
const DEFAULT_PR_CONFIG = {
title: 'Automated changes',
baseBranch: 'main',
draft: false,
labels: [],
reviewers: [],
teamReviewers: [],
mergeStrategy: MergeStrategy.SQUASH,
deleteBranchOnMerge: true,
autoMerge: false
};
// 2. Instance configuration
const hypersonic = new Hypersonic({
githubToken: 'token',
defaultPrConfig: {
labels: ['automated'],
reviewers: ['default-reviewer'],
mergeStrategy: 'rebase'
}
});
// 3. Per-request configuration
await hypersonic.createPrFromContent(
'owner/repo',
'content',
'file.txt',
{
title: 'Custom PR', // Overrides default title
labels: ['urgent'], // Replaces ['automated']
reviewers: [], // Removes default reviewer
// mergeStrategy inherits 'rebase' from instance config
// Other fields use built-in defaults
}
);
const hypersonic = new Hypersonic({
githubToken: 'your-token',
baseUrl: 'https://github.your-company.com/api/v3'
});
const defaultConfig = {
title: 'Update: ${filename}',
description: 'Updated ${path} with latest changes',
labels: ['automated'],
reviewers: ['teammate'],
teamReviewers: ['team-name'],
mergeStrategy: 'squash',
autoMerge: true
};
const hypersonic = new Hypersonic({
githubToken: 'your-token',
defaultPrConfig: defaultConfig
});
import { GitHubError, GitError } from '@runcased/hypersonic';
try {
await hypersonic.createPrFromFile(...);
} catch (error) {
if (error instanceof GitHubError) {
// Handle GitHub API errors
console.log(error.status); // HTTP status if available
} else if (error instanceof GitError) {
// Handle Git operation errors
}
}
Contributions welcome! Please read our contributing guidelines first.
MIT