Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions .kilo/skills/release-jetbrains/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ Create a changelog draft after the prepare PR exists:

1. Read the PR body with `gh pr view <pr> --json body`.
2. Extract `JetBrains-From-Tag`, `JetBrains-Tag`, and `## Generated Notes`.
3. Use the release range and path filter as the primary relevance signal:
3. Fetch the release range tags if they are missing locally:

```bash
git fetch origin refs/tags/<from-tag>:refs/tags/<from-tag> refs/tags/<tag>:refs/tags/<tag>
```

4. Use the release range and path filter as the primary relevance signal:

```bash
git log --oneline <from-tag>..<tag> -- packages/opencode packages/kilo-jetbrains
Expand Down Expand Up @@ -103,9 +109,33 @@ The script updates `packages/kilo-jetbrains/CHANGELOG.md` on `jetbrains/release/
docs(jetbrains): edit changelog for v<version>
```

If `update-changelog.ts` fails with `gh: Not Found (HTTP 404)`, verify the release branch and changelog path with:

```bash
gh api "repos/Kilo-Org/kilocode/contents/packages/kilo-jetbrains/CHANGELOG.md?ref=jetbrains/release/v<version>"
```

Then either fix and retry the helper, or perform the equivalent contents API update using `ref` in the query string.

## Approve And Publish

Ask the user to approve the release changelog and metadata. By default, have the user merge the release PR manually in GitHub, then watch the publish workflow:
Ask the user to approve the release changelog and metadata. Before merging or publishing, verify the PR approval and required checks are green:

```bash
gh pr view <pr> --json mergeStateStatus,reviewDecision,statusCheckRollup
gh pr checks <pr> --watch --interval 10
```

Do not merge or publish while required checks are failing unless the user explicitly gives a maintainer override.

If a required check fails from an apparent flake, rerun only the failed jobs and wait for the run to finish:

```bash
gh run rerun <run-id> --failed
gh run watch <run-id> --exit-status
```

By default, have the user merge the release PR manually in GitHub, then watch the publish workflow:

```bash
bun .kilo/skills/release-jetbrains/script/watch-publish.ts --pr <number> --version 7.0.1-rc.7
Expand All @@ -123,11 +153,18 @@ Pass a generous Bash timeout, such as `1800000` ms. If the shell times out, re-a
bun .kilo/skills/release-jetbrains/script/watch-publish.ts --pr <number> --version 7.0.1-rc.7 --run-id <run-id>
```

If `watch-publish.ts --merge` reports that the PR is already merged, or a transient GitHub API `5xx` interrupts publish-run discovery, rerun without `--merge`:

```bash
bun .kilo/skills/release-jetbrains/script/watch-publish.ts --pr <number> --version <version>
```

Report the Marketplace channel and GitHub Release URL. RC versions publish to the `eap` channel; stable versions publish to the default Marketplace channel.

## Recovery

- 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 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.
2 changes: 1 addition & 1 deletion .kilo/skills/release-jetbrains/script/update-changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const branch = `jetbrains/release/v${ver}`
const section = strip((await Bun.file(file).text()).trim())
validate(section, ver)

const current = (await $`gh api ${`repos/${repo}/contents/${path}`} -f ref=${branch}`.json()) as {
const current = (await $`gh api ${`repos/${repo}/contents/${path}?ref=${encodeURIComponent(branch)}`}`.json()) as {
content: string
encoding: string
sha: string
Expand Down
75 changes: 53 additions & 22 deletions .kilo/skills/release-jetbrains/script/watch-publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ console.log(`runUrl=${url}`)

await $`gh run watch ${id} --repo ${repo} --exit-status`

const rel = (await $`gh release view ${`jetbrains/v${ver}`} --repo ${repo} --json url,isPrerelease`.json()) as {
url: string
isPrerelease: boolean
}
const rel = await retry(
async () =>
(await $`gh release view ${`jetbrains/v${ver}`} --repo ${repo} --json url,isPrerelease`.json()) as {
url: string
isPrerelease: boolean
},
"view release",
)
console.log(
JSON.stringify(
{
Expand All @@ -56,7 +60,15 @@ console.log(

async function merge() {
const before = new Set((await runs()).map((run) => run.databaseId))
await $`gh pr merge ${pr} --repo ${repo} --merge`
try {
await $`gh pr merge ${pr} --repo ${repo} --merge`
} catch (err) {
if (await merged()) {
console.warn(`PR ${pr} is already merged; looking for the publish workflow run`)
return await find()
}
throw err
}

for (const _ of Array.from({ length: 120 })) {
const run = (await runs()).find((item) => item.headBranch === branch && !before.has(item.databaseId))
Expand All @@ -68,30 +80,49 @@ async function merge() {

async function find() {
for (const _ of Array.from({ length: 120 })) {
const run = (await runs()).find((item) => item.headBranch === branch && active(item.status))
const run = (await runs()).find((item) => item.headBranch === branch)
if (run) return String(run.databaseId)
await Bun.sleep(1000)
}
throw new Error(
`No ${workflow} run found for ${branch}. Merge PR ${pr} first, or pass --merge to merge it automatically.`,
)
throw new Error(`No ${workflow} run found for ${branch}. Merge PR ${pr} first, or pass --merge to merge it automatically.`)
}

function active(status: string) {
return (
status === "queued" ||
status === "in_progress" ||
status === "waiting" ||
status === "requested" ||
status === "pending"
async function merged() {
const info = await retry(
async () => (await $`gh pr view ${pr} --repo ${repo} --json state`.json()) as { state: string },
"check PR state",
)
return info.state === "MERGED"
}

async function runs() {
return (await $`gh run list --repo ${repo} --workflow ${workflow} --event pull_request --json databaseId,createdAt,headBranch,status --limit 100`.json()) as {
databaseId: number
createdAt: string
headBranch: string
status: string
}[]
return await retry(
async () =>
(await $`gh run list --repo ${repo} --workflow ${workflow} --event pull_request --json databaseId,createdAt,headBranch,status --limit 100`.json()) as {
databaseId: number
createdAt: string
headBranch: string
status: string
}[],
"list workflow runs",
)
}

async function retry<T>(task: () => Promise<T>, label: string, tries = 5): Promise<T> {
try {
return await task()
} catch (err) {
if (tries <= 1 || !transient(err)) throw err
console.warn(`${label} failed with a transient GitHub error; retrying (${tries - 1} left): ${message(err)}`)
await Bun.sleep(2000)
return await retry(task, label, tries - 1)
}
}

function transient(err: unknown) {
return /\bHTTP 5\d\d\b|\b50[234]\b|Bad Gateway|Gateway Timeout|Service Unavailable/i.test(message(err))
}

function message(err: unknown) {
return err instanceof Error ? err.message : String(err)
}
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Kilo CLI is an open source AI coding agent that generates code from natural lang
- **Dev**: `bun run dev` (runs from root) or `bun run --cwd packages/opencode --conditions=browser src/index.ts`
- **Dev with params**: `bun dev -- help`
- **Extension**: `bun run extension` (build + launch VS Code with the extension in dev mode). Pass `--no-build` to skip the build.
- **Typecheck**: `bun turbo typecheck` (uses `tsgo`, not `tsc`). Includes the JetBrains plugin requires Java 21. Check with `java -version` before running. If missing, install via SDKMAN: `sdk install java 21-tem && sdk use java 21-tem`. If SDKMAN is not installed, see https://sdkman.io/install.
- **Typecheck**: `bun turbo typecheck` (uses `tsgo`, not `tsc`). Includes the JetBrains plugin and requires Java 21; do not run `java -version` as a routine preflight. Only check Java when a Gradle/Java command fails with a Java-version or missing-Java error. If missing, install via SDKMAN: `sdk install java 21-tem && sdk use java 21-tem`. If SDKMAN is not installed, see https://sdkman.io/install.
- **Test**: `bun test` from `packages/opencode/` (NOT from root -- root blocks tests)
- **Single test**: `bun test ./test/tool/tool-define.test.ts` from `packages/opencode/`
- **CLI build artifact size check**: after `bun run script/build.ts --single --skip-install` in `packages/opencode/`, use `du -h dist/*/*/bin/kilo` (scoped package output lives under `dist/@kilocode/`)
Expand All @@ -35,7 +35,7 @@ Before saying an implementation is ready, run the smallest relevant checks that
| CLI | From `packages/opencode/`: `bun run typecheck`, `bun test` or targeted `bun test ./path/to/file.test.ts` |
| VS Code extension | From `packages/kilo-vscode/`: `bun run typecheck`, `bun run lint`, `bun run test:unit` or `bun run test` |
| Extension build/package | From `packages/kilo-vscode/`: `bun run compile` or `bun run package` when touching build, packaging, SDK, or webview integration paths |
| JetBrains plugin | From `packages/kilo-jetbrains/`: `./gradlew typecheck`, `./gradlew test`. Requires Java 21 — check first with `java -version`. Install via SDKMAN if missing: `sdk install java 21-tem && sdk use java 21-tem`. |
| JetBrains plugin | From `packages/kilo-jetbrains/`: `./gradlew typecheck`, `./gradlew test`. Requires Java 21; do not run `java -version` as a routine preflight. Check Java only after a Java-version or missing-Java failure. |
| CI-only guards | Run affected guards documented above, such as `bun run knip`, `bun run check-kilocode-change`, `bun run script/check-opencode-annotations.ts`, or source link extraction |

Never run root `bun test`; the root script prints `do not run tests from root` and exits with code 1. Use package-level tests instead.
Expand Down
1 change: 1 addition & 0 deletions packages/kilo-jetbrains/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ For blocking I/O in coroutines, move the dispatcher switch inside the callee usi
- **Typecheck**: `bun run typecheck` or `./gradlew typecheck` from `packages/kilo-jetbrains/` — compiles all Kotlin sources including the generated API client. Does NOT require CLI binaries.
- **Full build**: `bun run build` from `packages/kilo-jetbrains/` (prepares CLI binaries + runs Gradle `buildPlugin`).
- **Gradle only**: `./gradlew buildPlugin` from `packages/kilo-jetbrains/` (requires CLI binaries already present in `backend/build/generated/cli/`; run `bun run build --prepare-cli` first).
- **Java checks**: Do not run `java -version` as a routine preflight. Gradle commands already fail clearly when Java is missing or incompatible; check Java only when diagnosing that failure mode.
- **Via Turbo**: `bun turbo build --filter=@kilocode/kilo-jetbrains` from repo root.
- **Run in sandbox**: `./gradlew runIde` — launches sandboxed IntelliJ with the plugin. Does NOT build CLI binaries.
- **Run split backend**: `./gradlew runIdeBackend` — if it exits shortly after startup, check for an orphaned Java process from a previous backend run and kill it before restarting.
Expand Down
Loading