mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-17 17:43:04 +08:00
refactor: kilo compat for v1.17.9
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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,6 +1,5 @@
|
||||
name: Question
|
||||
description: Ask a question
|
||||
labels: ["question"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: question
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)?)$/
|
||||
@@ -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 you’re 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 you’d 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._
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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}}"
|
||||
@@ -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 }}
|
||||
@@ -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
|
||||
@@ -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 }}
|
||||
+5
-5
@@ -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",
|
||||
@@ -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
|
||||
|
||||
@@ -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(`=============================`)
|
||||
@@ -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
|
||||
|
||||
@@ -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-*
|
||||
|
||||
+1
-4
@@ -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
|
||||
+1
-1
@@ -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 }}
|
||||
+4
-8
@@ -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
|
||||
@@ -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
@@ -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 }}
|
||||
|
||||
+2
-7
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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:
|
||||
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
Reference in New Issue
Block a user