333 lines
11 KiB
Markdown
333 lines
11 KiB
Markdown
# Upstream Merge Automation
|
|
|
|
Scripts for automating the merge of upstream opencode changes into Kilo.
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Install dependencies (from script/upstream directory)
|
|
cd script/upstream
|
|
bun install
|
|
|
|
# List available upstream versions
|
|
bun run list-versions.ts
|
|
|
|
# Analyze changes for a specific version (without merging)
|
|
bun run analyze.ts --version v1.1.49
|
|
|
|
# Run the full merge process
|
|
bun run merge.ts --version v1.1.49
|
|
|
|
# Dry-run to preview what would happen
|
|
bun run merge.ts --version v1.1.49 --dry-run
|
|
|
|
# Use a different base branch (e.g., for incremental merges)
|
|
bun run merge.ts --version v1.1.50 --base-branch catrielmuller/kilo-opencode-v1.1.44
|
|
```
|
|
|
|
## Scripts
|
|
|
|
### Main Scripts
|
|
|
|
| Script | Description |
|
|
| ------------------ | --------------------------------------------- |
|
|
| `merge.ts` | Main orchestration script for upstream merges |
|
|
| `list-versions.ts` | List available upstream versions |
|
|
| `analyze.ts` | Analyze changes without merging |
|
|
|
|
### Transform Scripts
|
|
|
|
| Script | Description |
|
|
| -------------------------------------- | ----------------------------------------------------------- |
|
|
| `transforms/package-names.ts` | Transform opencode package names to kilo |
|
|
| `transforms/preserve-versions.ts` | Preserve Kilo's package versions |
|
|
| `transforms/keep-ours.ts` | Keep Kilo's version of specific files |
|
|
| `transforms/skip-files.ts` | Skip/remove files that shouldn't exist in Kilo |
|
|
| `transforms/transform-i18n.ts` | Transform i18n files with Kilo branding |
|
|
| `transforms/transform-take-theirs.ts` | Take upstream + apply Kilo branding for branding-only files |
|
|
| `transforms/transform-tauri.ts` | Transform Tauri/Desktop config files |
|
|
| `transforms/transform-package-json.ts` | Enhanced package.json with Kilo dependency injection |
|
|
| `transforms/transform-scripts.ts` | Transform script files with GitHub API references |
|
|
| `transforms/transform-extensions.ts` | Transform extension files (Zed, etc.) |
|
|
| `transforms/transform-web.ts` | Transform web/docs files (.mdx) |
|
|
|
|
### Codemods (AST-based)
|
|
|
|
| Script | Description |
|
|
| ------------------------------- | ------------------------------------------ |
|
|
| `codemods/transform-imports.ts` | Transform import statements using ts-morph |
|
|
| `codemods/transform-strings.ts` | Transform string literals |
|
|
|
|
## Merge Process
|
|
|
|
The merge automation follows this process, applying **all transformations BEFORE the merge** to minimize conflicts:
|
|
|
|
1. **Validate environment**
|
|
- Check for upstream remote
|
|
- Ensure working directory is clean
|
|
|
|
2. **Fetch upstream** and determine target version
|
|
|
|
3. **Generate conflict report** analyzing which files will conflict
|
|
|
|
4. **Create branches**
|
|
- `backup/<branch>-<timestamp>` - Backup of current state
|
|
- `<author>/kilo-opencode-<version>` - Merge target branch
|
|
- `<author>/opencode-<version>` - Transformed upstream branch
|
|
|
|
5. **Apply ALL transformations to upstream branch (PRE-MERGE)**:
|
|
- Transform package names (opencode-ai -> @kilocode/cli)
|
|
- Preserve Kilo's versions
|
|
- Transform i18n files with Kilo branding
|
|
- Transform branding-only files (UI components, configs)
|
|
- Transform Tauri/Desktop config files
|
|
- Transform package.json files (names, deps, Kilo injections)
|
|
- Transform script files (GitHub API references)
|
|
- Transform extension files (Zed, etc.)
|
|
- Transform web/docs files
|
|
- Reset Kilo-specific files
|
|
|
|
6. **Merge** transformed upstream into Kilo branch
|
|
- Since all branding transforms are applied pre-merge, conflicts should be minimal
|
|
- Remaining conflicts are files with actual code differences (kilocode_change markers)
|
|
|
|
7. **Auto-resolve** any remaining conflicts
|
|
- Skip files that shouldn't exist in Kilo
|
|
- Keep Kilo's version of specific files
|
|
- Fallback transforms for edge cases
|
|
|
|
8. **Push** and generate final report
|
|
|
|
## Configuration
|
|
|
|
Configuration is defined in `utils/config.ts`:
|
|
|
|
```typescript
|
|
{
|
|
// Package name mappings
|
|
packageMappings: [
|
|
{ from: "opencode-ai", to: "@kilocode/cli" },
|
|
{ from: "@opencode-ai/cli", to: "@kilocode/cli" },
|
|
// ...
|
|
],
|
|
|
|
// Files to always keep Kilo's version (never take upstream)
|
|
keepOurs: [
|
|
"README.md",
|
|
"CONTRIBUTING.md",
|
|
"AGENTS.md",
|
|
".github/workflows/publish.yml", // GitHub workflows - manual review
|
|
// ...
|
|
],
|
|
|
|
// Files to skip entirely (remove from merge)
|
|
skipFiles: [
|
|
"README.*.md", // Translated READMEs
|
|
"STATS.md",
|
|
".github/workflows/update-nix-hashes.yml",
|
|
// ...
|
|
],
|
|
|
|
// Files to take upstream + apply Kilo branding transforms
|
|
takeTheirsAndTransform: [
|
|
"packages/app/src/components/**/*.tsx",
|
|
"packages/app/src/context/**/*.tsx",
|
|
"packages/ui/src/**/*.tsx",
|
|
// ...
|
|
],
|
|
|
|
// Tauri/Desktop config files
|
|
tauriFiles: [
|
|
"packages/desktop/src-tauri/*.json",
|
|
"packages/desktop/src-tauri/src/*.rs",
|
|
// ...
|
|
],
|
|
|
|
// Kilo-specific directories (preserved)
|
|
kiloDirectories: [
|
|
"packages/opencode/src/kilocode",
|
|
"packages/kilo-gateway",
|
|
"packages/kilo-telemetry",
|
|
// ...
|
|
],
|
|
}
|
|
```
|
|
|
|
## Pre-Merge Transformation Strategy
|
|
|
|
**Key insight**: By applying all branding transforms to the upstream branch BEFORE merging, we eliminate most conflicts that would otherwise occur due to branding differences (OpenCode -> Kilo).
|
|
|
|
### Transform Order (Pre-Merge)
|
|
|
|
The following transforms are applied to the opencode branch before merging:
|
|
|
|
1. **Package names** - `opencode-ai` -> `@kilocode/cli`, etc.
|
|
2. **Versions** - Preserve Kilo's version numbers
|
|
3. **i18n files** - OpenCode -> Kilo in user-visible strings
|
|
4. **Branding files** - UI components, configs with branding only
|
|
5. **Tauri configs** - Desktop app identifiers, names
|
|
6. **package.json** - Names, dependencies, Kilo injections
|
|
7. **Scripts** - GitHub API references
|
|
8. **Extensions** - Zed, etc.
|
|
9. **Web/docs** - Documentation files
|
|
|
|
### Post-Merge Strategies
|
|
|
|
After merging, any remaining conflicts are handled based on file type:
|
|
|
|
| File Type | Strategy | Description |
|
|
| ----------------- | ----------------------- | ------------------------------------------------ |
|
|
| i18n files | `i18n-transform` | Take upstream, apply Kilo branding |
|
|
| App components | `take-theirs-transform` | Take upstream, apply branding (no logic changes) |
|
|
| Tauri configs | `tauri-transform` | Take upstream, transform identifiers/names |
|
|
| package.json | `package-transform` | Take upstream, transform names, inject Kilo deps |
|
|
| Script files | `script-transform` | Take upstream, transform GitHub references |
|
|
| Extensions | `extension-transform` | Take upstream, apply branding |
|
|
| Web/docs | `web-transform` | Take upstream, apply branding |
|
|
| README/docs | `keep-ours` | Keep Kilo's version |
|
|
| GitHub workflows | `keep-ours` | Keep Kilo's version (manual review) |
|
|
| Code with markers | `manual` | Has `kilocode_change` markers, needs review |
|
|
|
|
### Why This Reduces Conflicts
|
|
|
|
Previously, conflicts occurred because:
|
|
|
|
- Upstream had `OpenCode` branding
|
|
- Kilo had `Kilo` branding
|
|
- Git saw these as conflicting changes
|
|
|
|
Now:
|
|
|
|
- We transform upstream to `Kilo` branding BEFORE merge
|
|
- Both branches have the same branding
|
|
- Git sees no conflict for branding-only files
|
|
|
|
The only remaining conflicts are files with **actual code differences** - files with `kilocode_change` markers that contain Kilo-specific logic.
|
|
|
|
## CLI Options
|
|
|
|
### merge.ts
|
|
|
|
```
|
|
Options:
|
|
--version <version> Target upstream version (e.g., v1.1.49)
|
|
--commit <hash> Target upstream commit hash
|
|
--base-branch <name> Base branch to merge into (default: dev)
|
|
--dry-run Preview changes without applying them
|
|
--no-push Don't push branches to remote
|
|
--report-only Only generate conflict report
|
|
--verbose Enable verbose logging
|
|
--author <name> Author name for branch prefix
|
|
```
|
|
|
|
### analyze.ts
|
|
|
|
```
|
|
Options:
|
|
--version <version> Target upstream version
|
|
--commit <hash> Target commit hash
|
|
--base-branch <name> Base branch to analyze from (default: dev)
|
|
--output <file> Output file for report
|
|
```
|
|
|
|
## Using Custom Base Branches
|
|
|
|
By default, upstream merges start from the `dev` branch. However, you can use `--base-branch` to start from a different branch. This is useful for:
|
|
|
|
### Incremental Merges
|
|
|
|
When working on multiple upstream versions, you can create a chain of merge PRs:
|
|
|
|
```bash
|
|
# First merge: v1.1.44 into dev
|
|
bun run merge.ts --version v1.1.44
|
|
|
|
# Create PR: catrielmuller/kilo-opencode-v1.1.44 -> dev
|
|
|
|
# Second merge: v1.1.50 based on the previous PR (without waiting for approval)
|
|
bun run merge.ts --version v1.1.50 --base-branch catrielmuller/kilo-opencode-v1.1.44
|
|
|
|
# Create PR: catrielmuller/kilo-opencode-v1.1.50 -> catrielmuller/kilo-opencode-v1.1.44
|
|
# OR: catrielmuller/kilo-opencode-v1.1.50 -> dev (once first PR is merged)
|
|
```
|
|
|
|
### Benefits
|
|
|
|
- **Work in parallel**: Don't wait for PR approval to start the next merge
|
|
- **Isolation**: Each merge is independent and easier to review
|
|
- **Flexibility**: Can adjust the PR chain as needed
|
|
- **Cleaner history**: Related merges can be grouped together
|
|
|
|
### Example Workflow
|
|
|
|
```bash
|
|
# 1. Analyze next version from your WIP branch
|
|
bun run analyze.ts --version v1.1.50 --base-branch catrielmuller/kilo-opencode-v1.1.44
|
|
|
|
# 2. Run the merge
|
|
bun run merge.ts --version v1.1.50 --base-branch catrielmuller/kilo-opencode-v1.1.44
|
|
|
|
# 3. Create PR from catrielmuller/kilo-opencode-v1.1.50
|
|
# - Target: catrielmuller/kilo-opencode-v1.1.44 (if first PR not merged yet)
|
|
# - Target: dev (if first PR is already merged)
|
|
```
|
|
|
|
## Manual Conflict Resolution
|
|
|
|
After running the merge script, you may have remaining conflicts. To resolve:
|
|
|
|
1. Open each conflicted file
|
|
2. Look for `kilocode_change` markers to identify Kilo-specific code
|
|
3. Resolve conflicts, keeping Kilo-specific changes
|
|
4. Stage and commit:
|
|
```bash
|
|
git add -A
|
|
git commit -m "resolve merge conflicts"
|
|
```
|
|
|
|
## Rollback
|
|
|
|
If something goes wrong:
|
|
|
|
```bash
|
|
# Find your backup branch
|
|
git branch | grep backup
|
|
|
|
# Reset to backup
|
|
git checkout dev
|
|
git reset --hard backup/dev-<timestamp>
|
|
```
|
|
|
|
## Adding New Transformations
|
|
|
|
### String-based (simple)
|
|
|
|
Edit `transforms/package-names.ts` and add patterns to `PACKAGE_PATTERNS`.
|
|
|
|
### AST-based (robust)
|
|
|
|
1. Create a new file in `codemods/`
|
|
2. Use ts-morph for TypeScript AST manipulation
|
|
3. Export transform functions
|
|
4. Add to the merge orchestration if needed
|
|
|
|
## Troubleshooting
|
|
|
|
### "No upstream remote found"
|
|
|
|
```bash
|
|
git remote add upstream git@github.com:anomalyco/opencode.git
|
|
```
|
|
|
|
### "Working directory has uncommitted changes"
|
|
|
|
```bash
|
|
git stash
|
|
# or
|
|
git commit -am "WIP"
|
|
```
|
|
|
|
### Merge conflicts after auto-resolution
|
|
|
|
Some files require manual review. Check the generated report for guidance.
|