Files
Kilo-Org_kilocode/script/sync-versions.ts
2026-05-05 13:45:44 +00:00

99 lines
3.6 KiB
TypeScript
Executable File

#!/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
// 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)`)