fix(jetbrains): prune bundled CLI cache

This commit is contained in:
kirillk
2026-07-24 14:10:51 -04:00
parent d266efcda8
commit 32652b017a
4 changed files with 48 additions and 10 deletions
@@ -187,17 +187,14 @@ jobs:
- name: Resolve bundled asset URL
id: asset
run: |
url="$(python3 - <<'PY'
import os
import urllib.parse
repo = os.environ["GITHUB_REPOSITORY"]
tag = urllib.parse.quote(os.environ["TAG"], safe="")
asset = urllib.parse.quote(os.environ["ASSET"], safe="")
print(f"https://github.com/{repo}/releases/download/{tag}/{asset}")
PY
)"
url="$(gh release view "$TAG" --json assets --jq '.assets[] | select(.name == env.ASSET) | .url' --repo "$GITHUB_REPOSITORY")"
if [[ -z "$url" ]]; then
echo "Could not resolve GitHub Release URL for $ASSET" >&2
exit 1
fi
echo "url=$url" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ needs.validate.outputs.tag }}
ASSET: ${{ steps.archive.outputs.asset }}
+1
View File
@@ -201,6 +201,7 @@ jobs:
NOTES: packages/kilo-jetbrains/build/release-notes.md
- name: Dispatch bundled GitHub release build
continue-on-error: true
run: |
gh workflow run publish-jetbrains-bundled.yml \
--repo "$GITHUB_REPOSITORY" \
@@ -1,5 +1,6 @@
package ai.kilocode.backend.cli
import ai.kilocode.log.KiloLog
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.util.SystemInfo
import kotlinx.coroutines.Dispatchers
@@ -11,24 +12,32 @@ import java.util.zip.ZipInputStream
object KiloRepoCli {
private const val ARCHIVE = "kilo-cli.zip"
private val log = KiloLog.create(KiloRepoCli::class.java)
fun available(): Boolean = KiloRepoCli::class.java.classLoader.getResource(ARCHIVE) != null
suspend fun extract(force: Boolean): File = extract(
force = force,
root = File(PathManager.getSystemPath(), "kilo/repo-cli/${KiloProps.cliVersion()}"),
cleanup = true,
source = {
KiloRepoCli::class.java.classLoader.getResourceAsStream(ARCHIVE)
?: throw IllegalStateException("kilo-cli.zip resource not found; rebuild with bundled CLI resources")
},
)
internal suspend fun extract(force: Boolean, root: File, source: () -> InputStream): File = withContext(Dispatchers.IO) {
internal suspend fun extract(
force: Boolean,
root: File,
cleanup: Boolean = false,
source: () -> InputStream,
): File = withContext(Dispatchers.IO) {
val platform = KiloCliPlatform.current()
val exe = File(root, "$platform/bin/${KiloCliPlatform.exe()}")
val done = File(root, ".complete")
if (!force && done.isFile && exe.isFile) {
if (!SystemInfo.isWindows) exe.setExecutable(true)
if (cleanup) prune(root)
return@withContext exe
}
@@ -53,9 +62,22 @@ object KiloRepoCli {
if (!exe.isFile) throw IllegalStateException("Bundled CLI archive did not contain $platform/bin/${KiloCliPlatform.exe()}")
if (!SystemInfo.isWindows) exe.setExecutable(true)
done.writeText("ok\n")
if (cleanup) prune(root)
return@withContext exe
}
private fun prune(root: File) {
val parent = root.parentFile ?: return
val entries = parent.listFiles() ?: return
for (entry in entries) {
if (!entry.isDirectory || entry.name == root.name || entry.name.startsWith(".")) continue
log.info("Removing stale bundled Kilo CLI version ${entry.absolutePath}")
if (!entry.deleteRecursively()) {
log.warn("Failed to remove stale bundled Kilo CLI version ${entry.absolutePath}")
}
}
}
private fun select(dir: File, name: String, platform: String): String? {
check(dir, name)
val path = name.replace('\\', '/')
@@ -53,6 +53,24 @@ class KiloRepoCliTest {
assertFalse(File(dir, "$other/bin/kilo").exists())
}
@Test
fun `prunes stale bundled cli versions after resolve`() = runBlocking {
val root = File(dir, "7.4.11")
val stale = File(dir, "7.4.10")
File(stale, "old").apply {
parentFile.mkdirs()
writeText("old")
}
val cli = KiloRepoCli.extract(false, root, cleanup = true) {
ByteArrayInputStream(archive("current"))
}
assertTrue(cli.isFile)
assertFalse(stale.exists())
assertTrue(root.isDirectory)
}
@Test
fun `rejects archive entries that escape root`() = runBlocking {
val ex = assertFailsWith<IllegalStateException> {