refactor: kilo compat for v1.17.9

This commit is contained in:
marius-kilocode
2026-07-22 13:31:23 +02:00
parent 95db2da8e9
commit a776bd4d29
5476 changed files with 27305 additions and 719938 deletions
+4 -5
View File
@@ -1,6 +1,5 @@
name: Bug report
description: Report an issue that should be fixed
labels: ["bug"]
description: Report an issue that should be fixed (avoid pasting giant AI generated summaries or your issue may be closed/ignored)
body:
- type: textarea
id: description
@@ -20,10 +19,10 @@ body:
required: false
- type: input
id: kilo-version
id: opencode-version
attributes:
label: Kilo version
description: What version of Kilo are you using?
label: OpenCode version
description: What version of OpenCode are you using?
validations:
required: false
+2 -2
View File
@@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Join our Discord
url: https://kilo.ai/discord
- name: 💬 Discord Community
url: https://discord.gg/opencode
about: For quick questions or real-time discussion. Note that issues are searchable and help others with the same question.
@@ -1,6 +1,5 @@
name: 🚀 Feature Request
description: Suggest an idea, feature, or enhancement
labels: [discussion]
title: "[FEATURE]:"
body:
-1
View File
@@ -1,6 +1,5 @@
name: Question
description: Ask a question
labels: ["question"]
body:
- type: textarea
id: question
+4 -49
View File
@@ -33,10 +33,7 @@ runs:
shell: bash
run: echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT"
# Restoring and extracting the ~1 GB cache took 2m23s on Windows, while a # kilocode_change
# fresh install took 1m27s. Keep Windows off this cache until that reverses. # kilocode_change
- name: Restore Bun dependencies
if: runner.os != 'Windows' # kilocode_change
id: bun-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
@@ -45,66 +42,24 @@ runs:
restore-keys: |
${{ runner.os }}-bun-
# kilocode_change start
- name: Setup Node for native dependency builds
if: runner.os != 'Windows'
uses: actions/setup-node@v6
with:
node-version: "24"
package-manager-cache: false
- name: Configure node-gyp Node headers
if: runner.os != 'Windows'
id: node-gyp
run: |
node <<'NODE'
const fs = require("node:fs")
const path = require("node:path")
const exe = path.dirname(fs.realpathSync(process.execPath))
const dirs = [exe, path.dirname(exe)]
const root = dirs.find((dir) => fs.existsSync(path.join(dir, "include", "node", "node.h")))
if (!root) {
throw new Error(`Node headers not found under ${dirs.join(", ")}`)
}
fs.appendFileSync(process.env.GITHUB_OUTPUT, `nodedir=${root}\n`)
NODE
shell: bash
# kilocode_change end
- name: Install setuptools for distutils compatibility
run: python3 -m pip install setuptools || pip install setuptools || true
shell: bash
- name: Install dependencies
run: |
# kilocode_change start
if [ "$RUNNER_OS" != "Windows" ]; then
export npm_config_nodedir="${{ steps.node-gyp.outputs.nodedir }}"
fi
# kilocode_change end
# Workaround for patched peer variants
# e.g. ./patches/ for standard-openapi
# https://github.com/oven-sh/bun/issues/28147 # kilocode_change
# https://github.com/oven-sh/bun/issues/28147
if [ "$RUNNER_OS" = "Windows" ]; then
# kilocode_change start
if ! bun install --frozen-lockfile --linker hoisted ${{ inputs.install-flags }}; then
echo "::warning::Bun install failed on Windows; retrying with conservative extraction"
sleep 5
BUN_FEATURE_FLAG_DISABLE_STREAMING_INSTALL=1 \
bun install --frozen-lockfile --linker hoisted --network-concurrency 16 ${{ inputs.install-flags }}
fi
# kilocode_change end
bun install --linker hoisted ${{ inputs.install-flags }}
else
bun install --frozen-lockfile ${{ inputs.install-flags }} # kilocode_change
bun install ${{ inputs.install-flags }}
fi
shell: bash
# Do not upload a Windows cache that Windows jobs intentionally never restore. # kilocode_change
- name: Save Bun dependencies
if: runner.os != 'Windows' && steps.bun-cache.outputs.cache-hit != 'true' && github.event_name != 'pull_request' && github.event_name != 'pull_request_target' # kilocode_change
if: steps.bun-cache.outputs.cache-hit != 'true' && github.event_name != 'pull_request' && github.event_name != 'pull_request_target'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.cache.outputs.dir }}
+6 -19
View File
@@ -1,14 +1,12 @@
name: "Setup Git Committer"
description: "Create app token and configure git user"
inputs:
# kilocode_change start
kilo-maintainer-app-id:
description: "Kilo Maintainer GitHub App ID"
opencode-app-id:
description: "OpenCode GitHub App ID"
required: true
kilo-maintainer-app-secret:
description: "Kilo Maintainer GitHub App private key"
opencode-app-secret:
description: "OpenCode GitHub App private key"
required: true
# kilocode_change end
outputs:
token:
description: "GitHub App token"
@@ -23,10 +21,8 @@ runs:
id: apptoken
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
with:
# kilocode_change start
app-id: ${{ inputs['kilo-maintainer-app-id'] }}
private-key: ${{ inputs['kilo-maintainer-app-secret'] }}
# kilocode_change end
app-id: ${{ inputs.opencode-app-id }}
private-key: ${{ inputs.opencode-app-secret }}
owner: ${{ github.repository_owner }}
- name: Configure git user
@@ -39,15 +35,6 @@ runs:
- name: Clear checkout auth
run: |
git config --local --unset-all http.https://github.com/.extraheader || true
# kilocode_change start
keys="$(git config --local --name-only --get-regexp '^includeIf\.gitdir:' || true)"
for key in $keys; do
path="$(git config --local --get "$key" || true)"
case "$path" in
*git-credentials-*.config) git config --local --unset-all "$key" || true ;;
esac
done
# kilocode_change end
shell: bash
- name: Configure git remote
-13
View File
@@ -1,13 +0,0 @@
# kilocode_change - new file
name: "Setup Kilo"
description: "Install Kilo CLI globally"
runs:
using: "composite"
steps:
- name: Install Kilo CLI
run: curl -fsSL https://kilo.ai/cli/install | bash
shell: bash
- name: Add Kilo to PATH
run: echo "$HOME/.kilo/bin" >> $GITHUB_PATH
shell: bash
@@ -1,21 +0,0 @@
# kilocode_change - new file
name: "Setup Linux Sandbox"
description: "Build the Linux bubblewrap helper"
runs:
using: "composite"
steps:
- name: Setup Zig
run: |
curl --fail --location --retry 3 \
https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz \
--output "$RUNNER_TEMP/zig.tar.xz"
echo "473ec26806133cf4d1918caf1a410f8403a13d979726a9045b421b685031a982 $RUNNER_TEMP/zig.tar.xz" | sha256sum --check --status
tar -xJf "$RUNNER_TEMP/zig.tar.xz" -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/zig-linux-x86_64-0.14.0" >> "$GITHUB_PATH"
shell: bash
- name: Build bubblewrap helper
run: |
bun packages/opencode/script/kilocode/bubblewrap.ts --arch x64 --output "$RUNNER_TEMP/bwrap"
echo "KILO_BWRAP_PATH=$RUNNER_TEMP/bwrap" >> "$GITHUB_ENV"
shell: bash
-12
View File
@@ -1,12 +0,0 @@
# kilocode_change - new file
name: Critical-only CodeQL config
query-filters:
- include:
kind:
- problem
- path-problem
- alert
- path-alert
tags contain: security
security-severity: /^(9(\.[0-9])?|10(\.0)?)$/
+17 -62
View File
@@ -1,74 +1,29 @@
## Issue
### Issue for this PR
<!-- Reference an existing issue with `Fixes #123`, `Closes #123`, or equivalent linked issue wording. -->
Closes #
Fixes #
### Type of change
## Context
- [ ] Bug fix
- [ ] New feature
- [ ] Refactor / code improvement
- [ ] Documentation
<!-- Brief description of WHAT youre doing and WHY. -->
### What does this PR do?
## Implementation
Please provide a description of the issue, the changes you made to fix it, and why they work. It is expected that you understand why your changes work and if you do not understand why at least say as much so a maintainer knows how much to value the PR.
<!--
**If you paste a large clearly AI generated description here your PR may be IGNORED or CLOSED!**
Some description of HOW you achieved it. Perhaps give a high level description of the program flow. Did you need to refactor something? What tradeoffs did you take? Are there things in here which youd particularly like people to pay close attention to? Keep this focused on context reviewers cannot infer from the diff; skip file-by-file summaries, placeholders, and other filler.
### How did you verify your code works?
-->
### Screenshots / recordings
## Screenshots / Video
_If this is a UI change, please include a screenshot or recording._
<!-- Required for visual changes. Include the relevant before/after or resulting state. -->
### Checklist
| before | after |
|---|---|
| | |
- [ ] I have tested my changes locally
- [ ] I have not included unrelated changes in this PR
## How to Test
### Manual/local verification
<!--
Describe local CLI, extension, or docs verification. Example:
- Opened the updated settings page and confirmed the new copy appears
-->
-
### Reviewer test steps
<!--
Provide steps reviewers can retrace. Example:
1. Sign in with a user with tracks
2. Activate `show_awesome_cat_gifs` feature by adding `?feature.show_awesome_cat_gifs=1` to your URL
3. Confirm you see a GIF with cats dancing
-->
-
### Blocked checks and substitute verification
<!--
If a relevant command could not be completed, name the command, explain the blocker or failure, and describe the substitute verification performed. Example:
- `bun run test:integration` could not complete because the required API key is unavailable; substitute verification was testing the affected flow manually in the development extension
-->
-
<!--
Every PR marked ready for review must include testing evidence. A bare "Not tested" or "N/A" answer is not sufficient. For each piece of evidence make clear if the test was executed by the agent or by a human
Docs-only, config-only, and similar changes still need concrete evidence. For examples, see [Testing Evidence for Pull Requests](https://kilo.ai/docs/contributing/development-environment#testing-evidence-for-pull-requests). Draft PRs may be incomplete until marked ready for review.
-->
## Checklist
- [ ] Issue linked above, or exception explained
- [ ] Tests/verification described
- [ ] Screenshots/video included for visual changes, or marked N/A
- [ ] Changeset considered for user-facing changes
- [ ] I personally reviewed the diff and can explain the changes, including any AI-assisted work.
## Get in Touch
<!-- We'd love to have a way to chat with you about your changes if necessary. If you're in the [Kilo Code Discord](https://kilo.ai/discord), please share your handle here. -->
_If you do not follow this template your PR will be automatically rejected._
-116
View File
@@ -1,116 +0,0 @@
name: Auto-docs dry-run intake
# Trigger on merged feature PRs, or manually with a specific PR number.
# IMPORTANT: This workflow intentionally does NOT check out PR code and does NOT
# execute any code from the PR branch. It only reads PR metadata and forwards it
# to a webhook. This is required for safe use of pull_request_target on a public repo.
on:
pull_request_target:
types: [closed]
workflow_dispatch:
inputs:
pr_number:
description: "PR number to test"
required: true
# Minimal permissions: read repo contents and PR metadata only.
permissions:
contents: read
pull-requests: read
# One run per PR at a time. Does not cancel in progress — let the current run
# finish so we don't drop events when a PR is quickly closed/reopened/closed.
concurrency:
group: auto-docs-${{ github.event.pull_request.number || inputs.pr_number }}
cancel-in-progress: false
jobs:
call-valtown:
# kilocode_change start
if: >
github.event_name == 'workflow_dispatch' ||
(
github.repository == 'Kilo-Org/kilocode' &&
github.event.pull_request.merged == true &&
(
startsWith(github.event.pull_request.title, 'feat:') ||
startsWith(github.event.pull_request.title, 'feat(')
)
)
# kilocode_change end
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Build webhook payload
env:
GH_TOKEN: ${{ github.token }}
EVENT_NAME: ${{ github.event_name }}
REPO: ${{ github.repository }}
PR_NUMBER_FROM_EVENT: ${{ github.event.pull_request.number }}
PR_NUMBER_FROM_INPUT: ${{ inputs.pr_number }}
run: |
set -euo pipefail
PR_NUMBER="${PR_NUMBER_FROM_EVENT:-$PR_NUMBER_FROM_INPUT}"
if [ -z "$PR_NUMBER" ]; then
echo "Missing PR number"
exit 1
fi
gh api "repos/$REPO/pulls/$PR_NUMBER" > pr.json
jq -n \
--arg event_name "$EVENT_NAME" \
--arg repo "$REPO" \
--arg pr_number "$PR_NUMBER" \
--slurpfile pr pr.json \
'{
event_name: $event_name,
repo: $repo,
pr_number: $pr_number,
title: $pr[0].title,
description: ($pr[0].body // ""),
author: $pr[0].user.login,
merged_at: ($pr[0].merged_at // ""),
pr_url: $pr[0].html_url,
base_branch: $pr[0].base.ref,
head_branch: $pr[0].head.ref
}' > payload.json
echo "Payload created:"
jq '{
event_name,
repo,
pr_number,
title,
author,
merged_at,
pr_url,
base_branch,
head_branch
}' payload.json
- name: Send webhook to Val Town
env:
DOC_WEBHOOK_URL: ${{ secrets.DOC_WEBHOOK_URL }}
DOC_WEBHOOK_SECRET: ${{ secrets.DOC_WEBHOOK_SECRET }}
run: |
set -euo pipefail
if [ -z "${DOC_WEBHOOK_URL:-}" ]; then
echo "DOC_WEBHOOK_URL secret is not set"
exit 1
fi
if [ -z "${DOC_WEBHOOK_SECRET:-}" ]; then
echo "DOC_WEBHOOK_SECRET secret is not set"
exit 1
fi
curl --fail-with-body -sS -X POST "$DOC_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "X-Docs-Webhook-Secret: $DOC_WEBHOOK_SECRET" \
--data-binary @payload.json
+9 -9
View File
@@ -7,31 +7,31 @@ on:
jobs:
sync:
if: github.repository == 'Kilo-Org/kilocode'
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v6 # kilocode_change
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false # kilocode_change
fetch-depth: 0
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Setup Git Committer
id: committer
id: setup-git-committer
uses: ./.github/actions/setup-git-committer
with:
# kilocode_change start
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
# kilocode_change end
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Install OpenCode
run: bun i -g opencode-ai
- name: Sync beta branch
env:
GH_TOKEN: ${{ steps.committer.outputs.token }}
GH_TOKEN: ${{ steps.setup-git-committer.outputs.token }}
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
run: bun script/beta.ts
@@ -1,21 +0,0 @@
# kilocode_change - new file
name: Check forbidden strings
on:
pull_request:
workflow_dispatch:
jobs:
check:
name: Check forbidden strings
if: github.repository == 'Kilo-Org/kilocode'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # kilocode_change
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- uses: oven-sh/setup-bun@v2
- name: Run check
run: bun run script/check-forbidden-strings.ts
@@ -1,27 +0,0 @@
# kilocode_change - new file
name: Check Kilo generated artifacts
on:
pull_request:
paths:
- ".gitignore"
- ".github/workflows/check-kilo-generated-artifacts.yml"
- ".kilo/**"
- ".kilocode/**"
- "script/check-kilo-generated-artifacts.ts"
workflow_dispatch:
jobs:
check:
name: Check Kilo generated artifacts
if: github.repository == 'Kilo-Org/kilocode'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # kilocode_change
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- uses: oven-sh/setup-bun@v2
- name: Run check
run: bun run script/check-kilo-generated-artifacts.ts
@@ -1,24 +0,0 @@
name: Check markdown table padding
on:
pull_request:
paths:
- "**/*.md"
- "script/check-md-table-padding.ts"
- ".github/workflows/check-md-table-padding.yml"
workflow_dispatch:
jobs:
check:
name: Check markdown table padding
if: github.repository == 'Kilo-Org/kilocode'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # kilocode_change
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- uses: oven-sh/setup-bun@v2
- name: Run check
run: bun run script/check-md-table-padding.ts
@@ -1,49 +0,0 @@
name: Check shared upstream annotations
on:
pull_request:
paths:
- ".github/**"
- "github/**"
- "packages/extensions/**"
- "packages/opencode/**"
- "packages/script/**"
- "packages/shared/**"
- "packages/storybook/**"
- "packages/ui/**"
- "script/**"
workflow_dispatch:
jobs:
check-annotations:
name: Check kilocode_change annotations
if: github.repository == 'Kilo-Org/kilocode'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # kilocode_change
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- name: Check kilocode_change annotations in shared upstream files
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
if [ -n "$BASE_SHA" ]; then
bun run script/check-opencode-annotations.ts --base "$BASE_SHA"
else
echo "No PR base SHA available (workflow_dispatch without PR context) — skipping."
fi
# kilocode_change start
- name: Check Effect Promise facade allowlist
run: bun run script/check-opencode-promise-facades.ts
- name: Check model tool network boundary
run: bun run script/check-model-tool-network.ts
- name: Check workflow allowlist
run: bun run script/check-workflows.ts
# kilocode_change end
-48
View File
@@ -1,48 +0,0 @@
name: check-org-member
on:
workflow_call:
inputs:
username:
required: true
type: string
secrets:
kilo-maintainer-app-id:
required: true
kilo-maintainer-app-secret:
required: true
outputs:
is-member:
description: Whether the user is an org member or kilo-maintainer bot
value: ${{ jobs.check.outputs['is-member'] }}
jobs:
check:
runs-on: blacksmith-2vcpu-ubuntu-2404 # kilocode_change
outputs:
is-member: ${{ steps.check.outputs['is-member'] }}
steps:
- name: Create app token
id: apptoken
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets['kilo-maintainer-app-id'] }}
private-key: ${{ secrets['kilo-maintainer-app-secret'] }}
owner: ${{ github.repository_owner }}
- name: Check if author is org member or kilo bot
id: check
env:
GITHUB_TOKEN: ${{ steps.apptoken.outputs.token }}
USERNAME: ${{ inputs.username }}
run: |
if [[ "$USERNAME" == "kilo-maintainer[bot]" || "$USERNAME" == "kiloconnect[bot]" || "$USERNAME" == "kiloconnect-lite[bot]" ]]; then
echo "is-member=true" >> "$GITHUB_OUTPUT"
echo "User is a kilo bot"
elif gh api orgs/Kilo-Org/members/"$USERNAME" --silent 2>/dev/null; then
echo "is-member=true" >> "$GITHUB_OUTPUT"
echo "User is an org member"
else
echo "is-member=false" >> "$GITHUB_OUTPUT"
echo "User is not an org member"
fi
-69
View File
@@ -1,69 +0,0 @@
# kilocode_change - new file
name: "CodeQL Kotlin"
on:
push:
branches: ["main"]
paths:
- "packages/kilo-jetbrains/**"
- ".github/workflows/codeql-kotlin.yml"
pull_request:
branches: ["main"]
paths:
- "packages/kilo-jetbrains/**"
- ".github/workflows/codeql-kotlin.yml"
schedule:
- cron: "29 10 * * 5"
workflow_dispatch:
jobs:
analyze:
name: Analyze (java-kotlin)
if: github.event_name == 'workflow_dispatch' || github.repository == 'Kilo-Org/kilocode'
runs-on: ubuntu-latest
permissions:
security-events: write
packages: read
actions: read
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Free disk space for CodeQL
shell: bash
run: |
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /usr/local/share/boost
docker system prune --all --force || true
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: java-kotlin
build-mode: manual
config-file: ./.github/codeql/codeql-config.yml
- name: Build Java/Kotlin
shell: bash
run: ./gradlew typecheck --rerun-tasks --no-build-cache
working-directory: packages/kilo-jetbrains
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:java-kotlin"
-82
View File
@@ -1,82 +0,0 @@
# kilocode_change - new file
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
schedule:
- cron: "29 10 * * 5"
workflow_dispatch:
jobs:
analyze:
name: Analyze (${{ matrix.language }})
if: github.event_name == 'workflow_dispatch' || github.repository == 'Kilo-Org/kilocode'
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: actions
build-mode: none
- language: javascript-typescript
build-mode: none
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
config-file: ./.github/codeql/codeql-config.yml
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"
+7 -15
View File
@@ -3,7 +3,7 @@ name: containers
on:
push:
branches:
- main # kilocode_change
- dev
paths:
- packages/containers/**
- .github/workflows/containers.yml
@@ -16,18 +16,12 @@ permissions:
jobs:
build:
if: github.event_name == 'workflow_dispatch' || github.repository == 'Kilo-Org/kilocode' # kilocode_change
runs-on: blacksmith-4vcpu-ubuntu-2404
env:
REGISTRY: ghcr.io/${{ github.repository_owner }}
TAG: "24.04"
steps:
# kilocode_change start
- name: Set lowercase repository owner
id: repo
run: echo "owner_lc=${OWNER,,}" >> $GITHUB_OUTPUT
env:
OWNER: ${{ github.repository_owner }}
# kilocode_change end
- uses: actions/checkout@v6 # kilocode_change
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: ./.github/actions/setup-bun
@@ -47,7 +41,5 @@ jobs:
- name: Build and push containers
run: bun ./packages/containers/script/build.ts --push
env:
# kilocode_change start
REGISTRY: ghcr.io/${{ steps.repo.outputs.owner_lc }}
TAG: "24.04"
# kilocode_change end
REGISTRY: ${{ env.REGISTRY }}
TAG: ${{ env.TAG }}
@@ -1,38 +0,0 @@
name: kilo
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
jobs:
kilo:
if: |
(github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') &&
(
contains(github.event.comment.body, ' /kc') ||
startsWith(github.event.comment.body, '/kc') ||
contains(github.event.comment.body, ' /kilo') ||
startsWith(github.event.comment.body, '/kilo')
)
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
id-token: write
contents: read
pull-requests: read
issues: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: ./.github/actions/setup-bun
- name: Run opencode
uses: Kilo-Org/kilocode/github@latest
env:
KILO_API_KEY: ${{ secrets.KILO_API_KEY }}
KILO_ORG_ID: ${{ secrets.KILO_ORG_ID }}
KILO_PERMISSION: '{"bash": "deny"}'
with:
model: kilo/kilo-auto/frontier
@@ -1,46 +0,0 @@
name: nix-desktop
on:
push:
branches: [main]
paths:
- "flake.nix"
- "flake.lock"
- "nix/**"
- "packages/app/**"
- "packages/desktop/**"
- ".github/workflows/nix-desktop.yml"
pull_request:
paths:
- "flake.nix"
- "flake.lock"
- "nix/**"
- "packages/app/**"
- "packages/desktop/**"
- ".github/workflows/nix-desktop.yml"
workflow_dispatch:
jobs:
nix-desktop:
strategy:
fail-fast: false
matrix:
os:
- blacksmith-4vcpu-ubuntu-2404
- blacksmith-4vcpu-ubuntu-2404-arm
- macos-15-intel
- macos-latest
runs-on: ${{ matrix.os }}
timeout-minutes: 60
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Nix
uses: nixbuild/nix-quick-install-action@v34
- name: Build desktop via flake
run: |
set -euo pipefail
nix --version
nix build .#desktop -L
@@ -1,35 +0,0 @@
name: "sync-zed-extension"
on:
workflow_dispatch:
release:
types: [published]
jobs:
zed:
name: Release Zed Extension
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
- uses: ./.github/actions/setup-bun
- name: Get version tag
id: get_tag
run: |
if [ "${{ github.event_name }}" = "release" ]; then
TAG="${{ github.event.release.tag_name }}"
else
TAG=$(git tag --list 'v[0-9]*.*' --sort=-version:refname | head -n 1)
fi
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "Using tag: ${TAG}"
- name: Sync Zed extension
run: |
./script/sync-zed.ts ${{ steps.get_tag.outputs.tag }}
env:
ZED_EXTENSIONS_PAT: ${{ secrets.ZED_EXTENSIONS_PAT }}
ZED_PR_PAT: ${{ secrets.ZED_PR_PAT }}
-30
View File
@@ -1,30 +0,0 @@
name: docs-build
on:
push:
branches: [main]
paths:
- "packages/kilo-docs/**"
pull_request:
paths:
- "packages/kilo-docs/**"
workflow_dispatch:
jobs:
build:
name: Build docs site
runs-on: blacksmith-4vcpu-ubuntu-2404 # kilocode_change
steps:
- name: Checkout repository
uses: actions/checkout@v6 # kilocode_change
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Build site
run: bun run --filter @kilocode/kilo-docs build
env:
NEXT_PUBLIC_POSTHOG_KEY: ${{ secrets.POSTHOG_API_KEY }}
- name: Run tests
run: bun run --filter @kilocode/kilo-docs test
-29
View File
@@ -1,29 +0,0 @@
name: Check Links
on:
push:
branches: [main]
pull_request:
paths:
- "packages/kilo-docs/**"
- ".github/workflows/docs-check-links.yml"
schedule:
# Run daily at 9am UTC
- cron: "0 9 * * *"
workflow_dispatch: # Allow manual trigger
jobs:
link-checker:
if: github.repository == 'Kilo-Org/kilocode'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # kilocode_change
- name: Link Checker
uses: Kilo-Org/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411
with:
args: "**/*.md"
workingDirectory: packages/kilo-docs
fail: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -20,13 +20,13 @@ jobs:
- uses: ./.github/actions/setup-bun
- name: Install opencode
run: curl -fsSL https://kilo.ai/install | bash
run: curl -fsSL https://opencode.ai/install | bash
- name: Check duplicates and compliance
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KILO_PERMISSION: |
OPENCODE_PERMISSION: |
{
"bash": {
"*": "deny",
@@ -118,7 +118,7 @@ jobs:
Remember: post at most ONE comment combining all findings. If everything is fine, post nothing."
recheck-compliance:
if: github.event.action == 'edited' && contains(github.event.issue.labels.*.name, 'needs:compliance') # kilocode_change
if: github.event.action == 'edited' && contains(github.event.issue.labels.*.name, 'needs:compliance')
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: read
@@ -132,13 +132,13 @@ jobs:
- uses: ./.github/actions/setup-bun
- name: Install opencode
run: curl -fsSL https://kilo.ai/install | bash
run: curl -fsSL https://opencode.ai/install | bash
- name: Recheck compliance
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KILO_PERMISSION: |
OPENCODE_PERMISSION: |
{
"bash": {
"*": "deny",
+4 -11
View File
@@ -7,30 +7,23 @@ on:
jobs:
generate:
if: github.repository == 'Kilo-Org/kilocode'
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v6 # kilocode_change
# kilocode_change start
with:
persist-credentials: false
# kilocode_change end
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Setup Git Committer
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
# kilocode_change start
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
# kilocode_change end
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Generate
run: ./script/generate.ts
-366
View File
@@ -1,366 +0,0 @@
# kilocode_change - new file
name: kilo-auto-close
on:
workflow_dispatch:
inputs:
dryRun:
description: "Log actions without closing items"
type: boolean
default: true
schedule:
- cron: "0 6 * * *"
permissions:
contents: read
issues: write
pull-requests: write
jobs:
close:
if: github.repository == 'Kilo-Org/kilocode'
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 30
steps:
- name: Close inactive PRs and issues
uses: actions/github-script@v8
env:
KILO_AUTO_CLOSE_ENABLED: ${{ vars.KILO_AUTO_CLOSE_ENABLED }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const PR_DAYS_INACTIVE = 30
const ISSUE_DAYS_INACTIVE = 60
const MAX_RETRIES = 3
// Adaptive delay: fast for small batches, slower for large to respect
// GitHub's 80 content-generating requests/minute limit
const SMALL_BATCH_THRESHOLD = 10
const SMALL_BATCH_DELAY_MS = 1000 // 1s for daily operations (≤10 items)
const LARGE_BATCH_DELAY_MS = 2000 // 2s for backlog (>10 items) = ~30 ops/min, well under 80 limit
const startTime = Date.now()
const prCutoff = new Date(Date.now() - PR_DAYS_INACTIVE * 24 * 60 * 60 * 1000)
const issueCutoff = new Date(Date.now() - ISSUE_DAYS_INACTIVE * 24 * 60 * 60 * 1000)
const { owner, repo } = context.repo
const dryRunInput = context.payload.inputs?.dryRun
const enabled = process.env.KILO_AUTO_CLOSE_ENABLED === "true"
const dryRun = dryRunInput === undefined
? !enabled
: dryRunInput !== "false"
core.info(`Dry run mode: ${dryRun}`)
core.info(`PR cutoff date: ${prCutoff.toISOString()}`)
core.info(`Issue cutoff date: ${issueCutoff.toISOString()}`)
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function withRetry(fn, description = 'API call') {
let lastError
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
try {
const result = await fn()
return result
} catch (error) {
lastError = error
const isRateLimited = error.status === 403 &&
(error.message?.includes('rate limit') || error.message?.includes('secondary'))
if (!isRateLimited) {
throw error
}
if (attempt === MAX_RETRIES - 1) {
break
}
// Parse retry-after header, default to 60 seconds
const retryAfter = error.response?.headers?.['retry-after']
? parseInt(error.response.headers['retry-after'])
: 60
// Exponential backoff: retryAfter * 2^attempt
const backoffMs = retryAfter * 1000 * Math.pow(2, attempt)
core.warning(`${description}: Rate limited (attempt ${attempt + 1}/${MAX_RETRIES}). Waiting ${backoffMs / 1000}s before retry...`)
await sleep(backoffMs)
}
}
core.error(`${description}: Max retries (${MAX_RETRIES}) exceeded`)
throw lastError
}
const query = `
query($owner: String!, $repo: String!, $cursor: String) {
repository(owner: $owner, name: $repo) {
pullRequests(first: 100, states: OPEN, after: $cursor) {
pageInfo {
hasNextPage
endCursor
}
nodes {
number
title
author {
login
}
createdAt
commits(last: 1) {
nodes {
commit {
committedDate
}
}
}
comments(last: 1) {
nodes {
createdAt
}
}
reviews(last: 1) {
nodes {
createdAt
}
}
reviewThreads(last: 100) {
nodes {
comments(last: 1) {
nodes {
createdAt
}
}
}
}
}
}
}
}
`
const allPrs = []
let cursor = null
let hasNextPage = true
let pageCount = 0
while (hasNextPage) {
pageCount++
core.info(`Fetching page ${pageCount} of open PRs...`)
const result = await withRetry(
() => github.graphql(query, { owner, repo, cursor }),
`GraphQL page ${pageCount}`
)
allPrs.push(...result.repository.pullRequests.nodes)
hasNextPage = result.repository.pullRequests.pageInfo.hasNextPage
cursor = result.repository.pullRequests.pageInfo.endCursor
core.info(`Page ${pageCount}: fetched ${result.repository.pullRequests.nodes.length} PRs (total: ${allPrs.length})`)
// Delay between pagination requests (use small batch delay for reads)
if (hasNextPage) {
await sleep(SMALL_BATCH_DELAY_MS)
}
}
core.info(`Found ${allPrs.length} open pull requests`)
function entry(source, date) {
if (!date) return null
return { source, date: new Date(date) }
}
function latest(items) {
return items.filter(Boolean).sort((a, b) => b.date.getTime() - a.date.getTime())[0]
}
const stalePrs = allPrs.flatMap((pr) => {
const activity = latest([
entry("created", pr.createdAt),
entry("commit", pr.commits.nodes[0]?.commit.committedDate),
entry("comment", pr.comments.nodes[0]?.createdAt),
entry("review", pr.reviews.nodes[0]?.createdAt),
...pr.reviewThreads.nodes.map((t) => entry("review comment", t.comments.nodes[0]?.createdAt)),
])
const text = activity
? `${activity.date.toISOString()} via ${activity.source}`
: "unknown"
if (!activity || activity.date > prCutoff) {
core.info(`PR #${pr.number} is fresh (last activity: ${text})`)
return []
}
core.info(`PR #${pr.number} is STALE (last activity: ${text})`)
return [{ ...pr, activity }]
})
core.info(`Found ${stalePrs.length} stale pull requests`)
const prDelayMs = stalePrs.length > SMALL_BATCH_THRESHOLD
? LARGE_BATCH_DELAY_MS
: SMALL_BATCH_DELAY_MS
core.info(`Using ${prDelayMs}ms delay between PR operations (${stalePrs.length > SMALL_BATCH_THRESHOLD ? 'large' : 'small'} batch mode)`)
let closedPrCount = 0
let skippedPrCount = 0
for (const pr of stalePrs) {
const issue_number = pr.number
const closeComment = `To stay organized pull requests are automatically closed after ${PR_DAYS_INACTIVE} days of inactivity. If the pull request is still relevant please reopen it or create a fresh new one.`
if (dryRun) {
core.info(`[dry-run] Would close PR #${issue_number} from ${pr.author?.login || 'unknown'} (last activity: ${pr.activity.date.toISOString()} via ${pr.activity.source}): ${pr.title}`)
continue
}
try {
// Add comment
await withRetry(
() => github.rest.issues.createComment({
owner,
repo,
issue_number,
body: closeComment,
}),
`Comment on PR #${issue_number}`
)
// Close PR
await withRetry(
() => github.rest.pulls.update({
owner,
repo,
pull_number: issue_number,
state: "closed",
}),
`Close PR #${issue_number}`
)
closedPrCount++
core.info(`Closed PR #${issue_number} from ${pr.author?.login || 'unknown'} (last activity: ${pr.activity.date.toISOString()} via ${pr.activity.source}): ${pr.title}`)
// Delay before processing next PR
await sleep(prDelayMs)
} catch (error) {
skippedPrCount++
core.error(`Failed to close PR #${issue_number}: ${error.message}`)
}
}
let page = 1
let stop = false
const staleIssues = []
while (!stop) {
core.info(`Fetching page ${page} of open issues...`)
const result = await withRetry(
() => github.rest.issues.listForRepo({
owner,
repo,
state: "open",
sort: "updated",
direction: "asc",
per_page: 100,
page,
}),
`Issues page ${page}`
)
if (!result.data.length) {
break
}
core.info(`Page ${page}: fetched ${result.data.length} issues`)
for (const issue of result.data) {
const updated = new Date(issue.updated_at)
if (updated >= issueCutoff) {
core.info(`Found fresh issue/PR #${issue.number} (${updated.toISOString()}), stopping issue scan`)
stop = true
break
}
if (issue.pull_request) {
core.info(`Skipping PR #${issue.number} in issue scan`)
continue
}
staleIssues.push({ ...issue, activity: updated })
}
if (!stop) {
page++
await sleep(SMALL_BATCH_DELAY_MS)
}
}
core.info(`Found ${staleIssues.length} stale issues`)
const issueDelayMs = staleIssues.length > SMALL_BATCH_THRESHOLD
? LARGE_BATCH_DELAY_MS
: SMALL_BATCH_DELAY_MS
core.info(`Using ${issueDelayMs}ms delay between issue operations (${staleIssues.length > SMALL_BATCH_THRESHOLD ? 'large' : 'small'} batch mode)`)
let closedIssueCount = 0
let skippedIssueCount = 0
for (const issue of staleIssues) {
const closeComment = `To stay organized issues are automatically closed after ${ISSUE_DAYS_INACTIVE} days of no activity. If the issue is still relevant please reopen it or create a fresh new one.`
if (dryRun) {
core.info(`[dry-run] Would close issue #${issue.number} (last activity: ${issue.activity.toISOString()} via updated): ${issue.title}`)
continue
}
try {
await withRetry(
() => github.rest.issues.createComment({
owner,
repo,
issue_number: issue.number,
body: closeComment,
}),
`Comment on issue #${issue.number}`
)
await withRetry(
() => github.rest.issues.update({
owner,
repo,
issue_number: issue.number,
state: "closed",
state_reason: "not_planned",
}),
`Close issue #${issue.number}`
)
closedIssueCount++
core.info(`Closed issue #${issue.number} (last activity: ${issue.activity.toISOString()} via updated): ${issue.title}`)
await sleep(issueDelayMs)
} catch (error) {
skippedIssueCount++
core.error(`Failed to close issue #${issue.number}: ${error.message}`)
}
}
const elapsed = Math.round((Date.now() - startTime) / 1000)
core.info(`\n========== Summary ==========`)
core.info(`Total open PRs found: ${allPrs.length}`)
core.info(`Stale PRs identified: ${stalePrs.length}`)
core.info(`PRs closed: ${closedPrCount}`)
core.info(`PRs skipped (errors): ${skippedPrCount}`)
core.info(`Stale issues identified: ${staleIssues.length}`)
core.info(`Issues closed: ${closedIssueCount}`)
core.info(`Issues skipped (errors): ${skippedIssueCount}`)
core.info(`Elapsed time: ${elapsed}s`)
core.info(`=============================`)
+20 -2
View File
@@ -16,7 +16,6 @@ permissions:
jobs:
nix-eval:
if: github.repository == 'Kilo-Org/kilocode'
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 15
steps:
@@ -39,7 +38,9 @@ jobs:
nix flake show --all-systems
SYSTEMS="x86_64-linux aarch64-linux x86_64-darwin aarch64-darwin"
PACKAGES="kilo"
PACKAGES="opencode"
# TODO: move 'desktop' to PACKAGES when #11755 is fixed
OPTIONAL_PACKAGES="desktop"
echo ""
echo "=== Evaluating packages for all systems ==="
@@ -59,6 +60,23 @@ jobs:
done
done
echo ""
echo "=== Evaluating optional packages ==="
for system in $SYSTEMS; do
echo ""
echo "--- $system ---"
for pkg in $OPTIONAL_PACKAGES; do
printf " %s: " "$pkg"
if output=$(nix eval ".#packages.$system.$pkg.drvPath" --raw 2>&1); then
echo "✓"
else
echo "✗"
echo "::warning::Evaluation failed for packages.$system.$pkg"
echo "$output"
fi
done
done
echo ""
echo "=== Evaluating devShells for all systems ==="
for system in $SYSTEMS; do
+8 -12
View File
@@ -6,7 +6,7 @@ permissions:
on:
workflow_dispatch:
push:
branches: [main]
branches: [dev, beta]
paths:
- "bun.lock"
- "package.json"
@@ -25,7 +25,6 @@ jobs:
# Native runners required: bun install cross-compilation flags (--os/--cpu)
# do not produce byte-identical node_modules as native installs.
compute-hash:
if: github.repository == 'Kilo-Org/kilocode'
strategy:
fail-fast: false
matrix:
@@ -83,7 +82,7 @@ jobs:
echo "Computed hash for ${SYSTEM}: $HASH"
- name: Upload hash
uses: actions/upload-artifact@v7 # kilocode_change
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: hash-${{ matrix.system }}
path: hash.txt
@@ -91,32 +90,29 @@ jobs:
update-hashes:
needs: compute-hash
if: github.repository == 'Kilo-Org/kilocode' && github.event_name != 'pull_request'
if: github.event_name != 'pull_request'
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v6 # kilocode_change
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
fetch-depth: 0
ref: ${{ github.ref_name }}
- name: Setup Git Committer
id: committer
- name: Setup git committer
uses: ./.github/actions/setup-git-committer
with:
# kilocode_change start
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
# kilocode_change end
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Pull latest changes
run: |
git pull --rebase --autostash origin "$GITHUB_REF_NAME"
- name: Download hash artifacts
uses: actions/download-artifact@v8 # kilocode_change
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: hashes
pattern: hash-*
@@ -6,10 +6,7 @@ on:
jobs:
notify:
# kilocode_change start - disabled for kilo-cli fork (OpenCode Discord notifications)
if: false
# kilocode_change end
runs-on: depot-ubuntu-24.04
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Send nicely-formatted embed to Discord
uses: SethCohen/github-releases-to-discord@24d166886aee4646d448c8a389ff9e1ebcab3682 # v1.20.0
@@ -37,7 +37,7 @@ jobs:
- name: Install opencode
if: steps.team-check.outputs.is_team != 'true'
run: curl -fsSL https://kilo.ai/install | bash
run: curl -fsSL https://opencode.ai/install | bash
- name: Build prompt
if: steps.team-check.outputs.is_team != 'true'
@@ -1,64 +0,0 @@
# kilocode_change - new file
name: prepare-jetbrains-release
on:
workflow_dispatch:
inputs:
kind:
description: "Release kind"
required: true
type: choice
options:
- rc
- stable
version:
description: "Version, e.g. 7.3.13-rc.1 or 7.3.13"
required: true
type: string
from_tag:
description: "Optional previous tag for changelog range"
required: false
type: string
permissions:
contents: write
pull-requests: write
concurrency:
group: prepare-jetbrains-release-${{ inputs.version }}
cancel-in-progress: false
jobs:
prepare:
if: github.repository == 'Kilo-Org/kilocode'
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
fetch-depth: 0
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Setup Git Committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
- name: Create release tag and PR
run: |
args=(--kind "$KIND" --version "$VERSION")
if [[ -n "$FROM_TAG" ]]; then
args+=(--from-tag "$FROM_TAG")
fi
bun script/jetbrains-release-pr.ts "${args[@]}"
env:
GH_TOKEN: ${{ steps.committer.outputs.token }}
GH_REPO: ${{ github.repository }}
KIND: ${{ inputs.kind }}
VERSION: ${{ inputs.version }}
FROM_TAG: ${{ inputs.from_tag }}
@@ -22,13 +22,9 @@ jobs:
- run: git fetch --force --tags
- name: Setup Git Committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
- name: Publish
run: ./script/publish
run: |
git config --global user.email "opencode@sst.dev"
git config --global user.name "opencode"
./script/publish
working-directory: ./github
-208
View File
@@ -1,208 +0,0 @@
# kilocode_change - new file
name: publish-jetbrains
on:
pull_request:
types:
- closed
branches:
- main
workflow_dispatch:
inputs:
pr:
description: Merged JetBrains release PR number to publish
required: true
type: string
merge_commit:
description: Merge commit SHA from the reviewed release PR
required: true
type: string
concurrency:
group: publish-jetbrains-pr-${{ github.event.pull_request.number || inputs.pr }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
publish:
if: >-
github.repository == 'Kilo-Org/kilocode' &&
(
(
github.event_name == 'pull_request' &&
github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'jetbrains/release/') &&
contains(github.event.pull_request.labels.*.name, 'jetbrains-release') &&
github.event.pull_request.head.repo.full_name == github.repository
) ||
github.event_name == 'workflow_dispatch'
)
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- name: Checkout merged release PR
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.merge_commit_sha || inputs.merge_commit }}
- name: Setup Bun for validation
uses: ./.github/actions/setup-bun
- name: Validate release PR and tag
id: release
run: bun script/jetbrains-release-validate.ts --pr "$PR_NUMBER"
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr }}
- name: Save reviewed release metadata
run: |
cp packages/kilo-jetbrains/CHANGELOG.md "$RUNNER_TEMP/jetbrains-CHANGELOG.md"
cp packages/kilo-jetbrains/gradle.properties "$RUNNER_TEMP/jetbrains-gradle.properties"
- name: Checkout release tag
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ steps.release.outputs.tag }}
- name: Restore reviewed release metadata
run: |
cp "$RUNNER_TEMP/jetbrains-CHANGELOG.md" packages/kilo-jetbrains/CHANGELOG.md
cp "$RUNNER_TEMP/jetbrains-gradle.properties" packages/kilo-jetbrains/gradle.properties
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "24"
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Install dependencies
run: bun install
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Install build tools
run: |
sudo apt-get update
sudo apt-get install -y patchelf zip
curl --fail --location \
https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz \
--output "$RUNNER_TEMP/zig.tar.xz"
echo "473ec26806133cf4d1918caf1a410f8403a13d979726a9045b421b685031a982 $RUNNER_TEMP/zig.tar.xz" | sha256sum --check --status
tar -xJf "$RUNNER_TEMP/zig.tar.xz" -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/zig-linux-x86_64-0.14.0" >> "$GITHUB_PATH"
- name: Validate publishing secrets
run: |
missing=0
for name in JETBRAINS_MARKETPLACE_TOKEN JETBRAINS_CERTIFICATE_CHAIN JETBRAINS_PRIVATE_KEY JETBRAINS_PRIVATE_KEY_PASSWORD; do
if [[ -z "${!name}" ]]; then
echo "Missing required secret: $name" >&2
missing=1
fi
done
exit "$missing"
env:
JETBRAINS_MARKETPLACE_TOKEN: ${{ secrets.JETBRAINS_MARKETPLACE_TOKEN }}
JETBRAINS_CERTIFICATE_CHAIN: ${{ secrets.JETBRAINS_CERTIFICATE_CHAIN }}
JETBRAINS_PRIVATE_KEY: ${{ secrets.JETBRAINS_PRIVATE_KEY }}
JETBRAINS_PRIVATE_KEY_PASSWORD: ${{ secrets.JETBRAINS_PRIVATE_KEY_PASSWORD }}
- name: Verify plugin
working-directory: packages/kilo-jetbrains
run: ./gradlew verifyPlugin -Pproduction=true -Pkilo.channel="$CHANNEL"
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.release.outputs.version }}
CHANNEL: ${{ steps.release.outputs.marketplace_channel }}
- name: Render release notes
working-directory: packages/kilo-jetbrains
run: |
if ! grep -Fq "## [$VERSION]" CHANGELOG.md; then
echo "Missing packages/kilo-jetbrains/CHANGELOG.md entry for $VERSION. Review and merge a release PR before publishing." >&2
exit 1
fi
./gradlew getChangelog --project-version "$VERSION" --no-header --no-empty-sections --output-file=build/release-notes.md
env:
VERSION: ${{ steps.release.outputs.version }}
- name: Publish to JetBrains Marketplace
working-directory: packages/kilo-jetbrains
run: ./gradlew publishPlugin -Pproduction=true -Pkilo.channel="$CHANNEL"
env:
VERSION: ${{ steps.release.outputs.version }}
CHANNEL: ${{ steps.release.outputs.marketplace_channel }}
JETBRAINS_MARKETPLACE_TOKEN: ${{ secrets.JETBRAINS_MARKETPLACE_TOKEN }}
JETBRAINS_CERTIFICATE_CHAIN: ${{ secrets.JETBRAINS_CERTIFICATE_CHAIN }}
JETBRAINS_PRIVATE_KEY: ${{ secrets.JETBRAINS_PRIVATE_KEY }}
JETBRAINS_PRIVATE_KEY_PASSWORD: ${{ secrets.JETBRAINS_PRIVATE_KEY_PASSWORD }}
- name: Resolve plugin archive
id: archive
run: |
mapfile -t signed < <(compgen -G "packages/kilo-jetbrains/build/distributions/*-signed.zip")
if [[ "${#signed[@]}" -eq 1 ]]; then
echo "path=${signed[0]}" >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ "${#signed[@]}" -gt 1 ]]; then
echo "Expected exactly one signed JetBrains plugin ZIP, found ${#signed[@]}." >&2
printf '%s\n' "${signed[@]}" >&2
exit 1
fi
mapfile -t files < <(compgen -G "packages/kilo-jetbrains/build/distributions/*.zip")
if [[ "${#files[@]}" -ne 1 ]]; then
echo "Expected exactly one JetBrains plugin ZIP, found ${#files[@]}." >&2
printf '%s\n' "${files[@]}" >&2
exit 1
fi
echo "path=${files[0]}" >> "$GITHUB_OUTPUT"
- name: Upload to GitHub Release
run: |
tag="$TAG"
title="JetBrains $VERSION"
flags=(--title "$title" --notes-file "$NOTES")
if [[ "$KIND" == "rc" ]]; then
flags+=(--prerelease)
fi
if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release upload "$tag" "$ARCHIVE" --clobber --repo "$GITHUB_REPOSITORY"
gh release edit "$tag" "${flags[@]}" --repo "$GITHUB_REPOSITORY"
exit 0
fi
gh release create "$tag" "$ARCHIVE" "${flags[@]}" --repo "$GITHUB_REPOSITORY"
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.release.outputs.tag }}
VERSION: ${{ steps.release.outputs.version }}
KIND: ${{ steps.release.outputs.kind }}
ARCHIVE: ${{ steps.archive.outputs.path }}
NOTES: packages/kilo-jetbrains/build/release-notes.md
- name: Upload workflow artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: kilo-jetbrains-${{ steps.release.outputs.version }}
path: packages/kilo-jetbrains/build/distributions/*.zip
if-no-files-found: ignore
+394 -353
View File
@@ -1,13 +1,14 @@
name: publish
run-name: "${{ format('{0} {1}', inputs.pre_release && 'pre-release' || 'release', inputs.bump) }}"
run-name: "${{ format('release {0}', inputs.bump) }}"
on:
# push:
# branches:
# - ci
# - dev
# - beta
# - snapshot-*
push:
branches:
- ci
- dev
- beta
- fix/npm-native-binary-install
- snapshot-*
workflow_dispatch:
inputs:
bump:
@@ -15,440 +16,467 @@ on:
required: false
type: choice
options:
- patch
- minor
- major
- minor
- patch
version:
description: "Override version (optional)"
required: false
type: string
# kilocode_change start
pre_release:
description: "Publish as pre-release (VS Code marketplace + npm rc channel)"
required: false
type: boolean
default: true
# kilocode_change end
concurrency: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.version || inputs.bump }}
permissions:
id-token: write
contents: write
issues: write # kilocode_change - label automated JetBrains CLI pin bump PRs
packages: write
pull-requests: write # kilocode_change - create automated JetBrains CLI pin bump PRs
jobs:
version:
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.repository == 'Kilo-Org/kilocode'
if: github.repository == 'anomalyco/opencode'
steps:
- uses: actions/checkout@v6 # kilocode_change
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-depth: 0
- uses: ./.github/actions/setup-bun
# kilocode_change start - install deps for version script workspace resolution
- name: Install dependencies
run: bun install
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Install Kilo
- name: Install OpenCode
if: inputs.bump || inputs.version
run: bun i -g @kilocode/cli
# kilocode_change end
run: bun i -g opencode-ai
- id: version
run: |
./script/version.ts
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
KILO_BUMP: ${{ inputs.bump }}
KILO_VERSION: ${{ inputs.version }}
KILO_PRE_RELEASE: ${{ inputs.pre_release }}
KILO_API_KEY: ${{ secrets.KILO_API_KEY }}
KILO_ORG_ID: ${{ secrets.KILO_ORG_ID }}
GH_TOKEN: ${{ steps.committer.outputs.token }}
OPENCODE_BUMP: ${{ inputs.bump }}
OPENCODE_VERSION: ${{ inputs.version }}
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GH_REPO: ${{ (github.ref_name == 'beta' && 'anomalyco/opencode-beta') || github.repository }}
outputs:
version: ${{ steps.version.outputs.version }}
release: ${{ steps.version.outputs.release }}
tag: ${{ steps.version.outputs.tag }}
repo: ${{ steps.version.outputs.repo }}
build-cli:
needs: version
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.repository == 'Kilo-Org/kilocode'
if: github.repository == 'anomalyco/opencode'
steps:
- uses: actions/checkout@v6 # kilocode_change
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-tags: true
- uses: ./.github/actions/setup-bun
# kilocode_change start
- name: Setup Zig for Linux sandbox helpers
run: |
curl --fail --location --retry 3 \
https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz \
--output "$RUNNER_TEMP/zig.tar.xz"
echo "473ec26806133cf4d1918caf1a410f8403a13d979726a9045b421b685031a982 $RUNNER_TEMP/zig.tar.xz" | sha256sum --check --status
tar -xJf "$RUNNER_TEMP/zig.tar.xz" -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/zig-linux-x86_64-0.14.0" >> "$GITHUB_PATH"
# kilocode_change end
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Build
id: build
run: |
./packages/opencode/script/build.ts
./packages/opencode/script/build.ts ${{ (github.ref_name == 'beta' && '--sourcemaps') || '' }}
./packages/cli/script/build.ts ${{ (github.ref_name == 'beta' && '--sourcemaps') || '' }}
env:
KILO_VERSION: ${{ needs.version.outputs.version }}
KILO_RELEASE: ${{ needs.version.outputs.release }}
KILO_PRE_RELEASE: ${{ inputs.pre_release }}
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
GH_REPO: ${{ needs.version.outputs.repo }}
GH_TOKEN: ${{ steps.committer.outputs.token }}
# kilocode_change start - pack dist tree into a single zstd-compressed tar before upload.
# download-artifact@v4's streaming unzip is CPU-bound and processes entries one by one;
# collapsing ~480 files into one tar cuts build-vscode download from >30m to seconds.
# zstd compresses the wasms (~4x) and leaves the already-compact binaries alone, for
# ~1 GB artifact. upload-artifact@v7's `archive: false` skips the zip wrapper entirely
# so the tarball travels as-is (download-artifact@v8 auto-detects via Content-Type).
# With `archive: false` the `name:` input is ignored; the artifact is named after the
# file (kilo-cli.tar.zst). zstd + GNU tar are preinstalled on both github-hosted and
# blacksmith ubuntu-2404. See actions/upload-artifact#36, actions/toolkit#1533.
- name: Pack CLI dist into tar.zst
run: |
find packages/opencode/dist -name '*.map' -delete
tar --zstd -cf /tmp/kilo-cli.tar.zst -C packages/opencode/dist .
- uses: actions/upload-artifact@v7
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
path: /tmp/kilo-cli.tar.zst
archive: false
# kilocode_change end
name: opencode-cli
path: |
packages/opencode/dist/opencode-darwin*
packages/opencode/dist/opencode-linux*
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-cli-windows
path: packages/opencode/dist/opencode-windows*
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-preview-cli
path: packages/cli/dist/cli-*
outputs:
version: ${{ needs.version.outputs.version }}
# kilocode_change start - execute supported Unix CLI binaries before packaging VSIX artifacts
validate-cli-unix:
name: Validate CLI (${{ matrix.target }})
needs: build-cli
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- target: darwin-arm64
runner: macos-15
uname: arm64
package: "@kilocode/cli-darwin-arm64"
mode: host
- target: darwin-x64
runner: macos-15-intel
uname: x86_64
package: "@kilocode/cli-darwin-x64"
mode: host
- target: linux-arm64
runner: ubuntu-24.04-arm
uname: aarch64
package: "@kilocode/cli-linux-arm64"
mode: host
- target: linux-x64
runner: ubuntu-24.04
uname: x86_64
package: "@kilocode/cli-linux-x64"
mode: host
- target: alpine-arm64
runner: ubuntu-24.04-arm
uname: aarch64
package: "@kilocode/cli-linux-arm64-musl"
mode: alpine
platform: linux/arm64
- target: alpine-x64
runner: ubuntu-24.04
uname: x86_64
package: "@kilocode/cli-linux-x64-musl"
mode: alpine
platform: linux/amd64
steps:
- uses: actions/download-artifact@v8
with:
name: kilo-cli.tar.zst
path: /tmp
skip-decompress: true
- name: Unpack CLI dist
run: |
mkdir -p dist
tar --zstd -xf /tmp/kilo-cli.tar.zst -C dist
- name: Run CLI smoke test
run: |
test "$(uname -m)" = "${{ matrix.uname }}"
smoke_host() {
binary="$1"
"$binary" --version
helper="$(dirname "$binary")/bwrap"
if [[ "${{ matrix.target }}" == linux-* ]]; then
test -x "$helper"
grep -q '^SPDX-License-Identifier: LGPL-2.0-or-later$' "$(dirname "$binary")/licenses/bubblewrap/NOTICE"
"$helper" --version
# The live user-namespace bootstrap depends on the runner's kernel/AppArmor policy
# (GitHub-hosted Ubuntu 24.04 sets kernel.apparmor_restrict_unprivileged_userns=1), not on
# the shipped artifact. The runtime probe degrades gracefully, so keep this check non-fatal.
"$helper" --unshare-user --disable-userns --unshare-pid --die-with-parent --new-session \
--ro-bind / / --dev /dev --proc /proc -- "$helper" --version \
|| echo "unprivileged user namespaces unavailable on this runner; skipping live sandbox check"
fi
root="$(mktemp -d)"
trap 'rm -rf "$root"' RETURN
(
unset KILO_MODELS_PATH KILO_MODELS_URL KILO_CONFIG KILO_CONFIG_DIR
export XDG_DATA_HOME="$root/data"
export XDG_CACHE_HOME="$root/cache"
export XDG_CONFIG_HOME="$root/config"
export XDG_STATE_HOME="$root/state"
export KILO_DISABLE_MODELS_FETCH=1
export KILO_DISABLE_PROJECT_CONFIG=1
export KILO_CONFIG_CONTENT='{"enabled_providers":["anthropic"]}'
export ANTHROPIC_API_KEY=dummy
"$binary" --pure models anthropic | grep -q '^anthropic/'
)
}
if [ "${{ matrix.mode }}" = "host" ]; then
smoke_host "./dist/${{ matrix.package }}/bin/kilo"
exit 0
fi
docker run --rm \
--platform "${{ matrix.platform }}" \
-v "$PWD/dist:/dist:ro" \
-e PACKAGE="${{ matrix.package }}" \
alpine:3.22 \
sh -c '
set -eu
# kilocode_change start - Bun musl binaries link against libstdc++ and libgcc_s
# (GCC C++ runtime). Alpine does not ship these by default; they are available
# as optional packages and must be installed for any Bun-compiled musl binary to run.
apk add --no-cache libstdc++ libgcc
# kilocode_change end
binary="/dist/$PACKAGE/bin/kilo" # kilocode_change
"$binary" --version # kilocode_change
"/dist/$PACKAGE/bin/bwrap" --version # kilocode_change
grep -q '\''^SPDX-License-Identifier: LGPL-2.0-or-later$'\'' "/dist/$PACKAGE/bin/licenses/bubblewrap/NOTICE" # kilocode_change
root="$(mktemp -d)"
trap '\''rm -rf "$root"'\'' EXIT
unset KILO_MODELS_PATH KILO_MODELS_URL KILO_CONFIG KILO_CONFIG_DIR
export XDG_DATA_HOME="$root/data"
export XDG_CACHE_HOME="$root/cache"
export XDG_CONFIG_HOME="$root/config"
export XDG_STATE_HOME="$root/state"
export KILO_DISABLE_MODELS_FETCH=1
export KILO_DISABLE_PROJECT_CONFIG=1
export KILO_CONFIG_CONTENT='\''{"enabled_providers":["anthropic"]}'\''
export ANTHROPIC_API_KEY=dummy
"$binary" --pure models anthropic | grep -q "^anthropic/"
'
validate-cli-windows:
name: Validate CLI (windows-${{ matrix.arch }})
needs: build-cli
runs-on: ${{ matrix.runner }}
timeout-minutes: 20 # kilocode_change
strategy:
fail-fast: false
matrix:
include:
- arch: arm64
runner: windows-11-arm
package: "@kilocode/cli-windows-arm64"
- arch: x64
runner: windows-2025
package: "@kilocode/cli-windows-x64"
steps:
- uses: actions/download-artifact@v8
with:
name: kilo-cli.tar.zst
path: ${{ runner.temp }}
skip-decompress: true
- name: Install zstd
shell: pwsh
run: |
if (-not (Get-Command zstd -ErrorAction SilentlyContinue)) {
choco install zstandard -y --no-progress
}
- name: Unpack CLI dist
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist | Out-Null
zstd -d --stdout "$env:RUNNER_TEMP\kilo-cli.tar.zst" | tar -xf - -C dist
- name: Run CLI smoke test
shell: pwsh
run: |
$package = "${{ matrix.package }}".Replace("/", "\")
$binary = ".\dist\$package\bin\kilo.exe"
& $binary --version
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$root = Join-Path $env:RUNNER_TEMP ([guid]::NewGuid().ToString())
New-Item -ItemType Directory -Force -Path $root | Out-Null
try {
foreach ($name in "KILO_MODELS_PATH", "KILO_MODELS_URL", "KILO_CONFIG", "KILO_CONFIG_DIR") {
Remove-Item "Env:$name" -ErrorAction SilentlyContinue
}
$env:XDG_DATA_HOME = Join-Path $root "data"
$env:XDG_CACHE_HOME = Join-Path $root "cache"
$env:XDG_CONFIG_HOME = Join-Path $root "config"
$env:XDG_STATE_HOME = Join-Path $root "state"
$env:KILO_DISABLE_MODELS_FETCH = "1"
$env:KILO_DISABLE_PROJECT_CONFIG = "1"
$env:KILO_CONFIG_CONTENT = '{"enabled_providers":["anthropic"]}'
$env:ANTHROPIC_API_KEY = "dummy"
$output = & $binary --pure models anthropic
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
if (-not ($output -match "(?m)^anthropic/")) {
throw "Compiled Windows binary did not list Anthropic models from the embedded snapshot"
}
} finally {
Remove-Item -Recurse -Force $root -ErrorAction SilentlyContinue
}
# kilocode_change end
build-vscode:
sign-cli-windows:
needs:
- build-cli
- validate-cli-unix
- validate-cli-windows
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.repository == 'Kilo-Org/kilocode'
- version
runs-on: blacksmith-4vcpu-windows-2025
if: github.repository == 'anomalyco/opencode'
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE }}
AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
steps:
- uses: actions/checkout@v6 # kilocode_change
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli-windows
path: packages/opencode/dist
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Azure login
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- uses: azure/artifact-signing-action@b443cf8ea4124818d2ea9f043cba29fc3ec47b16 # v1.2.0
with:
endpoint: ${{ env.AZURE_TRUSTED_SIGNING_ENDPOINT }}
signing-account-name: ${{ env.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
certificate-profile-name: ${{ env.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE }}
files: |
${{ github.workspace }}\packages\opencode\dist\opencode-windows-arm64\bin\opencode.exe
${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64\bin\opencode.exe
${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64-baseline\bin\opencode.exe
exclude-environment-credential: true
exclude-workload-identity-credential: true
exclude-managed-identity-credential: true
exclude-shared-token-cache-credential: true
exclude-visual-studio-credential: true
exclude-visual-studio-code-credential: true
exclude-azure-cli-credential: false
exclude-azure-powershell-credential: true
exclude-azure-developer-cli-credential: true
exclude-interactive-browser-credential: true
- name: Verify Windows CLI signatures
shell: pwsh
run: |
$files = @(
"${{ github.workspace }}\packages\opencode\dist\opencode-windows-arm64\bin\opencode.exe",
"${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64\bin\opencode.exe",
"${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64-baseline\bin\opencode.exe"
)
foreach ($file in $files) {
$sig = Get-AuthenticodeSignature $file
if ($sig.Status -ne "Valid") {
throw "Invalid signature for ${file}: $($sig.Status)"
}
}
- name: Repack Windows CLI archives
working-directory: packages/opencode/dist
shell: pwsh
run: |
Compress-Archive -Path "opencode-windows-arm64\bin\*" -DestinationPath "opencode-windows-arm64.zip" -Force
Compress-Archive -Path "opencode-windows-x64\bin\*" -DestinationPath "opencode-windows-x64.zip" -Force
Compress-Archive -Path "opencode-windows-x64-baseline\bin\*" -DestinationPath "opencode-windows-x64-baseline.zip" -Force
- name: Upload signed Windows CLI release assets
if: needs.version.outputs.release != ''
shell: pwsh
env:
GH_TOKEN: ${{ steps.committer.outputs.token }}
run: |
gh release upload "v${{ needs.version.outputs.version }}" `
"${{ github.workspace }}\packages\opencode\dist\opencode-windows-arm64.zip" `
"${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64.zip" `
"${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64-baseline.zip" `
--clobber `
--repo "${{ needs.version.outputs.repo }}"
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-cli-signed-windows
path: |
packages/opencode/dist/opencode-windows-arm64
packages/opencode/dist/opencode-windows-x64
packages/opencode/dist/opencode-windows-x64-baseline
build-electron:
needs:
- build-cli
- version
if: github.repository == 'anomalyco/opencode'
continue-on-error: false
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE }}
AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
strategy:
fail-fast: false
matrix:
settings:
- host: macos-26-intel
target: x86_64-apple-darwin
platform_flag: --mac --x64
bun_install_flags: --os=darwin --cpu=x64
- host: macos-26
target: aarch64-apple-darwin
platform_flag: --mac --arm64
bun_install_flags: --os=darwin --cpu=arm64
# github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
- host: "windows-2025"
target: aarch64-pc-windows-msvc
platform_flag: --win --arm64
- host: "blacksmith-4vcpu-windows-2025"
target: x86_64-pc-windows-msvc
platform_flag: --win
- host: "blacksmith-4vcpu-ubuntu-2404"
target: x86_64-unknown-linux-gnu
platform_flag: --linux
- host: "blacksmith-4vcpu-ubuntu-2404-arm"
target: aarch64-unknown-linux-gnu
platform_flag: --linux --arm64
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: apple-actions/import-codesign-certs@8f3fb608891dd2244cdab3d69cd68c0d37a7fe93 # v2.0.0
if: runner.os == 'macOS'
with:
keychain: build
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- name: Setup Apple API Key
if: runner.os == 'macOS'
run: echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8
- uses: ./.github/actions/setup-bun
with:
install-flags: ${{ matrix.settings.bun_install_flags }}
- uses: actions/setup-node@v6 # kilocode_change
- name: Azure login
if: runner.os == 'Windows'
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
- name: Install @vscode/vsce
run: bun install -g @vscode/vsce
# kilocode_change start - download into /tmp and extract the tar.zst packed by build-cli
- uses: actions/download-artifact@v8
- name: Cache apt packages
if: contains(matrix.settings.host, 'ubuntu')
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
name: kilo-cli.tar.zst
path: /tmp
skip-decompress: true
path: ~/apt-cache
key: ${{ runner.os }}-${{ matrix.settings.target }}-apt-electron-${{ hashFiles('.github/workflows/publish.yml') }}
restore-keys: |
${{ runner.os }}-${{ matrix.settings.target }}-apt-electron-
- name: Unpack CLI dist
- name: Install dependencies (ubuntu only)
if: contains(matrix.settings.host, 'ubuntu')
run: |
mkdir -p packages/opencode/dist
tar --zstd -xf /tmp/kilo-cli.tar.zst -C packages/opencode/dist
# kilocode_change end
- name: Build VSIX packages
run: bun script/build.ts
working-directory: ./packages/kilo-vscode
env:
CLI_DIST_DIR: ../../packages/opencode/dist
KILO_VERSION: ${{ needs.build-cli.outputs.version }}
KILO_PRE_RELEASE: ${{ inputs.pre_release }}
GH_REPO: ${{ github.repository }}
mkdir -p ~/apt-cache && chmod -R a+rw ~/apt-cache
sudo apt-get update
sudo apt-get install -y --no-install-recommends -o dir::cache::archives="$HOME/apt-cache" rpm
sudo chmod -R a+rw ~/apt-cache
- uses: actions/upload-artifact@v7 # kilocode_change
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
name: kilo-vscode
path: packages/kilo-vscode/out
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
# kilocode_change start
# Run smoke tests against CLI assets uploaded to the draft GitHub release
# before publishing the release and package artifacts.
smoke-test:
name: Smoke Test (pre-publish gate)
needs:
- version
- build-cli
if: github.repository == 'Kilo-Org/kilocode'
uses: ./.github/workflows/smoke-test.yml
with:
cli_version: ${{ needs.version.outputs.version }}
secrets: inherit
# kilocode_change end
- name: Prepare
run: bun ./scripts/prepare.ts
working-directory: packages/desktop
env:
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
OPENCODE_CLI_ARTIFACT: ${{ (runner.os == 'Windows' && 'opencode-cli-windows') || 'opencode-cli' }}
RUST_TARGET: ${{ matrix.settings.target }}
GH_TOKEN: ${{ github.token }}
GITHUB_RUN_ID: ${{ github.run_id }}
- name: Build
run: bun run build
working-directory: packages/desktop
env:
OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_PROJECT: ${{ vars.WEB_SENTRY_PROJECT }}
SENTRY_RELEASE: desktop@${{ needs.version.outputs.version }}
VITE_SENTRY_DSN: ${{ vars.WEB_SENTRY_DSN }}
VITE_SENTRY_ENVIRONMENT: ${{ (github.ref_name == 'beta' && 'beta') || 'production' }}
VITE_SENTRY_RELEASE: desktop@${{ needs.version.outputs.version }}
- name: Package
if: needs.version.outputs.release
run: npx electron-builder ${{ matrix.settings.platform_flag }} --publish never --config electron-builder.config.ts
working-directory: packages/desktop
timeout-minutes: 60
env:
OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
GH_TOKEN: ${{ steps.committer.outputs.token }}
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_API_KEY: ${{ runner.temp }}/apple-api-key.p8
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
- name: Package (no publish)
if: ${{ !needs.version.outputs.release }}
run: npx electron-builder ${{ matrix.settings.platform_flag }} --publish never --config electron-builder.config.ts
working-directory: packages/desktop
timeout-minutes: 60
env:
OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
- name: Create macOS .app.tar.gz
if: runner.os == 'macOS' && needs.version.outputs.release
working-directory: packages/desktop/dist
run: |
if [[ "${{ matrix.settings.target }}" == "x86_64-apple-darwin" ]]; then
APP_DIR="mac"
OUT_NAME="opencode-desktop-mac-x64.app.tar.gz"
elif [[ "${{ matrix.settings.target }}" == "aarch64-apple-darwin" ]]; then
APP_DIR="mac-arm64"
OUT_NAME="opencode-desktop-mac-arm64.app.tar.gz"
else
echo "Unknown macOS target: ${{ matrix.settings.target }}"
exit 1
fi
APP_PATH=$(find "$APP_DIR" -maxdepth 1 -name "*.app" -type d | head -1)
if [ -z "$APP_PATH" ]; then
echo "No .app bundle found in $APP_DIR"
exit 1
fi
tar -czf "$OUT_NAME" -C "$(dirname "$APP_PATH")" "$(basename "$APP_PATH")"
- name: Verify signed Windows Electron artifacts
if: runner.os == 'Windows'
shell: pwsh
run: |
$files = @()
$files += Get-ChildItem "${{ github.workspace }}\packages\desktop\dist\*.exe" | Select-Object -ExpandProperty FullName
$files += Get-ChildItem "${{ github.workspace }}\packages\desktop\dist\*unpacked\*.exe" | Select-Object -ExpandProperty FullName
$files += Get-ChildItem "${{ github.workspace }}\packages\desktop\dist\*unpacked\resources\opencode-cli.exe" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName
foreach ($file in $files | Select-Object -Unique) {
$sig = Get-AuthenticodeSignature $file
if ($sig.Status -ne "Valid") {
throw "Invalid signature for ${file}: $($sig.Status)"
}
}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-desktop-${{ matrix.settings.target }}
path: packages/desktop/dist/*
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: needs.version.outputs.release
with:
name: latest-yml-${{ matrix.settings.target }}
path: packages/desktop/dist/latest*.yml
publish:
needs:
- version
- build-cli
- build-vscode
- validate-cli-unix # kilocode_change
- validate-cli-windows # kilocode_change
- smoke-test
runs-on: ubuntu-24.04
- sign-cli-windows
- build-electron
if: always() && !failure() && !cancelled()
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v6 # kilocode_change
# kilocode_change start
with:
persist-credentials: false
# kilocode_change end
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: ./.github/actions/setup-bun
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- uses: actions/setup-node@v6 # kilocode_change
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
package-manager-cache: false # kilocode_change
- name: Install @vscode/vsce
run: bun install -g @vscode/vsce
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli
path: packages/opencode/dist
- name: Setup Git Committer
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli-windows
path: packages/opencode/dist
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli-signed-windows
path: packages/opencode/dist
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-preview-cli
path: packages/cli/dist
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: needs.version.outputs.release
with:
pattern: latest-yml-*
path: /tmp/latest-yml
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: needs.version.outputs.release
with:
pattern: opencode-desktop-*
path: /tmp/desktop
merge-multiple: true
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
# kilocode_change start
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
# kilocode_change end
# kilocode_change start - download into /tmp and extract the tar.zst packed by build-cli
- uses: actions/download-artifact@v8
with:
name: kilo-cli.tar.zst
path: /tmp
skip-decompress: true
- name: Unpack CLI dist
run: |
mkdir -p packages/opencode/dist
tar --zstd -xf /tmp/kilo-cli.tar.zst -C packages/opencode/dist
# kilocode_change end
- uses: actions/download-artifact@v8
with:
name: kilo-vscode
path: packages/kilo-vscode/out
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Cache apt packages (AUR)
uses: actions/cache@v5 # kilocode_change
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: /var/cache/apt/archives
key: ${{ runner.os }}-apt-aur-${{ hashFiles('.github/workflows/publish.yml') }}
@@ -462,18 +490,31 @@ jobs:
mkdir -p ~/.ssh
echo "${{ secrets.AUR_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
git config --global user.email "kilo-maintainer[bot]@users.noreply.github.com"
git config --global user.name "kilo-maintainer[bot]"
git config --global user.email "opencode@sst.dev"
git config --global user.name "opencode"
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true
- name: Upload desktop release assets
if: needs.version.outputs.release
env:
GH_TOKEN: ${{ steps.committer.outputs.token }}
run: |
shopt -s nullglob
files=(/tmp/desktop/*.{exe,blockmap,dmg,zip,AppImage,deb,rpm} /tmp/desktop/*.app.tar.gz)
if (( ${#files[@]} == 0 )); then
echo "No desktop release assets found"
exit 1
fi
gh release upload "v${{ needs.version.outputs.version }}" "${files[@]}" --clobber --repo "${{ needs.version.outputs.repo }}"
- run: ./script/publish.ts
env:
KILO_VERSION: ${{ needs.version.outputs.version }}
KILO_RELEASE: ${{ needs.version.outputs.release }}
KILO_PRE_RELEASE: ${{ inputs.pre_release }}
GH_REPO: ${{ github.repository }}
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
AUR_KEY: ${{ secrets.AUR_KEY }}
GITHUB_TOKEN: ${{ steps.committer.outputs.token }}
NPM_CONFIG_PROVENANCE: true
VSCE_PAT: ${{ secrets.VSCE_TOKEN }}
OPENVSX_TOKEN: ${{ secrets.OVSX_TOKEN }}
GH_REPO: ${{ needs.version.outputs.repo }}
NPM_CONFIG_PROVENANCE: false
LATEST_YML_DIR: /tmp/latest-yml
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
@@ -22,13 +22,8 @@ jobs:
- run: git fetch --force --tags
- name: Setup Git Committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
- name: Release
run: |
git config --global user.email "opencode@sst.dev"
git config --global user.name "opencode"
./github/script/release
@@ -6,14 +6,10 @@ on:
jobs:
check-guidelines:
# kilocode_change start - disabled for kilo-cli fork (requires OpenCode install and API keys)
if: false
# kilocode_change end
# Original condition:
# if: |
# github.event.issue.pull_request &&
# startsWith(github.event.comment.body, '/review') &&
# contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association)
if: |
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/review') &&
contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association)
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: read
@@ -51,7 +47,7 @@ jobs:
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KILO_PERMISSION: '{ "bash": { "*": "deny", "gh*": "allow", "gh pr review*": "deny" } }'
OPENCODE_PERMISSION: '{ "bash": { "*": "deny", "gh*": "allow", "gh pr review*": "deny" } }'
PR_TITLE: ${{ steps.pr-details.outputs.title }}
run: |
PR_BODY=$(jq -r .body pr_data.json)
-151
View File
@@ -1,151 +0,0 @@
# kilocode_change - new file
# Standalone smoke test — checks out kilo-bench and runs a small set of
# Harbor eval tasks against the latest published CLI (or a specific version).
#
# Tasks: hello-world (~$0.01), log-summary-date-ranges (~$0.13)
# Expected total: < $0.50, < 15 min wall clock
#
# Triggers:
# - workflow_dispatch: manually from Actions tab (optionally pass a CLI version)
# - workflow_call: from publish.yml after draft release assets are uploaded
#
# Required secrets:
# KILO_API_KEY — Kilo Gateway key
# KILO_ORG_ID — Kilo org ID
# BENCH_GITHUB_TOKEN — PAT with contents:read on Kilo-Org/kilo-bench (private repo)
name: smoke-test
on:
workflow_dispatch:
inputs:
cli_version:
description: "CLI version to test (e.g. 7.0.36). Leave blank for latest npm release."
required: false
type: string
workflow_call:
inputs:
cli_version:
description: "CLI version to test from draft release assets."
required: false
type: string
concurrency:
group: smoke-test
cancel-in-progress: false
permissions:
contents: write # needed to read draft release assets when called from publish.yml
jobs:
smoke-test:
name: Smoke Test
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 30
env:
KILO_API_KEY: ${{ secrets.KILO_API_KEY }}
KILO_ORG_ID: ${{ secrets.KILO_ORG_ID }}
steps:
- name: Checkout kilo-bench
uses: actions/checkout@v6 # kilocode_change
with:
repository: Kilo-Org/kilo-bench
token: ${{ secrets.BENCH_GITHUB_TOKEN }}
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.13
- name: Install dependencies
run: uv sync --no-dev
- name: Validate API key
run: |
if [[ -z "$KILO_API_KEY" ]]; then
echo "::error::KILO_API_KEY secret is not set."
exit 1
fi
- name: Resolve CLI asset URL
id: cli
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="${{ inputs.cli_version }}"
if [[ -z "$VERSION" ]]; then
echo "cli_url=" >> "$GITHUB_OUTPUT"
echo "::notice::Testing latest CLI from npm"
exit 0
fi
# Resolve the release asset via the API so this works for draft
# releases too (browser /releases/download/... URLs 404 on drafts).
# The installer passes Accept: application/octet-stream + bearer
# auth, which is what the API asset endpoint expects.
# The tag_name filter yields at most one release and one asset,
# so --jq returns a single URL without needing head/pipefail games.
URL=$(gh api "repos/${{ github.repository }}/releases" \
--jq ".[] | select(.tag_name == \"v${VERSION}\") | .assets[] | select(.name == \"kilo-linux-x64.tar.gz\") | .url")
if [[ -z "$URL" ]]; then
echo "::error::asset kilo-linux-x64.tar.gz not found for v${VERSION}"
exit 1
fi
echo "cli_url=$URL" >> "$GITHUB_OUTPUT"
echo "::notice::Testing CLI v${VERSION} via asset API: $URL"
# Harbor's default agent-setup timeout is 360s. The hello-world container
# (FROM ubuntu:24.04) needs apt-get update + apt-get install + a NodeSource
# curl|bash + apt install nodejs before the CLI even downloads, and on
# the Blacksmith runners that occasionally pushes past 6 min when an apt
# mirror or NodeSource cdn is slow, killing the run with
# AgentSetupTimeoutError. Doubling the multiplier to 2 gives enough
# headroom for transient mirror/cdn slowness while still finishing well
# under timeout-minutes. Note: --timeout-multiplier scales every timeout
# uniformly (setup, agent, verifier, env build), but they're all upper
# limits so this is harmless.
- name: Run smoke test — hello-world
env:
KILO_CLI_URL: ${{ steps.cli.outputs.cli_url }}
KILO_CLI_GITHUB_TOKEN: ${{ github.token }}
run: |
./scripts/run_eval.sh \
-m kilo/anthropic/claude-sonnet-4.6 \
-d hello-world \
--job-name smoke-test-hello-world \
--timeout-multiplier 2
- name: Run smoke test — log-summary-date-ranges
env:
KILO_CLI_URL: ${{ steps.cli.outputs.cli_url }}
KILO_CLI_GITHUB_TOKEN: ${{ github.token }}
run: |
./scripts/run_eval.sh \
-m kilo/anthropic/claude-sonnet-4.6 \
-d terminal-bench-sample \
--include-task-name "log-summary-date-ranges" \
--job-name smoke-test-log-summary \
--timeout-multiplier 2
- name: Validate results
run: python3 scripts/validate_smoke_test.py jobs/smoke-test-*/
# Also upload the agent setup logs (stdout/stderr/return-code from the
# CLI install script) so we can see exactly which step stalls when the
# next AgentSetupTimeoutError happens. These come from the install
# script in kilo-bench, which uses `set -euo pipefail` (no `set -x`)
# and never echoes auth tokens or API keys, so the captured output is
# safe to upload.
- name: Upload results
if: always()
uses: actions/upload-artifact@v7 # kilocode_change
with:
name: smoke-test-results
path: |
jobs/smoke-test-*/**/result.json
jobs/smoke-test-*/**/trajectory.json
jobs/smoke-test-*/**/agent/setup/*.txt
retention-days: 30
if-no-files-found: warn
-24
View File
@@ -1,24 +0,0 @@
name: Check Source Links
on:
pull_request:
paths:
- "packages/kilo-vscode/src/**"
- "packages/kilo-vscode/webview-ui/**"
- "packages/opencode/src/**"
- "packages/kilo-docs/source-links.md"
- "script/extract-source-links.ts"
- ".github/workflows/source-check-links.yml"
workflow_dispatch: # Allow manual trigger
jobs:
source-links-freshness:
if: github.repository == 'Kilo-Org/kilocode'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # kilocode_change
- uses: oven-sh/setup-bun@v2
- name: Check source-links.md is up to date
run: bun run script/extract-source-links.ts --check
@@ -9,6 +9,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
stats:
if: github.repository == 'anomalyco/opencode'
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: write
-115
View File
@@ -1,115 +0,0 @@
# kilocode_change - new file
name: test-jetbrains
on:
workflow_call:
workflow_dispatch:
permissions:
contents: read
checks: write
pull-requests: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
changes:
name: detect JetBrains changes
runs-on: blacksmith-4vcpu-ubuntu-2404
outputs:
jetbrains: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.filter.outputs.jetbrains }}
steps:
- name: Checkout repository
if: github.event_name != 'workflow_dispatch'
uses: actions/checkout@v6
- name: Detect JetBrains changes
if: github.event_name != 'workflow_dispatch'
id: filter
uses: Kilo-Org/paths-filter@668c092af3649c4b664c54e4b704aa46782f6f7c # v3
with:
predicate-quantifier: every
filters: |
jetbrains:
- '**'
- '!.changeset/**'
- '!packages/kilo-vscode/**'
- '!packages/kilo-docs/**'
unit:
name: jetbrains
needs: changes
if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.jetbrains == 'true'
runs-on: blacksmith-4vcpu-ubuntu-2404
defaults:
run:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Mark workspace as git-safe
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: package.json
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
- name: Run JetBrains unit tests
run: bun script/test-ci.ts
working-directory: packages/kilo-jetbrains
- name: Publish JetBrains unit reports
if: always()
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v6.4.0
with:
report_paths: packages/kilo-jetbrains/.artifacts/unit/junit.xml
check_name: "unit results (jetbrains)"
detailed_summary: true
include_time_in_summary: true
fail_on_failure: false
- name: Upload JetBrains unit artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: unit-jetbrains-${{ github.run_attempt }}
include-hidden-files: true
if-no-files-found: ignore
retention-days: 7
path: packages/kilo-jetbrains/.artifacts/unit/junit.xml
required:
name: result
needs:
- changes
- unit
if: always()
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Verify JetBrains jobs passed
run: |
echo "changes=${{ needs.changes.result }}"
echo "jetbrains=${{ needs.unit.result }}"
test "${{ needs.changes.result }}" = "success"
if [ "${{ needs.changes.outputs.jetbrains }}" = "true" ]; then
test "${{ needs.unit.result }}" = "success"
else
test "${{ needs.changes.outputs.jetbrains }}" = "false"
test "${{ needs.unit.result }}" = "skipped"
fi
-55
View File
@@ -1,55 +0,0 @@
name: test-vscode
on:
push:
branches:
- main
- dev
paths:
- "packages/kilo-vscode/**"
- "packages/ui/**"
- "packages/kilo-ui/**"
- ".github/workflows/test-vscode.yml"
pull_request:
paths:
- "packages/kilo-vscode/**"
- "packages/ui/**"
- "packages/kilo-ui/**"
- ".github/workflows/test-vscode.yml"
workflow_dispatch:
jobs:
unit:
name: unit tests
runs-on: blacksmith-4vcpu-ubuntu-2404 # kilocode_change
defaults:
run:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v6 # kilocode_change
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Run unit tests
working-directory: packages/kilo-vscode
run: bun run test:unit
- name: Check lint (ESLint)
working-directory: packages/kilo-vscode
run: bun run lint
- name: Check formatting (prettier)
working-directory: packages/kilo-vscode
run: bun run format:check
- name: Check for dead code (knip)
working-directory: packages/kilo-vscode
run: bun run knip
- name: Check for kilocode_change markers
working-directory: packages/kilo-vscode
run: bun run check-kilocode-change
+78 -209
View File
@@ -3,14 +3,14 @@ name: test
on:
push:
branches:
- main # kilocode_change
- dev
pull_request:
workflow_dispatch:
concurrency:
# Keep every run on main so cancelled checks do not pollute the default branch # kilocode_change
# Keep every run on dev so cancelled checks do not pollute the default branch
# commit history. PRs and other branches still share a group and cancel stale runs.
group: ${{ case(github.ref == 'refs/heads/main', format('{0}-{1}', github.workflow, github.run_id), format('{0}-{1}', github.workflow, github.event.pull_request.number || github.ref)) }} # kilocode_change
group: ${{ case(github.ref == 'refs/heads/dev', format('{0}-{1}', github.workflow, github.run_id), format('{0}-{1}', github.workflow, github.event.pull_request.number || github.ref)) }}
cancel-in-progress: true
permissions:
@@ -21,256 +21,125 @@ env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# kilocode_change start
changes:
name: detect general unit test changes
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: read
pull-requests: read
outputs:
settings: ${{ steps.matrix.outputs.settings }}
general: ${{ steps.matrix.outputs.general }}
steps:
- name: Checkout repository
if: github.event_name != 'workflow_dispatch'
uses: actions/checkout@v6
- name: Detect general unit test changes
if: github.event_name != 'workflow_dispatch'
id: filter
uses: Kilo-Org/paths-filter@668c092af3649c4b664c54e4b704aa46782f6f7c # v3
with:
predicate-quantifier: every
filters: |
general:
- '**'
- '!.changeset/**'
- '!packages/kilo-jetbrains/**'
- '!packages/kilo-vscode/**'
- '!packages/kilo-docs/**'
- '!packages/extensions/zed/**'
- '!specs/**'
- '!perf/**'
- name: Configure unit matrix
id: matrix
env:
GENERAL: ${{ github.event_name != 'pull_request' || steps.filter.outputs.general == 'true' }}
run: |
if [ "$GENERAL" != "true" ]; then
echo 'general=false' >> "$GITHUB_OUTPUT"
echo 'settings=[{"os":"linux","index":1,"total":1,"host":"blacksmith-4vcpu-ubuntu-2404","run":false,"packages":false}]' >> "$GITHUB_OUTPUT"
exit 0
fi
echo 'general=true' >> "$GITHUB_OUTPUT"
echo 'settings=[{"os":"linux","index":1,"total":2,"host":"blacksmith-4vcpu-ubuntu-2404","run":true,"packages":true},{"os":"linux","index":2,"total":2,"host":"blacksmith-4vcpu-ubuntu-2404","run":true,"packages":false},{"os":"macos","index":1,"total":1,"host":"macos-15","run":true,"packages":true},{"os":"windows","index":1,"total":4,"host":"blacksmith-4vcpu-windows-2025","run":true,"packages":true},{"os":"windows","index":2,"total":4,"host":"blacksmith-4vcpu-windows-2025","run":true,"packages":false},{"os":"windows","index":3,"total":4,"host":"blacksmith-4vcpu-windows-2025","run":true,"packages":false},{"os":"windows","index":4,"total":4,"host":"blacksmith-4vcpu-windows-2025","run":true,"packages":false}]' >> "$GITHUB_OUTPUT"
# kilocode_change end
unit:
# kilocode_change start
name: ${{ !matrix.settings.run && 'unit (unchanged)' || matrix.settings.total > 1 && format('unit ({0}, {1}/{2})', matrix.settings.os, matrix.settings.index, matrix.settings.total) || format('unit ({0})', matrix.settings.os) }}
needs: changes
# kilocode_change end
name: unit (${{ matrix.settings.name }})
strategy:
fail-fast: false
matrix:
settings: ${{ fromJSON(needs.changes.outputs.settings) }} # kilocode_change
settings:
- name: linux
host: blacksmith-4vcpu-ubuntu-2404
- name: windows
host: blacksmith-4vcpu-windows-2025
runs-on: ${{ matrix.settings.host }}
timeout-minutes: 45 # kilocode_change
defaults:
run:
shell: bash
steps:
# kilocode_change start
- name: Skip unchanged general unit tests
if: ${{ !matrix.settings.run }}
run: echo "Only isolated product, documentation, or metadata files changed; general unit tests are unchanged."
# kilocode_change end
- name: Checkout repository
if: matrix.settings.run # kilocode_change
uses: actions/checkout@v6 # kilocode_change
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
# kilocode_change start
- name: Setup Node
if: matrix.settings.run
id: setup-node
continue-on-error: ${{ runner.os == 'Windows' }}
uses: actions/setup-node@v6
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
# kilocode_change end
# kilocode_change start
- name: Retry Setup Node on Windows
if: matrix.settings.run && runner.os == 'Windows' && steps.setup-node.outcome == 'failure'
uses: actions/setup-node@v6
with:
node-version: "24"
# kilocode_change end
- name: Setup Bun
if: matrix.settings.run # kilocode_change
uses: ./.github/actions/setup-bun
# kilocode_change start
- name: Setup Linux sandbox helper
if: matrix.settings.run && runner.os == 'Linux'
uses: ./.github/actions/setup-linux-sandbox
# kilocode_change end
- name: Configure git identity
if: matrix.settings.run # kilocode_change
# kilocode_change start
run: |
git config --global user.email "kilo-maintainer[bot]@users.noreply.github.com"
git config --global user.name "kilo-maintainer[bot]"
# kilocode_change end
git config --global user.email "bot@opencode.ai"
git config --global user.name "opencode"
- name: Cache Turbo
if: matrix.settings.run # kilocode_change
uses: actions/cache@v5 # kilocode_change
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: .turbo/cache # kilocode_change
key: turbo-${{ runner.os }}-${{ hashFiles('turbo.json', 'bun.lock') }}-${{ matrix.settings.os }}-${{ matrix.settings.index }}-${{ github.sha }} # kilocode_change
# kilocode_change start
path: node_modules/.cache/turbo
key: turbo-${{ runner.os }}-${{ hashFiles('turbo.json', '**/package.json') }}-${{ github.sha }}
restore-keys: |
turbo-${{ runner.os }}-${{ hashFiles('turbo.json', 'bun.lock') }}-${{ matrix.settings.os }}-${{ matrix.settings.index }}-
turbo-${{ runner.os }}-${{ hashFiles('turbo.json', 'bun.lock') }}-
turbo-${{ runner.os }}-${{ hashFiles('turbo.json', '**/package.json') }}-
turbo-${{ runner.os }}-
# kilocode_change end
# kilocode_change start - test non-CLI packages separately from sharded CLI tests
- name: Run non-CLI unit tests
if: matrix.settings.run && matrix.settings.packages
run: bun turbo test:ci --output-logs=errors-only --log-order=grouped --log-prefix=task --filter='!@kilocode/cli' --filter='!@kilocode/kilo-jetbrains'
# kilocode_change end
# kilocode_change start - ensure the Darwin profile cannot suppress its own validation
- name: Validate Darwin CLI test profile
if: matrix.settings.run && matrix.settings.os == 'macos'
working-directory: packages/opencode
run: bun test test/kilocode/test-profile.test.ts
# kilocode_change end
# kilocode_change start - run Kilo CLI tests through platform-specific shards
- name: Run CLI unit tests
if: matrix.settings.run
run: bun turbo test:ci --output-logs=errors-only --log-order=grouped --log-prefix=task --filter='@kilocode/cli'
- name: Run unit tests
timeout-minutes: 20
run: bun turbo test --output-logs=errors-only --log-order=grouped --log-prefix=task
env:
KILO_EXPERIMENTAL_DISABLE_FILEWATCHER: ${{ runner.os == 'Windows' && 'true' || 'false' }}
KILO_TEST_PROFILE: ${{ matrix.settings.os == 'macos' && 'darwin' || '' }}
KILO_TEST_SHARD: ${{ format('{0}/{1}', matrix.settings.index, matrix.settings.total) }}
# kilocode_change end
OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: ${{ runner.os == 'Windows' && 'true' || 'false' }}
# kilocode_change start
- name: Publish unit reports
if: always() && matrix.settings.run
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v6.4.0
with:
report_paths: packages/*/.artifacts/unit/junit.xml
annotate_only: true
detailed_summary: true
include_time_in_summary: true
fail_on_failure: false
- name: Run HttpApi exerciser gates
if: runner.os == 'Linux'
working-directory: packages/opencode
run: bun run test:httpapi
- name: Upload unit artifacts
if: always() && matrix.settings.run
uses: actions/upload-artifact@v7
with:
name: unit-${{ matrix.settings.os }}-${{ matrix.settings.index }}-${{ github.run_attempt }}
include-hidden-files: true
if-no-files-found: ignore
retention-days: 7
path: packages/*/.artifacts/unit/junit.xml
# kilocode_change end
# kilocode_change start
httpapi:
name: HttpApi exerciser
needs: changes
if: needs.changes.outputs.general == 'true'
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 15
e2e:
name: e2e (${{ matrix.settings.name }})
strategy:
fail-fast: false
matrix:
settings:
- name: linux
host: blacksmith-4vcpu-ubuntu-2404
- name: windows
host: blacksmith-4vcpu-windows-2025
runs-on: ${{ matrix.settings.host }}
env:
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.playwright-browsers
defaults:
run:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Setup Linux sandbox helper
uses: ./.github/actions/setup-linux-sandbox
- name: Configure git identity
- name: Read Playwright version
id: playwright-version
run: |
git config --global user.email "kilo-maintainer[bot]@users.noreply.github.com"
git config --global user.name "kilo-maintainer[bot]"
version=$(node -e 'console.log(require("./package.json").workspaces.catalog["@playwright/test"])')
echo "version=$version" >> "$GITHUB_OUTPUT"
- name: Cache Turbo
uses: actions/cache@v5
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: .turbo/cache
key: turbo-${{ runner.os }}-${{ hashFiles('turbo.json', 'bun.lock') }}-httpapi-${{ github.sha }}
restore-keys: |
turbo-${{ runner.os }}-${{ hashFiles('turbo.json', 'bun.lock') }}-httpapi-
turbo-${{ runner.os }}-${{ hashFiles('turbo.json', 'bun.lock') }}-
turbo-${{ runner.os }}-
path: ${{ github.workspace }}/.playwright-browsers
key: ${{ runner.os }}-${{ runner.arch }}-playwright-${{ steps.playwright-version.outputs.version }}-chromium
- name: Run HttpApi exerciser gates
run: bun turbo test:httpapi --filter='@kilocode/cli'
# kilocode_change end
- name: Install Playwright system dependencies
if: runner.os == 'Linux'
working-directory: packages/app
run: bunx playwright install-deps chromium
# kilocode_change start
jetbrains:
name: jetbrains
permissions:
contents: read
checks: write
pull-requests: read
uses: ./.github/workflows/test-jetbrains.yml
# kilocode_change end
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
working-directory: packages/app
run: bunx playwright install chromium
# kilocode_change start
unit-required:
name: unit (linux)
runs-on: blacksmith-4vcpu-ubuntu-2404
needs:
- unit
if: always()
steps:
- name: Verify unit matrix passed
run: |
echo "unit=${{ needs.unit.result }}"
test "${{ needs.unit.result }}" = "success"
# kilocode_change end
- name: Run app e2e tests
run: bun --cwd packages/app test:e2e:local
env:
CI: true
timeout-minutes: 30
# kilocode_change start
required:
name: test (linux)
runs-on: blacksmith-4vcpu-ubuntu-2404
needs:
- changes
- unit
- httpapi
- jetbrains
if: always()
steps:
- name: Verify upstream test jobs passed # kilocode_change
run: |
echo "unit=${{ needs.unit.result }}"
echo "httpapi=${{ needs.httpapi.result }}"
echo "jetbrains=${{ needs.jetbrains.result }}"
test "${{ needs.unit.result }}" = "success"
if [ "${{ needs.changes.outputs.general }}" = "true" ]; then
test "${{ needs.httpapi.result }}" = "success"
else
test "${{ needs.httpapi.result }}" = "skipped"
fi
test "${{ needs.jetbrains.result }}" = "success"
# kilocode_change end
- name: Upload Playwright artifacts
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-${{ matrix.settings.name }}-${{ github.run_attempt }}
if-no-files-found: ignore
retention-days: 7
path: |
packages/app/e2e/test-results
packages/app/e2e/playwright-report
@@ -20,7 +20,7 @@ jobs:
uses: ./.github/actions/setup-bun
- name: Install opencode
run: curl -fsSL https://kilo.ai/install | bash
run: curl -fsSL https://opencode.ai/install | bash
- name: Triage issue
env:
+7 -88
View File
@@ -2,101 +2,20 @@ name: typecheck
on:
push:
branches:
- main
branches: [dev]
pull_request:
branches: [dev]
workflow_dispatch:
jobs:
typecheck-js:
name: typecheck-js
runs-on: blacksmith-4vcpu-ubuntu-2404 # kilocode_change
typecheck:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v6 # kilocode_change
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Setup Bun
uses: ./.github/actions/setup-bun
# kilocode_change start
- name: Run TypeScript typecheck
run: bun turbo typecheck --filter='!@kilocode/kilo-jetbrains'
- name: Build Kilo Console
run: bun turbo build --filter=@kilocode/kilo-console
# kilocode_change end
# kilocode_change start
jetbrains-changes:
name: detect JetBrains changes
runs-on: blacksmith-4vcpu-ubuntu-2404
outputs:
jetbrains: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.filter.outputs.jetbrains }}
steps:
- name: Checkout repository
if: github.event_name != 'workflow_dispatch'
uses: actions/checkout@v6
- name: Detect JetBrains changes
if: github.event_name != 'workflow_dispatch'
id: filter
uses: Kilo-Org/paths-filter@668c092af3649c4b664c54e4b704aa46782f6f7c # v3
with:
predicate-quantifier: every
filters: |
jetbrains:
- '**'
- '!.changeset/**'
- '!packages/kilo-vscode/**'
- '!packages/kilo-docs/**'
typecheck-jetbrains:
name: typecheck-jetbrains
needs: jetbrains-changes
if: github.event_name == 'workflow_dispatch' || needs.jetbrains-changes.outputs.jetbrains == 'true'
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
- name: Run JetBrains typecheck
run: ./gradlew typecheck
working-directory: packages/kilo-jetbrains
required:
name: typecheck
runs-on: blacksmith-4vcpu-ubuntu-2404
needs:
- typecheck-js
- jetbrains-changes
- typecheck-jetbrains
if: always()
steps:
- name: Verify typecheck jobs passed
run: |
echo "typecheck-js=${{ needs.typecheck-js.result }}"
echo "jetbrains-changes=${{ needs.jetbrains-changes.result }}"
echo "typecheck-jetbrains=${{ needs.typecheck-jetbrains.result }}"
test "${{ needs.typecheck-js.result }}" = "success"
test "${{ needs.jetbrains-changes.result }}" = "success"
if [ "${{ needs.jetbrains-changes.outputs.jetbrains }}" = "true" ]; then
test "${{ needs.typecheck-jetbrains.result }}" = "success"
else
test "${{ needs.jetbrains-changes.outputs.jetbrains }}" = "false"
test "${{ needs.typecheck-jetbrains.result }}" = "skipped"
fi
# kilocode_change end
- name: Run typecheck
run: bun typecheck
-412
View File
@@ -1,412 +0,0 @@
# kilocode_change - new file
name: Visual Regression Tests
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: read
jobs:
check-paths:
name: Check changed paths
runs-on: ubuntu-latest # kilocode_change
outputs:
matched: ${{ steps.filter.outputs.matched }}
can_autocommit: ${{ steps.autocommit-check.outputs.can_autocommit }}
steps:
- uses: actions/checkout@v6
- name: Check changed files
id: filter
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
run: |
matched=false
while IFS= read -r file; do
case "$file" in
packages/kilo-ui/*|packages/ui/*|packages/util/*|packages/sdk/js/*|packages/kilo-vscode/webview-ui/*|packages/kilo-vscode/.storybook/*|packages/kilo-vscode/tests/visual-regression*|packages/kilo-vscode/tests/permission-dock-dropdown*|packages/kilo-vscode/tests/accessibility*|packages/kilo-docs/public/img/screenshot-tests/*|.github/actions/setup-bun/*|.github/workflows/visual-regression.yml)
matched=true
break
;;
esac
done < <(gh api --paginate "repos/${GITHUB_REPOSITORY}/pulls/${PR}/files" --jq '.[].filename')
echo "matched=$matched" >> "$GITHUB_OUTPUT"
echo "matched=$matched"
- name: Check if PR is from a fork
id: fork-check
run: |
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
echo "is_fork=true" >> "$GITHUB_OUTPUT"
else
echo "is_fork=false" >> "$GITHUB_OUTPUT"
fi
- name: Check baseline auto-commit permissions
id: autocommit-check
env:
MAINTAINER_APP_ID: ${{ secrets.KILO_MAINTAINER_APP_ID }}
MAINTAINER_APP_SECRET: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
run: |
if [ "${{ steps.fork-check.outputs.is_fork }}" != "true" ] && [ -n "$MAINTAINER_APP_ID" ] && [ -n "$MAINTAINER_APP_SECRET" ]; then
echo "can_autocommit=true" >> "$GITHUB_OUTPUT"
else
echo "can_autocommit=false" >> "$GITHUB_OUTPUT"
fi
visual-regression:
needs: check-paths
if: needs.check-paths.outputs.matched == 'true'
name: Visual Regression (kilo-ui) # kilocode_change
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 15
steps:
- name: Checkout (internal)
if: needs.check-paths.outputs.can_autocommit == 'true'
uses: actions/checkout@v6
with:
lfs: true
# Use github.token for LFS access. The maintainer app is used only for generated commits.
token: ${{ github.token }}
ref: ${{ github.head_ref }}
- name: Checkout (read-only)
if: needs.check-paths.outputs.can_autocommit != 'true'
uses: actions/checkout@v6
with:
lfs: true
- name: Check if HEAD is a baseline update commit
if: needs.check-paths.outputs.can_autocommit == 'true'
id: check-baseline-commit
run: |
COMMIT_MSG=$(git log -1 --format=%s)
if [ "$COMMIT_MSG" = "chore: update visual regression baselines" ] || [ "$COMMIT_MSG" = "chore: update kilo-vscode visual regression baselines" ]; then
echo "is_baseline_update=true" >> "$GITHUB_OUTPUT"
echo "HEAD commit is a baseline update commit — will not auto-commit again."
else
echo "is_baseline_update=false" >> "$GITHUB_OUTPUT"
fi
- name: Setup Bun
uses: ./.github/actions/setup-bun # kilocode_change
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('packages/kilo-ui/package.json') }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: bunx playwright install chromium
working-directory: packages/kilo-ui
- name: Install Playwright system deps
run: bunx playwright install-deps chromium
working-directory: packages/kilo-ui
- name: Cache Storybook build
id: storybook-cache
uses: actions/cache@v5
with:
path: packages/kilo-ui/storybook-static
key: storybook-${{ hashFiles('packages/kilo-ui/src/**', 'packages/kilo-ui/.storybook/**', 'packages/ui/src/**', 'packages/kilo-ui/package.json') }}
- name: Build Storybook
if: steps.storybook-cache.outputs.cache-hit != 'true'
run: bun run build-storybook
working-directory: packages/kilo-ui
- name: Generate baselines for new/missing stories
run: bun run test:visual:update
working-directory: packages/kilo-ui
env:
CI: true
PLAYWRIGHT_WORKERS: "4"
- name: Remove stale baselines for deleted stories
run: |
node -e "
const fs = require('fs'), path = require('path');
const idx = JSON.parse(fs.readFileSync('storybook-static/index.json', 'utf8'));
const stories = Object.values(idx.entries || idx.stories || {}).filter(s => s.id && !s.id.endsWith('--docs'));
const expected = new Set(stories.map(s => { const [c,v] = s.id.split('--'); return c + '/' + v + '-chromium-linux.png'; }));
const dir = '../kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression';
if (!fs.existsSync(dir)) process.exit(0);
for (const component of fs.readdirSync(dir)) {
const cdir = path.join(dir, component);
if (!fs.statSync(cdir).isDirectory()) continue;
for (const file of fs.readdirSync(cdir)) {
const rel = component + '/' + file;
if (file.endsWith('.png') && !expected.has(rel)) { console.log('Removing stale baseline:', rel); fs.unlinkSync(path.join(cdir, file)); }
}
}
"
working-directory: packages/kilo-ui
- name: Check for baseline changes (read-only PRs)
if: needs.check-paths.outputs.can_autocommit != 'true'
run: |
git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/
if git diff --cached --quiet; then
echo "No visual regression detected."
else
echo "::error::Visual regression detected. Screenshot baselines have changed."
echo "::error::Since this PR cannot receive baseline commits automatically, updated screenshots cannot be committed."
echo "::error::Please ask a Kilo developer for help updating the screenshots."
git diff --cached --stat
exit 1
fi
- name: Fail if baselines still changing after auto-update
if: needs.check-paths.outputs.can_autocommit == 'true' && steps.check-baseline-commit.outputs.is_baseline_update == 'true'
run: |
git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/
if git diff --cached --quiet; then
echo "Baselines are stable after auto-update."
else
echo "::error::Visual regression baselines changed again after a previous auto-update commit."
echo "::error::This indicates non-deterministic screenshots that would cause an infinite update loop."
echo "::error::Please investigate the flaky screenshots and add non-deterministic stories to the SKIP set."
git diff --cached --stat
exit 1
fi
- name: Check for baseline updates
if: needs.check-paths.outputs.can_autocommit == 'true' && steps.check-baseline-commit.outputs.is_baseline_update != 'true'
id: baseline-changes
run: |
git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/
if git diff --cached --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: Setup Git Committer
if: steps.baseline-changes.outputs.changed == 'true'
uses: ./.github/actions/setup-git-committer
with:
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
- name: Commit and push new baselines (if any)
if: steps.baseline-changes.outputs.changed == 'true'
id: commit-baselines
run: |
git commit -m "chore: update visual regression baselines"
git lfs push --all origin
git push --no-verify origin "HEAD:${GITHUB_HEAD_REF}"
echo "changed=true" >> "$GITHUB_OUTPUT"
- name: Fail if baselines changed
if: needs.check-paths.outputs.can_autocommit == 'true' && steps.commit-baselines.outputs.changed == 'true'
run: |
echo "::error::Visual regression baselines changed. New baselines have been committed to the branch. Please pull and review."
exit 1
- name: Upload test results on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: visual-regression-results
path: packages/kilo-ui/test-results/
retention-days: 7
visual-regression-vscode:
needs: check-paths
if: needs.check-paths.outputs.matched == 'true'
name: Visual Regression (kilo-vscode webview) # kilocode_change
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 15
env:
NODE_OPTIONS: --max-old-space-size=4096
steps:
- name: Checkout (internal)
if: needs.check-paths.outputs.can_autocommit == 'true'
uses: actions/checkout@v6
with:
lfs: true
# Use github.token for LFS access. The maintainer app is used only for generated commits.
token: ${{ github.token }}
ref: ${{ github.head_ref }}
- name: Checkout (read-only)
if: needs.check-paths.outputs.can_autocommit != 'true'
uses: actions/checkout@v6
with:
lfs: true
- name: Check if HEAD is a baseline update commit
if: needs.check-paths.outputs.can_autocommit == 'true'
id: check-baseline-commit-vscode
run: |
COMMIT_MSG=$(git log -1 --format=%s)
if [ "$COMMIT_MSG" = "chore: update visual regression baselines" ] || [ "$COMMIT_MSG" = "chore: update kilo-vscode visual regression baselines" ]; then
echo "is_baseline_update=true" >> "$GITHUB_OUTPUT"
echo "HEAD commit is a baseline update commit — will not auto-commit again."
else
echo "is_baseline_update=false" >> "$GITHUB_OUTPUT"
fi
- name: Setup Bun
uses: ./.github/actions/setup-bun # kilocode_change
- name: Cache Playwright browsers
id: playwright-cache-vscode
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: playwright-vscode-${{ hashFiles('packages/kilo-vscode/package.json') }}
- name: Install Playwright browsers
if: steps.playwright-cache-vscode.outputs.cache-hit != 'true'
run: bunx playwright install chromium
working-directory: packages/kilo-vscode
- name: Install Playwright system deps
run: bunx playwright install-deps chromium
working-directory: packages/kilo-vscode
- name: Cache Storybook build
id: storybook-cache-vscode
uses: actions/cache@v5
with:
path: packages/kilo-vscode/storybook-static
key: storybook-vscode-${{ hashFiles('packages/kilo-vscode/webview-ui/src/**', 'packages/kilo-vscode/.storybook/**', 'packages/kilo-ui/src/**', 'packages/ui/src/**', 'packages/kilo-vscode/package.json') }}
- name: Build Storybook
if: steps.storybook-cache-vscode.outputs.cache-hit != 'true'
run: bun run build-storybook
working-directory: packages/kilo-vscode
env:
NODE_OPTIONS: --max-old-space-size=4096
- name: Generate baselines and enforce webview accessibility checks
run: bun run test:visual:update
working-directory: packages/kilo-vscode
env:
CI: true
PLAYWRIGHT_WORKERS: "4"
NODE_OPTIONS: --max-old-space-size=4096
- name: Remove stale baselines for deleted stories
run: |
node -e "
const fs = require('fs'), path = require('path');
const idx = JSON.parse(fs.readFileSync('storybook-static/index.json', 'utf8'));
const stories = Object.values(idx.entries || idx.stories || {}).filter(s => s.id && !s.id.endsWith('--docs'));
const expected = new Set(stories.map(s => { const [c,v] = s.id.split('--'); return c + '/' + v + '-chromium-linux.png'; }));
const dir = '../kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression';
if (!fs.existsSync(dir)) process.exit(0);
for (const component of fs.readdirSync(dir)) {
const cdir = path.join(dir, component);
if (!fs.statSync(cdir).isDirectory()) continue;
for (const file of fs.readdirSync(cdir)) {
const rel = component + '/' + file;
if (file.endsWith('.png') && !expected.has(rel)) { console.log('Removing stale baseline:', rel); fs.unlinkSync(path.join(cdir, file)); }
}
}
"
working-directory: packages/kilo-vscode
- name: Remove stale baselines for permission-dock-dropdown tests
run: |
node -e "
const fs = require('fs');
const specPath = 'tests/permission-dock-dropdown.spec.ts';
const expected = new Set();
if (fs.existsSync(specPath)) {
const spec = fs.readFileSync(specPath, 'utf8');
const re = /toHaveScreenshot\(\[([^\]]+)\]\)/g;
let m;
while ((m = re.exec(spec)) !== null) {
const parts = m[1].split(',').map(s => s.trim().replace(/[\"']/g, ''));
const file = parts[parts.length - 1];
if (file) expected.add(file.replace(/\.png$/, '-chromium-linux.png'));
}
}
const dir = '../kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown';
if (!fs.existsSync(dir)) process.exit(0);
for (const file of fs.readdirSync(dir)) {
if (file.endsWith('.png') && !expected.has(file)) {
console.log('Removing stale baseline:', file);
fs.unlinkSync(dir + '/' + file);
}
}
"
working-directory: packages/kilo-vscode
- name: Check for baseline changes (read-only PRs)
if: needs.check-paths.outputs.can_autocommit != 'true'
run: |
git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/
if git diff --cached --quiet; then
echo "No visual regression detected."
else
echo "::error::Visual regression detected. Screenshot baselines have changed."
echo "::error::Since this PR cannot receive baseline commits automatically, updated screenshots cannot be committed."
echo "::error::Please ask a Kilo developer for help updating the screenshots."
git diff --cached --stat
exit 1
fi
- name: Fail if baselines still changing after auto-update
if: needs.check-paths.outputs.can_autocommit == 'true' && steps.check-baseline-commit-vscode.outputs.is_baseline_update == 'true'
run: |
git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/
if git diff --cached --quiet; then
echo "Baselines are stable after auto-update."
else
echo "::error::Visual regression baselines changed again after a previous auto-update commit."
echo "::error::This indicates non-deterministic screenshots that would cause an infinite update loop."
echo "::error::Please investigate the flaky screenshots and add non-deterministic stories to the SKIP set."
git diff --cached --stat
exit 1
fi
- name: Check for baseline updates
if: needs.check-paths.outputs.can_autocommit == 'true' && steps.check-baseline-commit-vscode.outputs.is_baseline_update != 'true'
id: baseline-changes-vscode
run: |
git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/
if git diff --cached --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: Setup Git Committer
if: steps.baseline-changes-vscode.outputs.changed == 'true'
uses: ./.github/actions/setup-git-committer
with:
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
- name: Commit and push new baselines (if any)
if: steps.baseline-changes-vscode.outputs.changed == 'true'
id: commit-baselines-vscode
run: |
git commit -m "chore: update kilo-vscode visual regression baselines"
git lfs push --all origin
git push --no-verify origin "HEAD:${GITHUB_HEAD_REF}"
echo "changed=true" >> "$GITHUB_OUTPUT"
- name: Fail if baselines changed
if: needs.check-paths.outputs.can_autocommit == 'true' && steps.commit-baselines-vscode.outputs.changed == 'true'
run: |
echo "::error::Visual regression baselines changed. New baselines have been committed to the branch. Please pull and review."
exit 1
- name: Upload test results on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: visual-regression-vscode-results
path: packages/kilo-vscode/test-results/
retention-days: 7
@@ -1,71 +0,0 @@
on:
schedule:
- cron: "7,37 * * * *" # every 30 min at :07 and :37
workflow_dispatch:
concurrency:
group: opencode-release-watch
cancel-in-progress: false
permissions:
contents: read
jobs:
check-release:
if: vars.OPENCODE_WATCH_ENABLED != 'false' && (github.event_name == 'workflow_dispatch' || github.repository == 'Kilo-Org/kilocode') # kilocode_change
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- id: fetch
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
data=$(gh release view --repo anomalyco/opencode --json tagName,name,url 2>/dev/null || echo '{}')
tag=$(echo "$data" | jq -r '.tagName // empty')
[ -z "$tag" ] && { echo "tag=" >> "$GITHUB_OUTPUT"; exit 0; }
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "name=$(echo "$data" | jq -r '.name // .tagName')" >> "$GITHUB_OUTPUT"
echo "url=$(echo "$data" | jq -r '.url')" >> "$GITHUB_OUTPUT"
- if: steps.fetch.outputs.tag != ''
id: cache
uses: actions/cache/restore@v4
with:
path: .cache/last-seen
key: last-seen-${{ steps.fetch.outputs.tag }}
restore-keys: last-seen-
- if: steps.fetch.outputs.tag != '' && steps.cache.outputs.cache-hit != 'true'
name: Trigger opencode sync
env:
URL: ${{ secrets.OPENCODE_WATCH_SYNC_URL }}
SECRET: ${{ secrets.OPENCODE_WATCH_SYNC_SECRET }}
VERCEL: ${{ secrets.OPENCODE_WATCH_VERCEL_SECRET }}
run: |
if [ -n "$URL" ] && [ -n "$SECRET" ]; then
headers=(-H "x-sync-secret: $SECRET" -H "Content-Type: application/json")
[ -n "$VERCEL" ] && headers+=(-H "x-vercel-protection-bypass: $VERCEL")
curl -sf -X POST "$URL" "${headers[@]}" -d '{}' || true
fi
- if: steps.fetch.outputs.tag != '' && steps.cache.outputs.cache-hit != 'true'
name: Notify Slack
uses: slackapi/slack-github-action@v2.0.0
with:
webhook: ${{ secrets.OPENCODE_WATCH_SLACK_WEBHOOK }}
webhook-type: incoming-webhook
payload: |
name: "${{ steps.fetch.outputs.name }}"
tag: "${{ steps.fetch.outputs.tag }}"
url: "${{ steps.fetch.outputs.url }}"
- if: steps.fetch.outputs.tag != '' && steps.cache.outputs.cache-hit != 'true'
name: Mark tag as seen
run: mkdir -p .cache/last-seen && echo "${{ steps.fetch.outputs.tag }}" > .cache/last-seen/tag.txt
- if: success() && steps.fetch.outputs.tag != '' && steps.cache.outputs.cache-hit != 'true'
name: Save seen-tag cache
uses: actions/cache/save@v4
with:
path: .cache/last-seen
key: last-seen-${{ steps.fetch.outputs.tag }}