From 6a989dc6bcc3e63d6876805264582b844cba9f02 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 13:43:54 +0000 Subject: [PATCH 1/2] chore: add sync-versions script for upstream merges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream opencode stamps its own version into shared files (the Zed extension toml + any package.json it bumps), which leaves the tree pointing at an upstream release tag that doesn't exist on Kilo's pipeline — Zed download URLs silently 404 as a result. script/sync-versions.ts rewrites every top-level package.json version and the Zed extension toml (version + 5 download URLs) to a single target in one shot. Defaults to the root package.json version, accepts an explicit version argument, and skips packages/kilo-jetbrains/ which tracks its own cadence. Documented in .kilo/command/upstream-manual-merge.md as a dedicated step-10 commit after 'resolve merge conflicts' so version churn stays out of the behavioural merge commit. --- .kilo/command/upstream-manual-merge.md | 31 +++++++- script/sync-versions.ts | 97 ++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100755 script/sync-versions.ts diff --git a/.kilo/command/upstream-manual-merge.md b/.kilo/command/upstream-manual-merge.md index e17e647b5e9..cebc4045353 100644 --- a/.kilo/command/upstream-manual-merge.md +++ b/.kilo/command/upstream-manual-merge.md @@ -189,7 +189,36 @@ git commit -m "resolve merge conflicts" The default `git merge` auto-message (`Merge branch '…' into …`) is also fine, but `resolve merge conflicts` is the convention for these PRs. -### 10. Write the PR body +### 10. Resync version strings in a separate commit + +Upstream stamps its own version into shared files — notably +`packages/extensions/zed/extension.toml` (version field + 5 Kilo-Org download +URLs), and any `package.json` that upstream bumped in the same release window. +After the merge this leaves parts of the tree pointing at upstream's version +(e.g. `1.14.30`), whose release tag does not exist on Kilo's pipeline, so the +Zed download URLs silently 404. + +Fix this in a dedicated commit *after* `resolve merge conflicts`: + +```bash +bun run script/sync-versions.ts # uses root package.json version +# or, to target an explicit version: +bun run script/sync-versions.ts 7.2.41 +git add -A +git commit -m "chore: resync versions after upstream merge" +``` + +The script rewrites every top-level `"version"` in `package.json` files +(excluding `node_modules`, hidden dirs, and `packages/kilo-jetbrains/` which +tracks its own cadence), plus the Zed extension toml. It is idempotent — rerun +it any time to rebase the version back onto Kilo main (useful during +long-running upstream merges where `main` releases in the meantime). + +Keeping this in its own commit makes reviewers' job easier: the merge commit +only contains behavioural resolutions, and the version resync is a trivial +diff they can skim in one glance. + +### 11. Write the PR body Structure the description so reviewers can skim: diff --git a/script/sync-versions.ts b/script/sync-versions.ts new file mode 100755 index 00000000000..5a69c9942f7 --- /dev/null +++ b/script/sync-versions.ts @@ -0,0 +1,97 @@ +#!/usr/bin/env bun +// Sync every Kilo version string across the monorepo to a single target. +// +// Why this exists: upstream opencode stamps its own version into shared files +// during each release (notably `packages/extensions/zed/extension.toml`). When +// we merge upstream, that churn either produces conflicts or silently leaves +// our packages pointing at upstream's version — and upstream's version tag +// doesn't exist on our release pipeline, so the resulting download URLs 404. +// +// Run this in a dedicated commit after resolving an upstream merge (see +// `.kilo/command/upstream-manual-merge.md`). It's also handy mid-merge to +// rebase our version bumps onto any new Kilo main releases. +// +// Usage: +// bun run script/sync-versions.ts # use root package.json version +// bun run script/sync-versions.ts 7.2.41 # explicit target +// bun run script/sync-versions.ts v7.2.41 # leading `v` is stripped +// +// What gets updated: +// - every `package.json` top-level `"version": "..."` field in the repo +// (excluding node_modules and hidden directories) +// - `packages/extensions/zed/extension.toml` top-level `version = "..."` +// - the five Kilo-Org download URLs inside that toml +// +// Intentionally NOT touched: +// - `packages/kilo-jetbrains/**` — the JetBrains plugin has its own release +// cadence and version number. +// - dependency version strings inside `package.json` — internal deps use +// `workspace:*` so they don't need bumping. + +import { Glob } from "bun" +import { join, relative } from "node:path" + +const root = join(import.meta.dir, "..") + +const arg = process.argv[2] +const target = await (async () => { + if (arg) return arg.replace(/^v/, "") + const pkg = await Bun.file(join(root, "package.json")).json() + return pkg.version as string +})() + +if (!/^\d+\.\d+\.\d+([-+].+)?$/.test(target)) { + console.error(`error: invalid version "${target}"`) + process.exit(1) +} + +console.log(`syncing versions → ${target}\n`) + +let updated = 0 + +const glob = new Glob("**/package.json") +for await (const rel of glob.scan({ cwd: root, onlyFiles: true })) { + if (rel.includes("node_modules/")) continue + if (rel.startsWith(".")) continue + if (rel.includes("/.")) continue + // JetBrains plugin tracks its own version. + if (rel.startsWith("packages/kilo-jetbrains/")) continue + + const path = join(root, rel) + const text = await Bun.file(path).text() + + // Only rewrite the top-level version field — avoid touching nested + // dependency version fields or versions inside sub-strings. The first + // `"version"` key at 2-space indentation is always the package version in + // this repo's style. + const next = text.replace(/^(\s*)"version":\s*"[^"]+"(,?)/m, (_m, indent, comma) => { + return `${indent}"version": "${target}"${comma}` + }) + + if (next === text) continue + // Defensive: the replace above runs unconditionally on any match — skip if + // the file had no `"version"` key at all. + if (!/"version"\s*:/.test(text)) continue + + await Bun.write(path, next) + console.log(` ${rel}`) + updated++ +} + +const zed = join(root, "packages/extensions/zed/extension.toml") +if (await Bun.file(zed).exists()) { + const text = await Bun.file(zed).text() + const next = text + .replace(/^version\s*=\s*"[^"]+"/m, `version = "${target}"`) + .replace( + /https:\/\/github\.com\/Kilo-Org\/kilocode\/releases\/download\/v[^/]+\//g, + `https://github.com/Kilo-Org/kilocode/releases/download/v${target}/`, + ) + if (next !== text) { + await Bun.write(zed, next) + console.log(` ${relative(root, zed)}`) + updated++ + } +} + +console.log(`\nupdated ${updated} file(s)`) From 3618565040b869533242245aad2f625c9536cfd5 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 13:45:44 +0000 Subject: [PATCH 2/2] chore: annotate sync-versions.ts as kilocode new file --- script/sync-versions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/script/sync-versions.ts b/script/sync-versions.ts index 5a69c9942f7..0d77d506467 100755 --- a/script/sync-versions.ts +++ b/script/sync-versions.ts @@ -1,4 +1,5 @@ #!/usr/bin/env bun +// kilocode_change - new file // Sync every Kilo version string across the monorepo to a single target. // // Why this exists: upstream opencode stamps its own version into shared files