mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 11:05:31 +08:00
docs(jetbrains): add CLI pin release helpers
This commit is contained in:
@@ -38,44 +38,67 @@ Show the resolved `version`, `kind`, and default `fromTagDefault` to the user.
|
||||
|
||||
## CLI Pin Verification
|
||||
|
||||
Before dispatching prepare, verify the JetBrains plugin is pinned to the intended Kilo Core release. The plugin downloads the CLI version from `packages/kilo-jetbrains/package.json`, not from the JetBrains plugin version.
|
||||
Before dispatching prepare, verify the JetBrains plugin is pinned to the intended Kilo Core release. The plugin downloads the CLI version from `packages/kilo-jetbrains/package.json`, not from the JetBrains plugin version. Prepare tags `origin/main`, so the authoritative pin is the value on `origin/main`, not a local edit.
|
||||
|
||||
Verify repo CLI dev mode is disabled on `main` before creating the immutable tag:
|
||||
Run the pin preflight:
|
||||
|
||||
```bash
|
||||
git show origin/main:packages/kilo-jetbrains/gradle.properties | grep '^kilo.cli.pinned=' || true
|
||||
bun .kilo/skills/release-jetbrains/script/check-pin.ts
|
||||
```
|
||||
|
||||
If `kilo.cli.pinned` is present and is not `true`, stop and ask the user to reset it to `true` on `main` before dispatching prepare. `kilo.cli.pinned=false` generates from and bundles the local repo CLI, so it is dev-only and non-releasable.
|
||||
The script prints:
|
||||
|
||||
Read the pinned CLI version:
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| `pinMain` | CLI version that `origin/main` will lock into the release tag. |
|
||||
| `pinLocal` | CLI version in the current worktree, useful for catching stale local checkouts. |
|
||||
| `latestCli` | Latest stable `v*` Kilo CLI GitHub release. |
|
||||
| `prevJetbrainsCli` | CLI pin used by the latest `jetbrains/v*` release tag, for reviewing the jump. |
|
||||
| `pinnedMain` / `pinnedLocal` | Whether `kilo.cli.pinned=true`; `false` means repo CLI dev mode. |
|
||||
| `assetsOk` / `missingAssets` | Whether the pinned CLI release has every runtime asset. |
|
||||
| `drift` | `up-to-date`, `behind`, `worktree-behind-main`, `repo-mode-on-main`, `repo-mode-local`, or `assets-missing`. |
|
||||
|
||||
Interpretation:
|
||||
|
||||
| Drift | Action |
|
||||
|---|---|
|
||||
| `up-to-date` | Continue after user confirmation. |
|
||||
| `behind` | Stop and show `pinMain`, `latestCli`, and `prevJetbrainsCli`; ask whether to cancel, bump + test, or proceed anyway. |
|
||||
| `worktree-behind-main` | Explain that prepare tags `origin/main`; refresh the worktree or rely on `pinMain` in the confirmation. |
|
||||
| `repo-mode-on-main` | Stop. `kilo.cli.pinned=false` is dev-only and must be reset to `true` on `main` before release. |
|
||||
| `repo-mode-local` | Stop or reset local `kilo.cli.pinned=true`; release checks should run from a releasable local state. |
|
||||
| `assets-missing` | Stop. The pinned CLI release is incomplete and would fail runtime download. |
|
||||
|
||||
Show the resolved JetBrains plugin version, release kind, default `fromTagDefault`, `pinMain`, `latestCli`, `prevJetbrainsCli`, and `assetsOk` to the user, then ask for confirmation before continuing. If the user wants a different CLI pin, use the bump workflow below and do not dispatch prepare until the bump is merged to `main`.
|
||||
|
||||
## Bump the CLI Pin
|
||||
|
||||
Use this only when the user wants to test or release with a different CLI than `origin/main` currently pins. The helper refuses versions whose GitHub release or runtime assets are missing.
|
||||
|
||||
Local test edit only:
|
||||
|
||||
```bash
|
||||
bun -e 'const p=require("./packages/kilo-jetbrains/package.json"); console.log(p.version)'
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest
|
||||
# or
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --version 7.4.1
|
||||
```
|
||||
|
||||
Verify the matching GitHub Release exists and includes every runtime asset the backend may download:
|
||||
Then test from `packages/kilo-jetbrains/`:
|
||||
|
||||
```bash
|
||||
cli_version="7.4.1"
|
||||
gh release view "v${cli_version}" --repo Kilo-Org/kilocode --json assets \
|
||||
--jq '.assets[].name' | sort
|
||||
./gradlew typecheck
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
Expected assets:
|
||||
If the user confirms the tested pin should be released, open or update a pin bump PR to `main`:
|
||||
|
||||
```text
|
||||
kilo-darwin-arm64.zip
|
||||
kilo-darwin-x64.zip
|
||||
kilo-linux-arm64.tar.gz
|
||||
kilo-linux-x64.tar.gz
|
||||
kilo-windows-arm64.zip
|
||||
kilo-windows-x64.zip
|
||||
```bash
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest --pr
|
||||
# or
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --version 7.4.1 --pr
|
||||
```
|
||||
|
||||
If the pin is stale or the release assets are missing, stop and ask the user to update `packages/kilo-jetbrains/package.json` on `main` before dispatching prepare. The prepare workflow tags `origin/main`, so the pin must already be reviewed and merged before the release tag is created.
|
||||
|
||||
Show the resolved JetBrains plugin version, release kind, default `fromTagDefault`, `kilo.cli.pinned` status, pinned CLI version, and CLI release asset status to the user, then ask for confirmation before continuing.
|
||||
After that PR merges to `main`, re-run `resolve-version.ts`, re-run `check-pin.ts`, confirm `drift=up-to-date`, then dispatch prepare. Do not dispatch prepare from a local-only pin edit; the prepare workflow tags `origin/main`.
|
||||
|
||||
## Prepare Workflow
|
||||
|
||||
@@ -208,6 +231,7 @@ Report the Marketplace channel and GitHub Release URL. RC versions publish to th
|
||||
|
||||
- If prepare created the tag but failed before creating a PR, rerun prepare for the same version. The existing workflow reuses the tag if it points to the same commit.
|
||||
- If a tag points to an unexpected SHA, stop and inspect manually. Do not move or delete release tags casually.
|
||||
- If prepare tagged an unintended CLI pin, do not move the tag. Land the intended pin on `main`, resolve the next JetBrains version, and create a new release tag.
|
||||
- If release PR checks fail from an apparent flake, use `gh run rerun <run-id> --failed`, then `gh run watch <run-id> --exit-status` before publishing.
|
||||
- If publish fails after merge, rerun the failed workflow only if Marketplace did not already accept the version.
|
||||
- If Marketplace succeeds but GitHub Release upload fails, manually create or edit the GitHub Release for `jetbrains/v<version>` using the reviewed changelog.
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import { $ } from "bun"
|
||||
import semver from "semver"
|
||||
import { parseArgs } from "util"
|
||||
|
||||
const repo = process.env.GH_REPO ?? process.env.GITHUB_REPOSITORY ?? "Kilo-Org/kilocode"
|
||||
const asset = [
|
||||
"kilo-darwin-arm64.zip",
|
||||
"kilo-darwin-x64.zip",
|
||||
"kilo-linux-arm64.tar.gz",
|
||||
"kilo-linux-x64.tar.gz",
|
||||
"kilo-windows-arm64.zip",
|
||||
"kilo-windows-x64.zip",
|
||||
]
|
||||
|
||||
const { values } = parseArgs({
|
||||
args: Bun.argv.slice(2),
|
||||
options: {
|
||||
help: { type: "boolean", short: "h", default: false },
|
||||
},
|
||||
})
|
||||
|
||||
if (values.help) {
|
||||
console.log(`
|
||||
Usage: bun .kilo/skills/release-jetbrains/script/check-pin.ts
|
||||
|
||||
Checks the CLI pin that a JetBrains release would lock. Prepare tags origin/main,
|
||||
so this reads packages/kilo-jetbrains/package.json from origin/main and compares
|
||||
it with the latest published Kilo CLI release plus the local worktree pin.
|
||||
|
||||
Exit codes:
|
||||
0 Pin is release-ready.
|
||||
2 Pin drift, repo CLI mode, or missing CLI assets require maintainer review.
|
||||
`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
await $`git fetch origin main --tags`.quiet()
|
||||
|
||||
const pinMain = JSON.parse(await $`git show origin/main:packages/kilo-jetbrains/package.json`.text()).version as string
|
||||
const pinLocal = (await Bun.file("packages/kilo-jetbrains/package.json").json()).version as string
|
||||
const propsMain = await $`git show origin/main:packages/kilo-jetbrains/gradle.properties`.text()
|
||||
const propsLocal = await Bun.file("packages/kilo-jetbrains/gradle.properties").text()
|
||||
const pinnedMain = pinned(propsMain)
|
||||
const pinnedLocal = pinned(propsLocal)
|
||||
const latestCli = await latest()
|
||||
const prevJetbrainsCli = await previous()
|
||||
const missingAssets = await missing(pinMain)
|
||||
const assetsOk = missingAssets.length === 0
|
||||
const drift = (() => {
|
||||
if (!pinnedMain) return "repo-mode-on-main"
|
||||
if (!pinnedLocal) return "repo-mode-local"
|
||||
if (pinLocal !== pinMain) return "worktree-behind-main"
|
||||
if (!assetsOk) return "assets-missing"
|
||||
if (latestCli && semver.lt(pinMain, latestCli)) return "behind"
|
||||
return "up-to-date"
|
||||
})()
|
||||
|
||||
console.log(JSON.stringify({
|
||||
pinMain,
|
||||
pinLocal,
|
||||
latestCli,
|
||||
prevJetbrainsCli,
|
||||
pinnedMain,
|
||||
pinnedLocal,
|
||||
assetsOk,
|
||||
missingAssets,
|
||||
drift,
|
||||
}, null, 2))
|
||||
|
||||
if (drift !== "up-to-date") process.exit(2)
|
||||
|
||||
async function latest() {
|
||||
const list = (await $`gh release list --repo ${repo} --limit 100 --json tagName,isDraft,isPrerelease`.json()) as {
|
||||
tagName: string
|
||||
isDraft: boolean
|
||||
isPrerelease: boolean
|
||||
}[]
|
||||
return list
|
||||
.filter((item) => /^v\d+\.\d+\.\d+$/.test(item.tagName) && !item.isDraft && !item.isPrerelease)
|
||||
.map((item) => item.tagName.slice(1))
|
||||
.sort(semver.rcompare)[0] ?? null
|
||||
}
|
||||
|
||||
async function previous() {
|
||||
const text = await $`git tag --list ${"jetbrains/v*"}`.text()
|
||||
const tag = text
|
||||
.split(/\r?\n/)
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean)
|
||||
.map((tag) => ({ tag, version: tag.replace(/^jetbrains\/v/, "") }))
|
||||
.filter((item) => semver.valid(item.version))
|
||||
.sort((a, b) => semver.rcompare(a.version, b.version))[0]?.tag
|
||||
if (!tag) return null
|
||||
const res = await $`git show ${tag}:packages/kilo-jetbrains/package.json`.nothrow().text()
|
||||
if (!res.trim()) return null
|
||||
return JSON.parse(res).version as string
|
||||
}
|
||||
|
||||
async function missing(version: string) {
|
||||
const res = await $`gh release view ${`v${version}`} --repo ${repo} --json assets --jq ${".assets[].name"}`.quiet().nothrow()
|
||||
if (res.exitCode !== 0) return asset
|
||||
const names = res.stdout.toString().split(/\r?\n/).map((item) => item.trim()).filter(Boolean)
|
||||
return asset.filter((item) => !names.includes(item))
|
||||
}
|
||||
|
||||
function pinned(text: string) {
|
||||
const line = text.split(/\r?\n/).find((item) => item.startsWith("kilo.cli.pinned="))
|
||||
const value = line?.split("=", 2)[1]?.trim().toLowerCase()
|
||||
return value == null || value === "true"
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import { $ } from "bun"
|
||||
import semver from "semver"
|
||||
import { parseArgs } from "util"
|
||||
|
||||
const repo = process.env.GH_REPO ?? process.env.GITHUB_REPOSITORY ?? "Kilo-Org/kilocode"
|
||||
const file = "packages/kilo-jetbrains/package.json"
|
||||
const asset = [
|
||||
"kilo-darwin-arm64.zip",
|
||||
"kilo-darwin-x64.zip",
|
||||
"kilo-linux-arm64.tar.gz",
|
||||
"kilo-linux-x64.tar.gz",
|
||||
"kilo-windows-arm64.zip",
|
||||
"kilo-windows-x64.zip",
|
||||
]
|
||||
|
||||
const { values } = parseArgs({
|
||||
args: Bun.argv.slice(2),
|
||||
options: {
|
||||
version: { type: "string" },
|
||||
latest: { type: "boolean", default: false },
|
||||
pr: { type: "boolean", default: false },
|
||||
help: { type: "boolean", short: "h", default: false },
|
||||
},
|
||||
})
|
||||
|
||||
if (values.help) {
|
||||
console.log(`
|
||||
Usage: bun .kilo/skills/release-jetbrains/script/set-pin.ts (--latest | --version <x.y.z>) [--pr]
|
||||
|
||||
Without --pr, rewrites ${file} in the local worktree so you can test a CLI pin.
|
||||
With --pr, opens or updates a PR against main using the GitHub API; prepare tags
|
||||
origin/main, so the pin bump must merge there before a JetBrains release starts.
|
||||
|
||||
Examples:
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --version 7.4.1
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest --pr
|
||||
`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
if (values.latest && values.version) throw new Error("Pass either --latest or --version, not both")
|
||||
const version = values.latest ? await latest() : values.version?.replace(/^v/, "")
|
||||
if (!version || !semver.valid(version) || semver.prerelease(version)) {
|
||||
throw new Error("Pass a stable CLI version with --version x.y.z or use --latest")
|
||||
}
|
||||
|
||||
const miss = await missing(version)
|
||||
if (miss.length > 0) {
|
||||
throw new Error(`CLI release v${version} is missing required assets: ${miss.join(", ")}`)
|
||||
}
|
||||
|
||||
if (values.pr) {
|
||||
await pr(version)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const pkg = await Bun.file(file).json()
|
||||
const previous = pkg.version as string
|
||||
pkg.version = version
|
||||
await Bun.write(file, `${JSON.stringify(pkg, null, 2)}\n`)
|
||||
if (previous === version) {
|
||||
console.log(`${file} already pins CLI v${version}`)
|
||||
} else {
|
||||
console.log(`Pinned JetBrains CLI ${previous} -> ${version} in ${file}`)
|
||||
}
|
||||
console.log("Test locally with: cd packages/kilo-jetbrains && ./gradlew typecheck && ./gradlew test")
|
||||
console.log("When satisfied, run this script again with --pr so the bump lands on main before prepare tags it.")
|
||||
|
||||
async function pr(version: string) {
|
||||
await $`git fetch origin main`.quiet()
|
||||
const branch = `chore/jetbrains-cli-pin-v${version}`
|
||||
const main = (await $`git rev-parse origin/main`.text()).trim()
|
||||
const text = await $`git show origin/main:${file}`.text()
|
||||
const pkg = JSON.parse(text)
|
||||
const previous = pkg.version as string
|
||||
if (previous === version) {
|
||||
console.log(`origin/main already pins CLI v${version}; no PR needed.`)
|
||||
return
|
||||
}
|
||||
pkg.version = version
|
||||
const body = `${JSON.stringify(pkg, null, 2)}\n`
|
||||
await ensure(branch, main)
|
||||
const current = (await $`gh api ${`repos/${repo}/contents/${file}?ref=${branch}`}`.json()) as { sha: string }
|
||||
await $`gh api --method PUT ${`repos/${repo}/contents/${file}`} -f message=${`chore(jetbrains): bump CLI pin to v${version}`} -f content=${Buffer.from(body).toString("base64")} -f branch=${branch} -f sha=${current.sha}`.quiet()
|
||||
|
||||
const title = `chore(jetbrains): bump CLI pin to v${version}`
|
||||
const desc = [
|
||||
`Bumps the JetBrains CLI pin from v${previous} to v${version}.`,
|
||||
"",
|
||||
"Prepare tags origin/main, so this PR must merge before dispatching a JetBrains release that should lock this CLI.",
|
||||
"",
|
||||
"After merging, re-run:",
|
||||
"",
|
||||
"```bash",
|
||||
"bun .kilo/skills/release-jetbrains/script/check-pin.ts",
|
||||
"```",
|
||||
].join("\n")
|
||||
const view = await $`gh pr view ${branch} --repo ${repo} --json url --jq .url`.quiet().nothrow()
|
||||
if (view.exitCode === 0 && view.stdout.toString().trim()) {
|
||||
await $`gh pr edit ${branch} --repo ${repo} --title ${title} --body ${desc}`
|
||||
console.log(view.stdout.toString().trim())
|
||||
return
|
||||
}
|
||||
const url = await $`gh pr create --repo ${repo} --base main --head ${branch} --title ${title} --body ${desc}`.text()
|
||||
console.log(url.trim())
|
||||
}
|
||||
|
||||
async function latest() {
|
||||
const list = (await $`gh release list --repo ${repo} --limit 100 --json tagName,isDraft,isPrerelease`.json()) as {
|
||||
tagName: string
|
||||
isDraft: boolean
|
||||
isPrerelease: boolean
|
||||
}[]
|
||||
const version = list
|
||||
.filter((item) => /^v\d+\.\d+\.\d+$/.test(item.tagName) && !item.isDraft && !item.isPrerelease)
|
||||
.map((item) => item.tagName.slice(1))
|
||||
.sort(semver.rcompare)[0]
|
||||
if (!version) throw new Error(`No stable CLI release found in ${repo}`)
|
||||
return version
|
||||
}
|
||||
|
||||
async function missing(version: string) {
|
||||
const res = await $`gh release view ${`v${version}`} --repo ${repo} --json assets --jq ${".assets[].name"}`.quiet().nothrow()
|
||||
if (res.exitCode !== 0) return asset
|
||||
const names = res.stdout.toString().split(/\r?\n/).map((item) => item.trim()).filter(Boolean)
|
||||
return asset.filter((item) => !names.includes(item))
|
||||
}
|
||||
|
||||
async function ensure(branch: string, sha: string) {
|
||||
const ref = `repos/${repo}/git/refs/heads/${branch}`
|
||||
const exists = await $`gh api ${ref}`.nothrow().quiet()
|
||||
if (exists.exitCode === 0) {
|
||||
await $`gh api --method PATCH ${ref} -f sha=${sha} -F force=true`.quiet()
|
||||
return
|
||||
}
|
||||
await $`gh api --method POST ${`repos/${repo}/git/refs`} -f ref=${`refs/heads/${branch}`} -f sha=${sha}`.quiet()
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
- Service classes ↔ `<applicationService>`/`<projectService>` entries in the corresponding module XML
|
||||
- `packages/kilo-jetbrains/package.json` version ↔ GitHub CLI release tag consumed by the backend downloader
|
||||
- `packages/kilo-jetbrains/gradle.properties` `kilo.cli.pinned` ↔ Gradle and release-script gates
|
||||
- `.kilo/skills/release-jetbrains/script/check-pin.ts` / `set-pin.ts` ↔ release skill and CLI pin documentation
|
||||
|
||||
## IntelliJ Platform Source Lookup
|
||||
|
||||
@@ -156,9 +157,7 @@ For blocking I/O in coroutines, move the dispatcher switch inside the callee usi
|
||||
|
||||
- CLI process spawning, download, extraction, and lifecycle belong in `backend`.
|
||||
- By default, the plugin does not bundle CLI binaries. At connect time the backend downloads the GitHub Release asset for the version pinned in `packages/kilo-jetbrains/package.json`; `backend` resources include `kilo.properties` with `cli.version` and `cli.pinned` for split-mode RPC and runtime use.
|
||||
- `kilo.cli.pinned=false` in `gradle.properties` is dev-only repo CLI mode: OpenAPI generation runs `bun run --conditions=browser ./src/index.ts generate` from `packages/opencode/`, and runtime extracts a staged local CLI resource instead of downloading.
|
||||
- Repo CLI mode requires a local CLI build. Run `./gradlew :backend:buildRepoCli` from `packages/kilo-jetbrains/` or `bun run script/build.ts --single --skip-install` from `packages/opencode/`, then let `:backend:stageRepoCli` bundle the full `dist/@kilocode/cli-<os>-<arch>/bin/` directory.
|
||||
- Production builds must keep `kilo.cli.pinned=true`; Gradle release mode, release scripts, and `script/build-version.sh` reject repo CLI mode.
|
||||
- For release questions, use the `release-jetbrains` skill and reference `.kilo/skills/release-jetbrains/SKILL.md`; it verifies the CLI pin before creating immutable `jetbrains/v*` tags.
|
||||
- For OS and environment checks, prefer IntelliJ Platform classes over raw JVM APIs such as `System.getProperty(...)` or `System.getenv(...)`.
|
||||
- Detect architecture with `com.intellij.util.system.CpuArch.CURRENT`, not `System.getProperty("os.arch")`.
|
||||
- Detect OS with `com.intellij.openapi.util.SystemInfo.isMac` / `isLinux` / `isWindows`.
|
||||
@@ -166,6 +165,31 @@ For blocking I/O in coroutines, move the dispatcher switch inside the callee usi
|
||||
- Resolve IDE paths with `com.intellij.openapi.application.PathManager` rather than inferring paths from process working directories.
|
||||
- For packaging/build plumbing, see `script/build.ts` and `backend/build.gradle.kts`.
|
||||
|
||||
### CLI Pinning, Unpinning, and Bumping
|
||||
|
||||
The JetBrains plugin has two independent CLI controls. Use the commands below directly when asked to change either one; do not hand-edit versions by guesswork.
|
||||
|
||||
**Pin mode** (`kilo.cli.pinned` in `packages/kilo-jetbrains/gradle.properties`) controls release CLI vs local repo CLI.
|
||||
|
||||
| Ask | Do |
|
||||
|---|---|
|
||||
| Unpin / use local repo CLI | Set `kilo.cli.pinned=false`, then run `./gradlew :backend:buildRepoCli` from `packages/kilo-jetbrains/`. `:backend:stageRepoCli` bundles `packages/opencode/dist/@kilocode/cli-<os>-<arch>/bin/`; runtime extracts it instead of downloading. |
|
||||
| Re-pin / use release CLI | Set `kilo.cli.pinned=true`. This is the default and the only releasable state. |
|
||||
|
||||
`kilo.cli.pinned=false` is dev-only: OpenAPI generation runs from local `packages/opencode/` source and the local binary is bundled. Production Gradle builds, `script/build-version.sh`, and the release scripts hard-fail on `false`, so restore `true` before releasing.
|
||||
|
||||
**Pinned CLI version** (`packages/kilo-jetbrains/package.json` `version`) controls which GitHub CLI release the plugin downloads and generates the client from. The JetBrains release locks the value already merged to `origin/main`.
|
||||
|
||||
| Ask | Do |
|
||||
|---|---|
|
||||
| Check whether the CLI pin is current | `bun .kilo/skills/release-jetbrains/script/check-pin.ts` |
|
||||
| Bump the pin to `<version>` / latest and test locally | `bun .kilo/skills/release-jetbrains/script/set-pin.ts --version <x.y.z>` or `bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest`, then run `./gradlew typecheck && ./gradlew test` from `packages/kilo-jetbrains/`. |
|
||||
| Land a tested pin bump for release | `bun .kilo/skills/release-jetbrains/script/set-pin.ts --version <x.y.z> --pr` or `bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest --pr`; merge the PR to `main`, then re-run `check-pin.ts` before dispatching prepare. |
|
||||
|
||||
`set-pin.ts` refuses versions whose CLI release or runtime assets do not exist, so it cannot create a pin that would 404 during runtime download.
|
||||
|
||||
For the full release process (resolve version, pin verification, prepare, changelog, publish), load the `release-jetbrains` skill: `.kilo/skills/release-jetbrains/SKILL.md`.
|
||||
|
||||
### Server Protocol
|
||||
|
||||
- The plugin spawns `kilo serve --port 0` (OS assigns random port) and reads stdout for `listening on http://...:(\d+)` to discover the port.
|
||||
|
||||
@@ -14,6 +14,40 @@ JetBrains plugin builds and runtime downloads use the Kilo Core version pinned i
|
||||
|
||||
The skill lives at `.kilo/skills/release-jetbrains/SKILL.md`. It does not move or recreate release tags, and merge permission is only required if the user explicitly asks the skill to merge the release PR automatically.
|
||||
|
||||
## CLI Pin Review
|
||||
|
||||
The JetBrains plugin has two independent versions:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| `packages/kilo-jetbrains/package.json` `version` | The pinned Kilo CLI release used for OpenAPI generation and runtime downloads. |
|
||||
| `packages/kilo-jetbrains/gradle.properties` `kilo.jetbrains.version` | The JetBrains Marketplace plugin version. |
|
||||
|
||||
The prepare workflow tags `origin/main`, so the CLI pin that matters is the one already merged to `main`. Before creating a release tag, run:
|
||||
|
||||
```bash
|
||||
bun .kilo/skills/release-jetbrains/script/check-pin.ts
|
||||
```
|
||||
|
||||
The script reports the CLI that `origin/main` will lock, the latest published stable CLI release, the CLI shipped by the latest `jetbrains/v*` tag, whether `kilo.cli.pinned=true`, and whether all runtime assets exist. Stop before tagging if the pin is behind the latest CLI and you want to test the newer CLI first.
|
||||
|
||||
To test a different CLI pin locally:
|
||||
|
||||
```bash
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest
|
||||
cd packages/kilo-jetbrains
|
||||
./gradlew typecheck
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
To land the tested pin on `main` before releasing:
|
||||
|
||||
```bash
|
||||
bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest --pr
|
||||
```
|
||||
|
||||
Merge the generated pin PR first, then re-run `check-pin.ts` and dispatch prepare. Do not dispatch prepare from a local-only pin edit.
|
||||
|
||||
## Create Release Tag And PR
|
||||
|
||||
1. Open the GitHub Actions workflow:
|
||||
|
||||
Reference in New Issue
Block a user