mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 11:05:31 +08:00
feat(jetbrains): add jetbrains-cli-pin skill
Add a skill that pins the JetBrains plugin to the latest released CLI, unpins to the local repo CLI, or fresh-regenerates the local CLI. Every command first cleans all leftover CLI binaries and build artifacts in the current worktree so each run starts from a fresh, artifact-free state. Reuses the release-jetbrains set-pin/pin-common helpers for validated version bumps and cross-links the skill from the JetBrains AGENTS.md.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
---
|
||||
name: jetbrains-cli-pin
|
||||
description: Use when pinning or unpinning the CLI version the Kilo JetBrains plugin uses, or fresh-regenerating the local repo CLI. Cleans all leftover CLI binaries and build artifacts in the current worktree so every operation starts from a fresh, artifact-free state.
|
||||
---
|
||||
|
||||
# JetBrains CLI Pin
|
||||
|
||||
Pin the Kilo JetBrains plugin to the latest released CLI, unpin it to use the local
|
||||
repo CLI, or fresh-regenerate the local CLI while unpinned. Every command first cleans
|
||||
all CLI/pin build artifacts and binaries in the current worktree so the result never
|
||||
carries state from a previous run.
|
||||
|
||||
Run all commands from the repository root of the worktree you want to affect. Paths are
|
||||
relative, so they resolve to the current worktree, not the main checkout.
|
||||
|
||||
## Two Controls
|
||||
|
||||
The plugin's CLI behavior is governed by two independent values:
|
||||
|
||||
| Control | Location | Meaning |
|
||||
|---|---|---|
|
||||
| Pin mode | `packages/kilo-jetbrains/gradle.properties` -> `kilo.cli.pinned` | `true` = download the released CLI at build/connect time. `false` = build and bundle the local repo CLI. |
|
||||
| Pinned version | `packages/kilo-jetbrains/package.json` -> `version` | Which GitHub CLI release is downloaded and generated from when `pinned=true`. |
|
||||
|
||||
"Pin to latest" means `kilo.cli.pinned=true` **and** `package.json` set to the latest
|
||||
stable CLI release. "Unpin" means `kilo.cli.pinned=false` with a freshly built local CLI
|
||||
bundled.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
bun .kilo/skills/jetbrains-cli-pin/script/cli-pin.ts <command> [--no-verify]
|
||||
```
|
||||
|
||||
| Command | Steps |
|
||||
|---|---|
|
||||
| `pin` | Clean -> set `kilo.cli.pinned=true` -> bump `package.json` to latest release (via `set-pin.ts --latest`, which validates release assets) -> verify with a cold `gradlew clean typecheck`. |
|
||||
| `unpin` | Clean -> set `kilo.cli.pinned=false` -> `:backend:buildRepoCli` (fresh CLI) -> `:backend:stageRepoCli` -> assert staged `kilo-cli.zip` -> verify with `gradlew typecheck`. |
|
||||
| `regen` | Fast dev loop while unpinned: `rm -rf dist` -> `buildRepoCli` -> `stageRepoCli`. Refuses to run unless `kilo.cli.pinned=false`. |
|
||||
| `clean` | Run the shared artifact clean only. |
|
||||
|
||||
`--no-verify` skips the gradle verification build (rewrites + clean only). Use it when
|
||||
offline or without Java 21.
|
||||
|
||||
## Cleaned Artifacts
|
||||
|
||||
`clean()` runs `./gradlew clean` plus targeted deletes. All paths are gitignored, so
|
||||
tracked files are never touched. The clean removes the stale artifacts that otherwise
|
||||
leak across a pin/unpin flip:
|
||||
|
||||
| Artifact | Path |
|
||||
|---|---|
|
||||
| Repo CLI binaries | `packages/opencode/dist/` |
|
||||
| Staged CLI archive | `packages/kilo-jetbrains/backend/build/generated/kilo-cli-res/kilo-cli.zip` |
|
||||
| Generated props / checksums / OpenAPI client | `packages/kilo-jetbrains/backend/build/generated/` |
|
||||
| Compiled resources (bundled zip on classpath) | `packages/kilo-jetbrains/backend/build/resources/` |
|
||||
| CLI download cache | `packages/kilo-jetbrains/backend/build/cli-cache/` |
|
||||
|
||||
The staged `kilo-cli.zip` is the nastiest leak: once it lands in `backend/build/resources/main/`
|
||||
from an unpinned build, runtime prefers the bundled zip over downloading. A full clean is
|
||||
the only reliable reset.
|
||||
|
||||
## Notes
|
||||
|
||||
- Verification builds pass `--no-configuration-cache` so the changed `kilo.cli.pinned`
|
||||
value is re-read instead of served from the on-disk Gradle configuration cache.
|
||||
- The `pin` verification is a cold build: it downloads the pinned CLI release via
|
||||
`generateOpenApiSpec` and needs network access plus Java 21. Use `--no-verify` offline.
|
||||
- `kilo.cli.pinned=false` is dev-only and not releasable. Production Gradle builds,
|
||||
`script/build-version.sh`, and the release scripts hard-fail on `false` -- run `pin`
|
||||
before releasing.
|
||||
|
||||
## Related
|
||||
|
||||
- Version-bump and release-gating logic lives in the `release-jetbrains` skill
|
||||
(`.kilo/skills/release-jetbrains/SKILL.md`); this skill reuses its `set-pin.ts` and
|
||||
`pin-common.ts` helpers.
|
||||
- Background on the build wiring: the "CLI Pinning, Unpinning, and Bumping" and "CLI
|
||||
Integration" sections of `packages/kilo-jetbrains/AGENTS.md`.
|
||||
@@ -0,0 +1,23 @@
|
||||
import { $ } from "bun"
|
||||
|
||||
// Single source of truth for every CLI/pin artifact that can leak across a mode
|
||||
// flip in the current worktree. Everything here is gitignored (dist, backend/build,
|
||||
// .gradle), so cleaning never touches tracked files.
|
||||
//
|
||||
// The build's conditional sourceSets/dependsOn wiring in backend/build.gradle.kts only
|
||||
// produces a correct package from a clean build/ directory. Incremental builds are what
|
||||
// let a stale kilo-cli.zip survive a pin<->unpin flip, and runtime prefers a bundled
|
||||
// zip over downloading -- so a full gradle clean is the reliable reset.
|
||||
export async function clean(jb = "packages/kilo-jetbrains") {
|
||||
// gradle clean wipes each project's build directory (including backend/build).
|
||||
await $`./gradlew clean --quiet`.cwd(jb).nothrow()
|
||||
|
||||
// Stale per-platform CLI binaries. build.ts only rm -rf dist for the platforms it
|
||||
// builds, so old platform dirs can survive; wipe the whole tree.
|
||||
await $`rm -rf packages/opencode/dist`
|
||||
|
||||
// Belt-and-suspenders in case gradle clean was skipped or ran offline.
|
||||
await $`rm -rf ${jb}/backend/build/generated`.nothrow()
|
||||
await $`rm -rf ${jb}/backend/build/resources`.nothrow()
|
||||
await $`rm -rf ${jb}/backend/build/cli-cache`.nothrow()
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import { $ } from "bun"
|
||||
import { parseArgs } from "util"
|
||||
import { clean } from "./clean"
|
||||
|
||||
const jb = "packages/kilo-jetbrains"
|
||||
const props = `${jb}/gradle.properties`
|
||||
const pkg = `${jb}/package.json`
|
||||
const zip = `${jb}/backend/build/generated/kilo-cli-res/kilo-cli.zip`
|
||||
|
||||
const arg = Bun.argv[2]
|
||||
const cmd = arg && !arg.startsWith("-") ? arg : undefined
|
||||
const { values } = parseArgs({
|
||||
args: cmd ? Bun.argv.slice(3) : Bun.argv.slice(2),
|
||||
options: {
|
||||
"no-verify": { type: "boolean", default: false },
|
||||
help: { type: "boolean", short: "h", default: false },
|
||||
},
|
||||
})
|
||||
|
||||
if (values.help || !cmd) {
|
||||
console.log(`
|
||||
Usage: bun .kilo/skills/jetbrains-cli-pin/script/cli-pin.ts <command> [--no-verify]
|
||||
|
||||
Commands:
|
||||
pin Pin the JetBrains plugin to the latest released CLI. Cleans artifacts,
|
||||
sets kilo.cli.pinned=true, bumps package.json to the latest release,
|
||||
then verifies with a cold gradle build (needs network + Java 21).
|
||||
unpin Use the local repo CLI. Cleans artifacts, sets kilo.cli.pinned=false,
|
||||
fresh-builds and stages the repo CLI, then verifies with typecheck.
|
||||
regen Fast dev loop: rebuild + restage the local repo CLI (requires unpinned).
|
||||
clean Remove all CLI/pin build artifacts and binaries in the current worktree.
|
||||
|
||||
Options:
|
||||
--no-verify Skip the gradle verification build (rewrites + clean only).
|
||||
|
||||
Run from the repository root of the worktree you want to affect.
|
||||
`)
|
||||
process.exit(values.help ? 0 : 1)
|
||||
}
|
||||
|
||||
async function pinned() {
|
||||
const text = await Bun.file(props).text()
|
||||
const line = text.split(/\r?\n/).find((l) => l.startsWith("kilo.cli.pinned="))
|
||||
return (line?.split("=", 2)[1]?.trim().toLowerCase() ?? "true") === "true"
|
||||
}
|
||||
|
||||
async function setPinned(value: boolean) {
|
||||
const text = await Bun.file(props).text()
|
||||
if (!/^kilo\.cli\.pinned=.*$/m.test(text)) throw new Error(`kilo.cli.pinned not found in ${props}`)
|
||||
await Bun.write(props, text.replace(/^kilo\.cli\.pinned=.*$/m, `kilo.cli.pinned=${value}`))
|
||||
}
|
||||
|
||||
async function report() {
|
||||
const version = (await Bun.file(pkg).json()).version
|
||||
console.log(`\nState: kilo.cli.pinned=${await pinned()}, package.json version=${version}`)
|
||||
}
|
||||
|
||||
if (cmd === "pin") {
|
||||
await clean()
|
||||
await setPinned(true)
|
||||
// set-pin.ts bumps package.json to the latest release and refuses versions with
|
||||
// missing runtime assets, so we do not reimplement release/asset validation.
|
||||
await $`bun .kilo/skills/release-jetbrains/script/set-pin.ts --latest`
|
||||
if (!values["no-verify"]) {
|
||||
// Cold pinned build downloads the pinned CLI release via generateOpenApiSpec.
|
||||
await $`./gradlew clean typecheck --no-configuration-cache`.cwd(jb)
|
||||
}
|
||||
await report()
|
||||
} else if (cmd === "unpin") {
|
||||
await clean()
|
||||
await setPinned(false)
|
||||
// build.ts does rm -rf dist internally, producing a fresh single-platform binary.
|
||||
await $`./gradlew :backend:buildRepoCli --no-configuration-cache`.cwd(jb)
|
||||
// stageRepoCli has upToDateWhen{false}; force it so the staged zip matches this build.
|
||||
await $`./gradlew :backend:stageRepoCli --no-configuration-cache`.cwd(jb)
|
||||
if (!(await Bun.file(zip).exists())) throw new Error(`Expected staged CLI at ${zip} after unpin`)
|
||||
if (!values["no-verify"]) {
|
||||
await $`./gradlew typecheck --no-configuration-cache`.cwd(jb)
|
||||
}
|
||||
await report()
|
||||
} else if (cmd === "regen") {
|
||||
if (await pinned()) throw new Error("regen requires the unpinned state; run 'unpin' first")
|
||||
await $`rm -rf packages/opencode/dist`
|
||||
await $`./gradlew :backend:buildRepoCli --no-configuration-cache`.cwd(jb)
|
||||
await $`./gradlew :backend:stageRepoCli --no-configuration-cache`.cwd(jb)
|
||||
if (!(await Bun.file(zip).exists())) throw new Error(`Expected staged CLI at ${zip} after regen`)
|
||||
await report()
|
||||
} else if (cmd === "clean") {
|
||||
await clean()
|
||||
await report()
|
||||
} else {
|
||||
throw new Error(`Unknown command '${cmd}'. Run with --help for usage.`)
|
||||
}
|
||||
@@ -170,6 +170,8 @@ For blocking I/O in coroutines, move the dispatcher switch inside the callee usi
|
||||
|
||||
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.
|
||||
|
||||
For a one-shot pin/unpin/regen that also cleans every leftover CLI binary and build artifact in the current worktree, use the `jetbrains-cli-pin` skill (`.kilo/skills/jetbrains-cli-pin/SKILL.md`): `bun .kilo/skills/jetbrains-cli-pin/script/cli-pin.ts <pin|unpin|regen|clean>`.
|
||||
|
||||
**Pin mode** (`kilo.cli.pinned` in `packages/kilo-jetbrains/gradle.properties`) controls release CLI vs local repo CLI.
|
||||
|
||||
| Ask | Do |
|
||||
|
||||
Reference in New Issue
Block a user