From 6a8302881daf12bb2de5c9296e085bc8e2aafdaf Mon Sep 17 00:00:00 2001 From: kirillk Date: Tue, 4 Aug 2026 19:28:55 -0400 Subject: [PATCH 1/5] 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. --- .kilo/skills/jetbrains-cli-pin/SKILL.md | 79 +++++++++++++++ .../skills/jetbrains-cli-pin/script/clean.ts | 23 +++++ .../jetbrains-cli-pin/script/cli-pin.ts | 95 +++++++++++++++++++ packages/kilo-jetbrains/AGENTS.md | 2 + 4 files changed, 199 insertions(+) create mode 100644 .kilo/skills/jetbrains-cli-pin/SKILL.md create mode 100644 .kilo/skills/jetbrains-cli-pin/script/clean.ts create mode 100644 .kilo/skills/jetbrains-cli-pin/script/cli-pin.ts diff --git a/.kilo/skills/jetbrains-cli-pin/SKILL.md b/.kilo/skills/jetbrains-cli-pin/SKILL.md new file mode 100644 index 00000000000..ecd59d67da5 --- /dev/null +++ b/.kilo/skills/jetbrains-cli-pin/SKILL.md @@ -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 [--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`. diff --git a/.kilo/skills/jetbrains-cli-pin/script/clean.ts b/.kilo/skills/jetbrains-cli-pin/script/clean.ts new file mode 100644 index 00000000000..a58ddcc532a --- /dev/null +++ b/.kilo/skills/jetbrains-cli-pin/script/clean.ts @@ -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() +} diff --git a/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts b/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts new file mode 100644 index 00000000000..ae293b6b1ff --- /dev/null +++ b/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts @@ -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 [--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.`) +} diff --git a/packages/kilo-jetbrains/AGENTS.md b/packages/kilo-jetbrains/AGENTS.md index 29012410381..254d66698f3 100644 --- a/packages/kilo-jetbrains/AGENTS.md +++ b/packages/kilo-jetbrains/AGENTS.md @@ -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 mode** (`kilo.cli.pinned` in `packages/kilo-jetbrains/gradle.properties`) controls release CLI vs local repo CLI. | Ask | Do | From a340d61716b6fdec89943bff438c151b513fd1f3 Mon Sep 17 00:00:00 2001 From: kirillk Date: Wed, 5 Aug 2026 09:37:33 -0400 Subject: [PATCH 2/5] feat(jetbrains): log CLI download/bundled mode and mark bundled Core version Backend now logs a clear one-line mode statement when resolving Core (BUNDLED vs DOWNLOAD), and logs distinctly when a cached/extracted binary is reused so no download or extraction happens. Adds a cliBundled() RPC so the frontend Core-info popup can prefix the version with "Bundled" when Core wasn't downloaded. --- .changeset/jetbrains-cli-mode-visibility.md | 5 +++ .../backend/cli/KiloBackendCliManager.kt | 12 ++++--- .../kilocode/backend/cli/KiloCliDownloader.kt | 2 +- .../ai/kilocode/backend/cli/KiloRepoCli.kt | 2 ++ .../kilocode/backend/rpc/KiloAppRpcApiImpl.kt | 3 ++ .../backend/cli/KiloCliDownloaderTest.kt | 2 +- .../kilocode/client/actions/CoreInfoAction.kt | 4 ++- .../ai/kilocode/client/app/KiloAppService.kt | 33 +++++++++++++++++++ .../resources/messages/KiloBundle.properties | 1 + .../client/actions/KiloRecoveryActionsTest.kt | 15 +++++++++ .../kilocode/client/testing/FakeAppRpcApi.kt | 6 ++++ .../kotlin/ai/kilocode/rpc/KiloAppRpcApi.kt | 3 ++ 12 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 .changeset/jetbrains-cli-mode-visibility.md diff --git a/.changeset/jetbrains-cli-mode-visibility.md b/.changeset/jetbrains-cli-mode-visibility.md new file mode 100644 index 00000000000..bc9cf774d13 --- /dev/null +++ b/.changeset/jetbrains-cli-mode-visibility.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": minor +--- + +Log whether the JetBrains plugin downloads Core or uses the bundled/cached version, and mark the Core version shown in the popup as "Bundled" when it wasn't downloaded. diff --git a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt index 9425f0779f7..580d226c33d 100644 --- a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt +++ b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt @@ -126,14 +126,18 @@ class KiloBackendCliManager( private suspend fun resolveCli(onProgress: (CliDownload) -> Unit): File { val force = forceExtract forceExtract = false + val version = KiloProps.cliVersion() + val platform = KiloCliPlatform.current() if (KiloRepoCli.available()) { - if (force) log.info("Force re-extracting bundled CLI ${KiloProps.cliVersion()}") + if (force) log.info("Force re-extracting bundled CLI $version") + log.info("Kilo CLI mode: BUNDLED — using CLI $version ($platform) shipped in the plugin; no download needed") val cli = KiloRepoCli.extract(force) - onProgress(CliDownload(100, KiloProps.cliVersion(), KiloCliPlatform.current())) + onProgress(CliDownload(100, version, platform)) return cli } - if (force) log.info("Force re-downloading CLI ${KiloProps.cliVersion()}") - return KiloCliDownloader(log = log).resolve(KiloProps.cliVersion(), force, onProgress) + if (force) log.info("Force re-downloading CLI $version") + log.info("Kilo CLI mode: DOWNLOAD — resolving CLI $version ($platform) from the GitHub release") + return KiloCliDownloader(log = log).resolve(version, force, onProgress) } // Must be called from a background thread — devStorageEnv() performs blocking I/O (mkdirs). diff --git a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt index bee74c12bb4..11cb6754ffe 100644 --- a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt +++ b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt @@ -112,7 +112,7 @@ class KiloCliDownloader( "completeExists=${done.isFile} digestValid=$valid exe=${exe.absolutePath} complete=${done.absolutePath}" ) if (!exe.isFile || !valid) return null - log.info("Using cached Kilo CLI $version for $platform at ${exe.absolutePath}") + log.info("Kilo CLI $version ($platform) already cached at ${exe.absolutePath}; skipping download and extraction") if (!SystemInfo.isWindows) exe.setExecutable(true) prune(version) return exe diff --git a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloRepoCli.kt b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloRepoCli.kt index 8138ae4daed..617e805ba76 100644 --- a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloRepoCli.kt +++ b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloRepoCli.kt @@ -36,10 +36,12 @@ object KiloRepoCli { val exe = File(root, "$platform/bin/${KiloCliPlatform.exe()}") val done = File(root, ".complete") if (!force && done.isFile && exe.isFile) { + log.info("Bundled Kilo CLI ${KiloProps.cliVersion()} ($platform) already extracted at ${exe.absolutePath}; skipping extraction") if (!SystemInfo.isWindows) exe.setExecutable(true) if (cleanup) prune(root) return@withContext exe } + log.info("Extracting bundled Kilo CLI ${KiloProps.cliVersion()} ($platform) into ${root.absolutePath}") if (root.exists() && !root.deleteRecursively()) { throw IllegalStateException("Failed to delete local repo CLI under ${root.absolutePath}") diff --git a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloAppRpcApiImpl.kt b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloAppRpcApiImpl.kt index 58e929dcd7e..2fe3edca360 100644 --- a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloAppRpcApiImpl.kt +++ b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloAppRpcApiImpl.kt @@ -11,6 +11,7 @@ import ai.kilocode.backend.app.LoadProgress import ai.kilocode.backend.app.ProfileResult import ai.kilocode.backend.cli.KiloCliPlatform import ai.kilocode.backend.cli.KiloProps +import ai.kilocode.backend.cli.KiloRepoCli import ai.kilocode.jetbrains.api.model.KiloProfile200Response import ai.kilocode.rpc.dto.ConfigPatchDto import ai.kilocode.rpc.KiloAppRpcApi @@ -57,6 +58,8 @@ class KiloAppRpcApiImpl : KiloAppRpcApi { override suspend fun cliPlatform(): String = KiloCliPlatform.current() + override suspend fun cliBundled(): Boolean = KiloRepoCli.available() + override suspend fun retry() = app.retry() override suspend fun restart() = app.restart() diff --git a/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDownloaderTest.kt b/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDownloaderTest.kt index 8c489813a65..477f001849f 100644 --- a/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDownloaderTest.kt +++ b/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDownloaderTest.kt @@ -70,7 +70,7 @@ class KiloCliDownloaderTest { assertEquals(cli.absolutePath, cached.absolutePath) assertEquals(1, server.requestCount) assertTrue(cachedProgress.isEmpty()) - assertContains(log.messages, "INFO: Using cached Kilo CLI 1.2.3 for ${KiloCliPlatform.current()} at ${cli.absolutePath}") + assertContains(log.messages, "INFO: Kilo CLI 1.2.3 (${KiloCliPlatform.current()}) already cached at ${cli.absolutePath}; skipping download and extraction") File(cli.parentFile.parentFile, ".complete").writeText("ok\n") server.enqueue(MockResponse().setResponseCode(200).setBody(Buffer().write(bytes))) diff --git a/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/actions/CoreInfoAction.kt b/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/actions/CoreInfoAction.kt index 1bad925ec0c..6ed21bcb695 100644 --- a/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/actions/CoreInfoAction.kt +++ b/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/actions/CoreInfoAction.kt @@ -15,8 +15,10 @@ class CoreInfoAction : AnAction(), DumbAware { val app = service() val info = app.core if (info == null) app.fetchCoreInfoAsync() + app.fetchBundledAsync() + val key = if (app.bundled == true) "action.Kilo.CoreInfo.bundled" else "action.Kilo.CoreInfo.text" e.presentation.text = info?.let { - KiloBundle.message("action.Kilo.CoreInfo.text", it.version, it.platform) + KiloBundle.message(key, it.version, it.platform) } ?: KiloBundle.message("action.Kilo.CoreInfo.loading") e.presentation.description = KiloBundle.message("action.Kilo.CoreInfo.description") e.presentation.isEnabled = false diff --git a/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloAppService.kt b/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloAppService.kt index 23443265e1b..1751383899a 100644 --- a/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloAppService.kt +++ b/packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloAppService.kt @@ -58,6 +58,18 @@ class KiloAppService internal constructor( val version: String? get() = info?.version + /** + * Whether the running Core is bundled in the plugin (true) or downloaded (false). + * Null until fetched. This is a static property of the plugin build, so it is + * fetched once via RPC independently of the download-progress state. + */ + @Volatile + private var bundledFlag: Boolean? = null + private val bundledLock = Any() + private var bundledJob: Job? = null + + val bundled: Boolean? get() = bundledFlag + /** * App-lifetime scope for fire-and-forget work that must outlive transient UIs such as the * settings dialog (whose own scope is cancelled the moment it closes on OK). @@ -152,6 +164,7 @@ class KiloAppService internal constructor( platform = call { cliPlatform() }, ) info = next + bundledFlag = call { cliBundled() } next } catch (e: Exception) { LOG.warn("core info failed", e) @@ -200,6 +213,26 @@ class KiloAppService internal constructor( fetchCoreInfoAsync { done(it?.version) } } + /** Fetch whether the running Core is bundled and cache it. Deduped and fetched once. */ + fun fetchBundledAsync() { + if (bundledFlag != null) return + synchronized(bundledLock) { + if (bundledFlag != null || bundledJob != null) return + bundledJob = cs.launch { + val value = try { + call { cliBundled() } + } catch (e: Exception) { + LOG.warn("core bundled check failed", e) + null + } + synchronized(bundledLock) { + if (value != null) bundledFlag = value + bundledJob = null + } + } + } + } + fun refreshModelFavoritesAsync() { cs.launch { try { diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties index faf0e7b7828..84f9423db3b 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties @@ -731,6 +731,7 @@ action.Kilo.Reinstall.text=Reinstall action.Kilo.Reinstall.cli.text=Reinstall Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart action.Kilo.CoreInfo.text=Core v{0} • Architecture: {1} +action.Kilo.CoreInfo.bundled=Bundled Core v{0} • Architecture: {1} action.Kilo.CoreInfo.loading=Core details loading... action.Kilo.CoreInfo.description=Kilo Core version and architecture action.Kilo.Session.Open.text=Open diff --git a/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/actions/KiloRecoveryActionsTest.kt b/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/actions/KiloRecoveryActionsTest.kt index 477a78333ca..9d4689d514b 100644 --- a/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/actions/KiloRecoveryActionsTest.kt +++ b/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/actions/KiloRecoveryActionsTest.kt @@ -126,6 +126,21 @@ class KiloRecoveryActionsTest : BasePlatformTestCase() { assertEquals("Core v1.2.3 • Architecture: darwin-arm64", event.presentation.text) } + fun `test core info action marks bundled core`() { + appRpc.cliVersion = "1.2.3" + appRpc.cliPlatform = "darwin-arm64" + appRpc.cliBundled = true + ApplicationManager.getApplication().executeOnPooledThread { + runBlocking { app().coreInfo() } + }.get() + val action = CoreInfoAction() + val event = event(action) + + update(action, event) + + assertEquals("Bundled Core v1.2.3 • Architecture: darwin-arm64", event.presentation.text) + } + fun `test local config action says open when target exists`() { rpc.localConfigPath = "/test/.kilo/kilo.jsonc" rpc.localConfigDisplayPath = "~/.kilo/kilo.jsonc" diff --git a/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeAppRpcApi.kt b/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeAppRpcApi.kt index 7c7d4a9affe..ba9ce1d3bca 100644 --- a/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeAppRpcApi.kt +++ b/packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeAppRpcApi.kt @@ -37,6 +37,7 @@ class FakeAppRpcApi : KiloAppRpcApi { var health = HealthDto(healthy = true, version = "1.0.0") var cliVersion = "1.0.0" var cliPlatform = "darwin-arm64" + var cliBundled = false var cliInfoGate: CompletableDeferred? = null var cliInfoError: Exception? = null var cliVersionCalls = 0 @@ -94,6 +95,11 @@ class FakeAppRpcApi : KiloAppRpcApi { return cliPlatform } + override suspend fun cliBundled(): Boolean { + assertNotEdt("cliBundled") + return cliBundled + } + override suspend fun retry() { assertNotEdt("retry") retries += 1 diff --git a/packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloAppRpcApi.kt b/packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloAppRpcApi.kt index e05b4c3bdf1..2322ce61640 100644 --- a/packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloAppRpcApi.kt +++ b/packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloAppRpcApi.kt @@ -45,6 +45,9 @@ interface KiloAppRpcApi : RemoteApi { /** Core platform downloaded by the backend process. */ suspend fun cliPlatform(): String + /** Whether the running Core is bundled in the plugin (true) or downloaded (false). */ + suspend fun cliBundled(): Boolean + /** Retry app connection or loading after a failure. */ suspend fun retry() From 7ee1909f73485197175c05411ac23c70d035d2ec Mon Sep 17 00:00:00 2001 From: kirillk Date: Wed, 5 Aug 2026 09:37:44 -0400 Subject: [PATCH 3/5] fix(jetbrains): resolve Bun path for repo CLI generation under IDE Gradle runs IDE-launched Gradle runs (e.g. Run IDE Split Mode) can have a stripped PATH where 'bun' isn't resolvable, so :backend:generateOpenApiSpec and :backend:buildRepoCli failed with 'A problem occurred starting process command bun' in repo-CLI (unpinned) mode. The jetbrains-cli-pin skill's unpin/regen commands now write an ignored, worktree-local Bun path hint (.gradle/kilo-cli-pin.properties) that backend/build.gradle.kts resolves and passes as an absolute path to the affected tasks. pin removes the hint since pinned mode doesn't depend on local Bun. --- .kilo/skills/jetbrains-cli-pin/SKILL.md | 19 ++++++++++++++--- .../jetbrains-cli-pin/script/cli-pin.ts | 21 +++++++++++++++++++ .../kilo-jetbrains/backend/build.gradle.kts | 10 ++++++++- .../main/kotlin/GenerateOpenApiSpecTask.kt | 5 ++++- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/.kilo/skills/jetbrains-cli-pin/SKILL.md b/.kilo/skills/jetbrains-cli-pin/SKILL.md index ecd59d67da5..2fc5b06ef58 100644 --- a/.kilo/skills/jetbrains-cli-pin/SKILL.md +++ b/.kilo/skills/jetbrains-cli-pin/SKILL.md @@ -34,9 +34,9 @@ bun .kilo/skills/jetbrains-cli-pin/script/cli-pin.ts [--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`. | +| `pin` | Clean -> set `kilo.cli.pinned=true` -> remove the repo-CLI Bun path hint -> 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` -> write the repo-CLI Bun path hint -> `:backend:buildRepoCli` (fresh CLI) -> `:backend:stageRepoCli` -> assert staged `kilo-cli.zip` -> verify with `gradlew typecheck`. | +| `regen` | Fast dev loop while unpinned: refresh the repo-CLI Bun path hint -> `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 @@ -60,6 +60,19 @@ The staged `kilo-cli.zip` is the nastiest leak: once it lands in `backend/build/ from an unpinned build, runtime prefers the bundled zip over downloading. A full clean is the only reliable reset. +## Bun Path Hint + +In repo CLI mode, Gradle's `generateOpenApiSpec` task runs the local CLI source through +`bun run --conditions=browser ./src/index.ts generate`. IDE-launched Gradle runs can have +worktree-local hint: + +```text +packages/kilo-jetbrains/.gradle/kilo-cli-pin.properties +``` + +The file contains `bun.path=` and is consumed by `backend/build.gradle.kts` +for repo CLI tasks. `pin` removes it because pinned mode should not depend on local Bun. + ## Notes - Verification builds pass `--no-configuration-cache` so the changed `kilo.cli.pinned` diff --git a/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts b/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts index ae293b6b1ff..a7223d3cbad 100644 --- a/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts +++ b/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts @@ -8,6 +8,7 @@ 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 hint = `${jb}/.gradle/kilo-cli-pin.properties` const arg = Bun.argv[2] const cmd = arg && !arg.startsWith("-") ? arg : undefined @@ -52,6 +53,23 @@ async function setPinned(value: boolean) { await Bun.write(props, text.replace(/^kilo\.cli\.pinned=.*$/m, `kilo.cli.pinned=${value}`)) } +async function bunPath() { + const result = await $`command -v bun`.quiet().nothrow() + const bin = result.exitCode === 0 ? result.stdout.toString().trim() : "" + return bin || process.execPath +} + +async function writeBunHint() { + const path = await bunPath() + await $`mkdir -p ${jb}/.gradle` + await Bun.write(hint, `# Generated by jetbrains-cli-pin so IDE-launched Gradle can find Bun in repo CLI mode.\nbun.path=${path}\n`) + console.log(`Wrote Bun path hint for repo CLI mode: ${path}`) +} + +async function removeBunHint() { + await $`rm -f ${hint}`.nothrow() +} + async function report() { const version = (await Bun.file(pkg).json()).version console.log(`\nState: kilo.cli.pinned=${await pinned()}, package.json version=${version}`) @@ -60,6 +78,7 @@ async function report() { if (cmd === "pin") { await clean() await setPinned(true) + await removeBunHint() // 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` @@ -71,6 +90,7 @@ if (cmd === "pin") { } else if (cmd === "unpin") { await clean() await setPinned(false) + await writeBunHint() // 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. @@ -82,6 +102,7 @@ if (cmd === "pin") { await report() } else if (cmd === "regen") { if (await pinned()) throw new Error("regen requires the unpinned state; run 'unpin' first") + await writeBunHint() await $`rm -rf packages/opencode/dist` await $`./gradlew :backend:buildRepoCli --no-configuration-cache`.cwd(jb) await $`./gradlew :backend:stageRepoCli --no-configuration-cache`.cwd(jb) diff --git a/packages/kilo-jetbrains/backend/build.gradle.kts b/packages/kilo-jetbrains/backend/build.gradle.kts index e09355e19f2..bcba0effb4c 100644 --- a/packages/kilo-jetbrains/backend/build.gradle.kts +++ b/packages/kilo-jetbrains/backend/build.gradle.kts @@ -26,6 +26,13 @@ val repoCli = pinned.map { !it } val bundled = providers.gradleProperty("kilo.cli.bundled").map { it.trim().toBoolean() }.orElse(false) val downloadsCli = repoCli.zip(bundled) { repo, bundle -> !repo && !bundle } val repoRootDir = rootProject.layout.projectDirectory.dir("../opencode") +val local = rootProject.layout.projectDirectory.file(".gradle/kilo-cli-pin.properties") +val bunPathProvider = providers.fileContents(local).asText.map { text -> + text.lineSequence().firstNotNullOfOrNull { line -> + val pair = line.split("=", limit = 2) + if (pair.getOrNull(0)?.trim() == "bun.path") pair.getOrNull(1)?.trim()?.takeIf { it.isNotEmpty() } else null + } ?: "bun" +}.orElse("bun") val pinnedCliVersion = providers.fileContents(rootProject.layout.projectDirectory.file("package.json")).asText.map { text -> Regex("\"version\"\\s*:\\s*\"([^\"]+)\"").find(text)?.groupValues?.get(1) @@ -64,12 +71,13 @@ val generateOpenApiSpec by tasks.registering(GenerateOpenApiSpecTask::class) { ) cacheDir.set(layout.buildDirectory.dir("cli-cache")) spec.set(rawSpec) + bunPath.set(bunPathProvider) } val buildRepoCli by tasks.registering(Exec::class) { description = "Build the local repo CLI for the current platform" workingDir = repoRootDir.asFile - commandLine("bun", "run", "script/build.ts", "--single", "--skip-install") + commandLine(bunPathProvider.get(), "run", "script/build.ts", "--single", "--skip-install") } fun platform(): String { diff --git a/packages/kilo-jetbrains/build-tasks/src/main/kotlin/GenerateOpenApiSpecTask.kt b/packages/kilo-jetbrains/build-tasks/src/main/kotlin/GenerateOpenApiSpecTask.kt index 5482dfbd492..1c1181c34d1 100644 --- a/packages/kilo-jetbrains/build-tasks/src/main/kotlin/GenerateOpenApiSpecTask.kt +++ b/packages/kilo-jetbrains/build-tasks/src/main/kotlin/GenerateOpenApiSpecTask.kt @@ -49,6 +49,9 @@ abstract class GenerateOpenApiSpecTask : DefaultTask() { @get:Internal abstract val cacheDir: DirectoryProperty + @get:Internal + abstract val bunPath: Property + @get:OutputFile abstract val spec: RegularFileProperty @@ -76,7 +79,7 @@ abstract class GenerateOpenApiSpecTask : DefaultTask() { val err = ByteArrayOutputStream() val result = exec.exec { workingDir = root - commandLine("bun", "run", "--conditions=browser", "./src/index.ts", "generate") + commandLine(bunPath.get(), "run", "--conditions=browser", "./src/index.ts", "generate") standardOutput = out errorOutput = err isIgnoreExitValue = true From ca421f8e19138bd7152b9390909208e5a01ad61d Mon Sep 17 00:00:00 2001 From: kirillk Date: Wed, 5 Aug 2026 10:58:13 -0400 Subject: [PATCH 4/5] chore(jetbrains): translate bundled Core version label --- .../src/main/resources/messages/KiloBundle_ar.properties | 1 + .../src/main/resources/messages/KiloBundle_bs.properties | 1 + .../src/main/resources/messages/KiloBundle_da.properties | 1 + .../src/main/resources/messages/KiloBundle_de.properties | 1 + .../src/main/resources/messages/KiloBundle_es.properties | 1 + .../src/main/resources/messages/KiloBundle_fr.properties | 1 + .../src/main/resources/messages/KiloBundle_ja.properties | 1 + .../src/main/resources/messages/KiloBundle_ko.properties | 1 + .../src/main/resources/messages/KiloBundle_nl.properties | 1 + .../src/main/resources/messages/KiloBundle_no.properties | 1 + .../src/main/resources/messages/KiloBundle_pl.properties | 1 + .../src/main/resources/messages/KiloBundle_pt_BR.properties | 1 + .../src/main/resources/messages/KiloBundle_ru.properties | 1 + .../src/main/resources/messages/KiloBundle_th.properties | 1 + .../src/main/resources/messages/KiloBundle_tr.properties | 1 + .../src/main/resources/messages/KiloBundle_uk.properties | 1 + .../src/main/resources/messages/KiloBundle_zh_CN.properties | 1 + .../src/main/resources/messages/KiloBundle_zh_TW.properties | 1 + 18 files changed, 18 insertions(+) diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ar.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ar.properties index 15944a645df..a3ad22de392 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ar.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ar.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=إنهاء عملية Core وإعادة تشغي action.Kilo.Reinstall.text=إعادة تثبيت Kilo action.Kilo.Reinstall.cli.text=إعادة تثبيت Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=‏Core المُضمّن v{0} • البنية: {1} action.Kilo.Session.Open.text=فتح action.Kilo.Session.Open.description=فتح الجلسة المحددة action.Kilo.Session.Rename.text=إعادة تسمية diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_bs.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_bs.properties index df5882b5000..f865d877598 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_bs.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_bs.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Ugasite i ponovo pokrenite Core proces action.Kilo.Reinstall.text=Ponovo instalirajte Kilo action.Kilo.Reinstall.cli.text=Ponovo instalirajte Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Ugrađeni Core v{0} • Arhitektura: {1} action.Kilo.Session.Open.text=Otvori action.Kilo.Session.Open.description=Otvorite odabranu sesiju action.Kilo.Session.Rename.text=Preimenuj diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_da.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_da.properties index 65d9d0909cd..aa558608cf1 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_da.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_da.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Afslut og genstart Core-processen action.Kilo.Reinstall.text=Geninstaller Kilo action.Kilo.Reinstall.cli.text=Geninstaller Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Medfølgende Core v{0} • Arkitektur: {1} action.Kilo.Session.Open.text=Åbn action.Kilo.Session.Open.description=Åbn den valgte session action.Kilo.Session.Rename.text=Omdøb diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_de.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_de.properties index 9b0ca266323..0aaaa9b1063 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_de.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_de.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Core-Prozess beenden und neu starten action.Kilo.Reinstall.text=Kilo neu installieren action.Kilo.Reinstall.cli.text=Core neu installieren action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Gebündelter Core v{0} • Architektur: {1} action.Kilo.Session.Open.text=Öffnen action.Kilo.Session.Open.description=Ausgewählte Sitzung öffnen action.Kilo.Session.Rename.text=Umbenennen diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_es.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_es.properties index 0d19e12cfd9..9ad869fc591 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_es.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_es.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Terminar y reiniciar el proceso Core action.Kilo.Reinstall.text=Reinstalar Kilo action.Kilo.Reinstall.cli.text=Reinstalar Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Core incluido v{0} • Arquitectura: {1} action.Kilo.Session.Open.text=Abrir action.Kilo.Session.Open.description=Abrir la sesión seleccionada action.Kilo.Session.Rename.text=Renombrar diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_fr.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_fr.properties index 683bf55d439..dfe14978821 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_fr.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_fr.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Tuer et redémarrer le processus Core action.Kilo.Reinstall.text=Réinstaller Kilo action.Kilo.Reinstall.cli.text=Réinstaller Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Core intégré v{0} • Architecture : {1} action.Kilo.Session.Open.text=Ouvrir action.Kilo.Session.Open.description=Ouvrir la session sélectionnée action.Kilo.Session.Rename.text=Renommer diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ja.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ja.properties index e9e1c52f3cb..1c8e84104d9 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ja.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ja.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Coreプロセスを終了して再起動 action.Kilo.Reinstall.text=Kiloを再インストール action.Kilo.Reinstall.cli.text=Coreを再インストール action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=バンドルされた Core v{0} • アーキテクチャ: {1} action.Kilo.Session.Open.text=開く action.Kilo.Session.Open.description=選択したセッションを開く action.Kilo.Session.Rename.text=変名 diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ko.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ko.properties index c2e935a4ed7..5594fdf3199 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ko.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ko.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Core 프로세스 종료 후 재시작 action.Kilo.Reinstall.text=Kilo 재설치 action.Kilo.Reinstall.cli.text=Core 재설치 action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=번들 Core v{0} • 아키텍처: {1} action.Kilo.Session.Open.text=열기 action.Kilo.Session.Open.description=선택한 세션 열기 action.Kilo.Session.Rename.text=이름 바꾸기 diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_nl.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_nl.properties index e43ba741bd8..d96e7241085 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_nl.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_nl.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Core-proces beëindigen en herstarten action.Kilo.Reinstall.text=Kilo herinstalleren action.Kilo.Reinstall.cli.text=Core herinstalleren action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Gebundelde Core v{0} • Architectuur: {1} action.Kilo.Session.Open.text=Openen action.Kilo.Session.Open.description=Geselecteerde sessie openen action.Kilo.Session.Rename.text=Hernoemen diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_no.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_no.properties index d391bcc32a3..57502a00bea 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_no.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_no.properties @@ -160,6 +160,7 @@ action.Kilo.Restart.description=Avslutt og start Core-prosessen på nytt action.Kilo.Reinstall.text=Installer Kilo på nytt action.Kilo.Reinstall.cli.text=Installer Core på nytt action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Innebygd Core v{0} • Arkitektur: {1} action.Kilo.Session.Open.text=Åpne action.Kilo.Session.Open.description=Åpne valgt økt action.Kilo.Session.Rename.text=Gi nytt navn diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pl.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pl.properties index ef4c5efe137..4b9bf11f462 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pl.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pl.properties @@ -160,6 +160,7 @@ action.Kilo.Restart.description=Zakończ i uruchom ponownie proces Core action.Kilo.Reinstall.text=Zainstaluj ponownie Kilo action.Kilo.Reinstall.cli.text=Zainstaluj ponownie Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Wbudowany Core v{0} • Architektura: {1} action.Kilo.Session.Open.text=Otwórz action.Kilo.Session.Open.description=Otwórz wybraną sesję action.Kilo.Session.Rename.text=Zmień nazwę diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pt_BR.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pt_BR.properties index 2bf9c4c4cce..08de02c275d 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pt_BR.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_pt_BR.properties @@ -160,6 +160,7 @@ action.Kilo.Restart.description=Encerrar e reiniciar o processo Core action.Kilo.Reinstall.text=Reinstalar Kilo action.Kilo.Reinstall.cli.text=Reinstalar Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Core incluído v{0} • Arquitetura: {1} action.Kilo.Session.Open.text=Abrir action.Kilo.Session.Open.description=Abrir a sessão selecionada action.Kilo.Session.Rename.text=Renomear diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ru.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ru.properties index aef654244b3..90a13ed0ed9 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ru.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_ru.properties @@ -160,6 +160,7 @@ action.Kilo.Restart.description=Завершить и перезапустить action.Kilo.Reinstall.text=Переустановить Kilo action.Kilo.Reinstall.cli.text=Переустановить Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Встроенный Core v{0} • Архитектура: {1} action.Kilo.Session.Open.text=Открыть action.Kilo.Session.Open.description=Открыть выбранную сессию action.Kilo.Session.Rename.text=Переименовать diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_th.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_th.properties index 8959598aa7a..ee10c59c9aa 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_th.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_th.properties @@ -160,6 +160,7 @@ action.Kilo.Restart.description=สิ้นสุดและรีสตาร action.Kilo.Reinstall.text=ติดตั้ง Kilo ใหม่ action.Kilo.Reinstall.cli.text=ติดตั้ง Core ใหม่ action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Core แบบรวมมาในตัว v{0} • สถาปัตยกรรม: {1} action.Kilo.Session.Open.text=เปิด action.Kilo.Session.Open.description=เปิดเซสชันที่เลือก action.Kilo.Session.Rename.text=เปลี่ยนชื่อ diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_tr.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_tr.properties index b954188a5ca..15c992fac3f 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_tr.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_tr.properties @@ -160,6 +160,7 @@ action.Kilo.Restart.description=Core sürecini sonlandır ve yeniden başlat action.Kilo.Reinstall.text=Kilo’yu yeniden yükle action.Kilo.Reinstall.cli.text=Core’yi yeniden yükle action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Paketlenmiş Core v{0} • Mimari: {1} action.Kilo.Session.Open.text=Aç action.Kilo.Session.Open.description=Seçilen oturumu aç action.Kilo.Session.Rename.text=Yeniden adlandır diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_uk.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_uk.properties index 77ea64c7752..b69ddc88618 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_uk.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_uk.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=Завершити і перезапустити action.Kilo.Reinstall.text=Перевстановити Kilo action.Kilo.Reinstall.cli.text=Перевстановити Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=Вбудований Core v{0} • Архітектура: {1} action.Kilo.Session.Open.text=Відкрити action.Kilo.Session.Open.description=Відкрити вибрану сесію action.Kilo.Session.Rename.text=Перейменувати diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_CN.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_CN.properties index 909073cae3e..f16bb2266b8 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_CN.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_CN.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=终止并重启 Core 进程 action.Kilo.Reinstall.text=重新安装 Kilo action.Kilo.Reinstall.cli.text=重新安装 Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=捆绑的 Core v{0} • 架构:{1} action.Kilo.Session.Open.text=打开 action.Kilo.Session.Open.description=打开所选会话 action.Kilo.Session.Rename.text=重命名 diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_TW.properties b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_TW.properties index bc74d81c93a..6eec893d1af 100644 --- a/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_TW.properties +++ b/packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_zh_TW.properties @@ -155,6 +155,7 @@ action.Kilo.Restart.description=終止並重啟 Core 程序 action.Kilo.Reinstall.text=重新安裝 Kilo action.Kilo.Reinstall.cli.text=重新安裝 Core action.Kilo.Reinstall.description=Download a fresh Core binary and restart +action.Kilo.CoreInfo.bundled=捆綁的 Core v{0} • 架構:{1} action.Kilo.Session.Open.text=開啟 action.Kilo.Session.Open.description=開啟所選工作階段 action.Kilo.Session.Rename.text=重命名 From f035c871ffc6c844a4b1400829dd98248fada4df Mon Sep 17 00:00:00 2001 From: kirillk Date: Wed, 5 Aug 2026 11:29:44 -0400 Subject: [PATCH 5/5] docs(jetbrains): fix Bun Path Hint wording and use Bun.which for bun lookup Addresses PR review: repairs the broken sentence in the SKILL.md Bun Path Hint section and replaces the dead 'command -v bun' lookup (not a Bun $ shell builtin) with native Bun.which. --- .kilo/skills/jetbrains-cli-pin/SKILL.md | 2 +- .kilo/skills/jetbrains-cli-pin/script/cli-pin.ts | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.kilo/skills/jetbrains-cli-pin/SKILL.md b/.kilo/skills/jetbrains-cli-pin/SKILL.md index 2fc5b06ef58..f04217edecf 100644 --- a/.kilo/skills/jetbrains-cli-pin/SKILL.md +++ b/.kilo/skills/jetbrains-cli-pin/SKILL.md @@ -64,7 +64,7 @@ the only reliable reset. In repo CLI mode, Gradle's `generateOpenApiSpec` task runs the local CLI source through `bun run --conditions=browser ./src/index.ts generate`. IDE-launched Gradle runs can have -worktree-local hint: +a stripped `PATH` where `bun` isn't resolvable. The `unpin`/`regen` commands write an ignored, worktree-local hint: ```text packages/kilo-jetbrains/.gradle/kilo-cli-pin.properties diff --git a/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts b/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts index a7223d3cbad..a57676806d1 100644 --- a/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts +++ b/.kilo/skills/jetbrains-cli-pin/script/cli-pin.ts @@ -53,14 +53,12 @@ async function setPinned(value: boolean) { await Bun.write(props, text.replace(/^kilo\.cli\.pinned=.*$/m, `kilo.cli.pinned=${value}`)) } -async function bunPath() { - const result = await $`command -v bun`.quiet().nothrow() - const bin = result.exitCode === 0 ? result.stdout.toString().trim() : "" - return bin || process.execPath +function bunPath() { + return Bun.which("bun") ?? process.execPath } async function writeBunHint() { - const path = await bunPath() + const path = bunPath() await $`mkdir -p ${jb}/.gradle` await Bun.write(hint, `# Generated by jetbrains-cli-pin so IDE-launched Gradle can find Bun in repo CLI mode.\nbun.path=${path}\n`) console.log(`Wrote Bun path hint for repo CLI mode: ${path}`)