script/upstream/README.md
Scripts for automating the merge of upstream opencode changes into Kilo.
# 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
| Script | Description |
|---|---|
merge.ts | Main orchestration script for upstream merges |
list-versions.ts | List available upstream versions |
analyze.ts | Analyze changes without merging |
fix-kilocode-markers.ts | Rebuild kilocode_change markers for one file against the last merged upstream |
| 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-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) |
| Script | Description |
|---|---|
codemods/transform-imports.ts | Transform import statements using ts-morph |
codemods/transform-strings.ts | Transform string literals |
The merge automation follows this process, applying all transformations BEFORE the merge to minimize conflicts:
Validate environment
Fetch upstream and determine target version
Generate conflict report analyzing which files will conflict
Create branches
backup/<branch>-<timestamp> - Backup of current state<author>/kilo-opencode-<version> - Merge target branch<author>/opencode-<version> - Transformed upstream branchApply ALL transformations to upstream branch (PRE-MERGE):
skipFiles)Merge transformed upstream into Kilo branch
Auto-resolve any remaining conflicts
Push and generate final report
Configuration is defined in utils/config.ts:
{
// 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/ui/src/**/*.tsx",
// ...
],
// Kilo-specific directories (preserved)
kiloDirectories: [
"packages/opencode/src/kilocode",
"packages/kilo-gateway",
"packages/kilo-telemetry",
// ...
],
}
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).
The following transforms are applied to the opencode branch before merging:
opencode-ai -> @kilocode/cli, etc.After merging, any remaining conflicts are handled based on file type:
| File Type | Strategy | Description |
|---|---|---|
| i18n files | i18n-transform | Take upstream, apply Kilo branding |
| UI components | take-theirs-transform | Take upstream, apply branding (no logic changes) |
| 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 |
Previously, conflicts occurred because:
OpenCode brandingKilo brandingNow:
Kilo branding BEFORE mergeThe only remaining conflicts are files with actual code differences - files with kilocode_change markers that contain Kilo-specific logic.
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: main)
--dry-run Preview changes without applying them
--no-push Don't push branches to remote
--no-worktrees Don't create reference worktrees
--report-only Only generate conflict report
--verbose Enable verbose logging
--author <name> Author name for branch prefix
By default, merge.ts also prepares prompt-friendly reference worktrees under .worktrees/opencode-merge/:
| Path | Snapshot |
|---|---|
.worktrees/opencode-merge/opencode | Pristine upstream opencode at the requested version or commit |
.worktrees/opencode-merge/kilo-main | The Kilo base branch snapshot used for the merge |
.worktrees/opencode-merge/auto-merge | The automated merge result before final lockfile or SDK regeneration |
If conflicts remain after automation, auto-merge is a committed local snapshot branch that may intentionally contain conflict markers as normal file content. The real merge branch remains unresolved so manual resolution can continue with accurate git conflict state.
Options:
--version <version> Target upstream version
--commit <hash> Target commit hash
--base-branch <name> Base branch to analyze from (default: main)
--output <file> Output file for report
Usage:
bun run script/upstream/fix-kilocode-markers.ts <repo-relative-file> [--dry-run]
Options:
--dry-run Show what would change without writing the file
The command finds the newest upstream tag already merged into HEAD, reads that upstream version of the file, applies the same branding transforms used by upstream merge automation, strips existing kilocode_change markers from the current file, and adds fresh markers around the remaining lines that differ from upstream.
By default, upstream merges start from the main branch. However, you can use --base-branch to start from a different branch. This is useful for:
When working on multiple upstream versions, you can create a chain of merge PRs:
# First merge: v1.1.44 into main
bun run merge.ts --version v1.1.44
# Create PR: catrielmuller/kilo-opencode-v1.1.44 -> main
# 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 -> main (once first PR is merged)
# 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: main (if first PR is already merged)
After running the merge script, you may have remaining conflicts. To resolve:
kilocode_change markers to identify Kilo-specific codegit add -A
git commit -m "resolve merge conflicts"
If something goes wrong:
# Find your backup branch
git branch | grep backup
# Reset to backup
git checkout main
git reset --hard backup/main-<timestamp>
Edit transforms/package-names.ts and add patterns to PACKAGE_PATTERNS.
codemods/git remote add upstream [email protected]:anomalyco/opencode.git
git stash
# or
git commit -am "WIP"
Some files require manual review. Check the generated report for guidance.