From 1ce84856f53a936b927f5d9a5cc8eea12b1a7feb Mon Sep 17 00:00:00 2001 From: Ligia Zanchet Date: Wed, 1 Apr 2026 13:35:22 +0200 Subject: [PATCH 01/83] docs(kilo-docs): add setup videos to Slack/Telegram/Google --- packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md | 6 ++++++ .../kilo-docs/pages/kiloclaw/chat-platforms/telegram.md | 7 +++++++ .../kilo-docs/pages/kiloclaw/development-tools/google.md | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md b/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md index 08fbb66f7b6..075a7c65ad3 100644 --- a/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md +++ b/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md @@ -5,6 +5,12 @@ description: "Connect your KiloClaw agent to Slack" # Slack +{% callout type="info" title="Setup Video Guide" %} +Watch this video to see how to connect your KiloClaw agent to Slack step by step. + +**[▶ Watch Setup Video](https://screen.studio/share/lPVmA6Ld)** +{% /callout %} + Connect your KiloClaw agent to Slack by creating a Slack app from the OpenClaw manifest and linking it to your KiloClaw dashboard. ## Step 1: Create a Slack App from the OpenClaw Manifest diff --git a/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md b/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md index 8fd8d7b524d..b95ca8882f0 100644 --- a/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md +++ b/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md @@ -5,6 +5,13 @@ description: "Connect your KiloClaw agent to Telegram" # Telegram +{% callout type="info" title="Setup Video Guide" %} +Watch this video to see how to connect your KiloClaw agent to Telegram step by step. + +**[▶ Watch Setup Video](https://screen.studio/share/ihxlwf4g)** + +{% /callout %} + Connect your KiloClaw agent to Telegram by creating a bot via BotFather and linking it to your KiloClaw dashboard. 1. Open Telegram and search for [@BotFather](https://t.me/BotFather) diff --git a/packages/kilo-docs/pages/kiloclaw/development-tools/google.md b/packages/kilo-docs/pages/kiloclaw/development-tools/google.md index 0fa7272ec29..1b4553d97fb 100644 --- a/packages/kilo-docs/pages/kiloclaw/development-tools/google.md +++ b/packages/kilo-docs/pages/kiloclaw/development-tools/google.md @@ -42,6 +42,12 @@ Before you begin, make sure you have: ## Setup +{% callout type="info" title="Setup Video Guide" %} +Watch this video to see how to connect your Google account to KiloClaw step by step. + +**[▶ Watch Setup Video](https://screen.studio/share/cU8B3K4N)** +{% /callout %} + 1. Go to the **Settings** tab on your [KiloClaw dashboard](/docs/kiloclaw/dashboard) 2. Find the **Google Account** section 3. Copy the provided `docker run` command — it includes a short-lived authentication token From 3f17bf2b2366b1a2d5371cbd1e9cf030a008ef07 Mon Sep 17 00:00:00 2001 From: kirillk Date: Wed, 1 Apr 2026 23:06:18 -0400 Subject: [PATCH 02/83] feat(jetbrains): add JetBrains plugin wireframe with split mode architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds packages/kilo-jetbrains/ — a Gradle project scaffolded for the IntelliJ Platform using the split mode (frontend/backend/shared modules). Plugin ID ai.kilocode.jetbrains, version 7.0.1, Kilo logo icon. Also adds .idea/gradle.xml to auto-link the Gradle project when opening the monorepo in IntelliJ, and a Run JetBrains Plugin run configuration for runIde. Updates .gitignore to track .idea/gradle.xml and .idea/.run while keeping all other .idea/ contents ignored. --- .gitignore | 5 +- .idea/gradle.xml | 20 ++ .run/Run JetBrains Plugin.run.xml | 27 ++ packages/kilo-jetbrains/.gitignore | 4 + .../kilo-jetbrains/backend/build.gradle.kts | 16 ++ .../main/resources/kilo.jetbrains.backend.xml | 6 + packages/kilo-jetbrains/build.gradle.kts | 52 ++++ .../kilo-jetbrains/frontend/build.gradle.kts | 17 ++ .../resources/kilo.jetbrains.frontend.xml | 6 + packages/kilo-jetbrains/gradle.properties | 4 + .../kilo-jetbrains/gradle/libs.versions.toml | 12 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + packages/kilo-jetbrains/gradlew | 234 ++++++++++++++++++ packages/kilo-jetbrains/gradlew.bat | 89 +++++++ packages/kilo-jetbrains/settings.gradle.kts | 13 + .../kilo-jetbrains/shared/build.gradle.kts | 13 + .../main/resources/kilo.jetbrains.shared.xml | 2 + .../src/main/resources/META-INF/plugin.xml | 19 ++ .../main/resources/META-INF/pluginIcon.svg | 4 + 20 files changed, 547 insertions(+), 1 deletion(-) create mode 100644 .idea/gradle.xml create mode 100644 .run/Run JetBrains Plugin.run.xml create mode 100644 packages/kilo-jetbrains/.gitignore create mode 100644 packages/kilo-jetbrains/backend/build.gradle.kts create mode 100644 packages/kilo-jetbrains/backend/src/main/resources/kilo.jetbrains.backend.xml create mode 100644 packages/kilo-jetbrains/build.gradle.kts create mode 100644 packages/kilo-jetbrains/frontend/build.gradle.kts create mode 100644 packages/kilo-jetbrains/frontend/src/main/resources/kilo.jetbrains.frontend.xml create mode 100644 packages/kilo-jetbrains/gradle.properties create mode 100644 packages/kilo-jetbrains/gradle/libs.versions.toml create mode 100644 packages/kilo-jetbrains/gradle/wrapper/gradle-wrapper.jar create mode 100644 packages/kilo-jetbrains/gradle/wrapper/gradle-wrapper.properties create mode 100755 packages/kilo-jetbrains/gradlew create mode 100644 packages/kilo-jetbrains/gradlew.bat create mode 100644 packages/kilo-jetbrains/settings.gradle.kts create mode 100644 packages/kilo-jetbrains/shared/build.gradle.kts create mode 100644 packages/kilo-jetbrains/shared/src/main/resources/kilo.jetbrains.shared.xml create mode 100644 packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml create mode 100644 packages/kilo-jetbrains/src/main/resources/META-INF/pluginIcon.svg diff --git a/.gitignore b/.gitignore index 6bd9245c08b..a8bee54501a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,10 @@ node_modules .worktrees .sst .env -.idea +.idea/* +!.idea/gradle.xml +!.idea/.run +.idea/*.iml .vscode/* !.vscode/extensions.json !.vscode/launch.json diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000000..f9fe116bbd6 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.run/Run JetBrains Plugin.run.xml b/.run/Run JetBrains Plugin.run.xml new file mode 100644 index 00000000000..ac959382073 --- /dev/null +++ b/.run/Run JetBrains Plugin.run.xml @@ -0,0 +1,27 @@ + + + + + + + true + true + false + false + false + false + false + + + \ No newline at end of file diff --git a/packages/kilo-jetbrains/.gitignore b/packages/kilo-jetbrains/.gitignore new file mode 100644 index 00000000000..c496940e432 --- /dev/null +++ b/packages/kilo-jetbrains/.gitignore @@ -0,0 +1,4 @@ +.gradle/ +build/ +.intellijPlatform/ +!gradle/wrapper/gradle-wrapper.jar diff --git a/packages/kilo-jetbrains/backend/build.gradle.kts b/packages/kilo-jetbrains/backend/build.gradle.kts new file mode 100644 index 00000000000..71c776146af --- /dev/null +++ b/packages/kilo-jetbrains/backend/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + alias(libs.plugins.kotlin) +} + +kotlin { + jvmToolchain(21) +} + +dependencies { + intellijPlatform { + intellijIdea(libs.versions.intellij.platform) + bundledModule("intellij.platform.backend") + } + + implementation(project(":shared")) +} diff --git a/packages/kilo-jetbrains/backend/src/main/resources/kilo.jetbrains.backend.xml b/packages/kilo-jetbrains/backend/src/main/resources/kilo.jetbrains.backend.xml new file mode 100644 index 00000000000..220ca388a9a --- /dev/null +++ b/packages/kilo-jetbrains/backend/src/main/resources/kilo.jetbrains.backend.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/kilo-jetbrains/build.gradle.kts b/packages/kilo-jetbrains/build.gradle.kts new file mode 100644 index 00000000000..6613904d6dc --- /dev/null +++ b/packages/kilo-jetbrains/build.gradle.kts @@ -0,0 +1,52 @@ +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType +import org.jetbrains.intellij.platform.gradle.TestFrameworkType +import org.jetbrains.intellij.platform.gradle.tasks.aware.SplitModeAware.SplitModeTarget + +group = "ai.kilocode.jetbrains" +version = "7.0.1" + +plugins { + application + id("java") + alias(libs.plugins.intellij.platform) + + alias(libs.plugins.kotlin) apply false + alias(libs.plugins.kotlin.serialization) apply false + alias(libs.plugins.compose.compiler) apply false +} + +subprojects { + apply(plugin = "org.jetbrains.intellij.platform.module") +} + +allprojects { + repositories { + mavenCentral() + intellijPlatform { + defaultRepositories() + } + maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies/") + } +} + +dependencies { + intellijPlatform { + intellijIdea(libs.versions.intellij.platform) + + pluginModule(implementation(project(":shared"))) + pluginModule(implementation(project(":frontend"))) + pluginModule(implementation(project(":backend"))) + testFramework(TestFrameworkType.Platform) + } +} + +intellijPlatform { + splitMode = true + splitModeTarget = SplitModeTarget.BOTH + + pluginVerification { + ides { + create(IntelliJPlatformType.IntellijIdeaUltimate, libs.versions.intellij.platform) + } + } +} diff --git a/packages/kilo-jetbrains/frontend/build.gradle.kts b/packages/kilo-jetbrains/frontend/build.gradle.kts new file mode 100644 index 00000000000..12190932592 --- /dev/null +++ b/packages/kilo-jetbrains/frontend/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + alias(libs.plugins.kotlin) + alias(libs.plugins.compose.compiler) +} + +kotlin { + jvmToolchain(21) +} + +dependencies { + intellijPlatform { + intellijIdea(libs.versions.intellij.platform) + bundledModule("intellij.platform.frontend") + } + + implementation(project(":shared")) +} diff --git a/packages/kilo-jetbrains/frontend/src/main/resources/kilo.jetbrains.frontend.xml b/packages/kilo-jetbrains/frontend/src/main/resources/kilo.jetbrains.frontend.xml new file mode 100644 index 00000000000..58d7b183a3f --- /dev/null +++ b/packages/kilo-jetbrains/frontend/src/main/resources/kilo.jetbrains.frontend.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/kilo-jetbrains/gradle.properties b/packages/kilo-jetbrains/gradle.properties new file mode 100644 index 00000000000..5d33083cf31 --- /dev/null +++ b/packages/kilo-jetbrains/gradle.properties @@ -0,0 +1,4 @@ +kotlin.stdlib.default.dependency=false +org.gradle.configuration-cache=true +org.gradle.caching=true +org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m diff --git a/packages/kilo-jetbrains/gradle/libs.versions.toml b/packages/kilo-jetbrains/gradle/libs.versions.toml new file mode 100644 index 00000000000..63bbebf0e7f --- /dev/null +++ b/packages/kilo-jetbrains/gradle/libs.versions.toml @@ -0,0 +1,12 @@ +[versions] +intellij-platform = "2025.3" +intellij-gradle-plugin = "2.10.5" +kotlin-jvm-plugin = "2.1.20" +kotlin-serialization-plugin = "2.1.20" +kotlin-serialization = "1.7.3" + +[plugins] +intellij-platform = { id = "org.jetbrains.intellij.platform", version.ref = "intellij-gradle-plugin" } +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-jvm-plugin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin-serialization-plugin" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin-jvm-plugin" } diff --git a/packages/kilo-jetbrains/gradle/wrapper/gradle-wrapper.jar b/packages/kilo-jetbrains/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/packages/kilo-jetbrains/gradlew.bat b/packages/kilo-jetbrains/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/packages/kilo-jetbrains/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/packages/kilo-jetbrains/settings.gradle.kts b/packages/kilo-jetbrains/settings.gradle.kts new file mode 100644 index 00000000000..4fa336c9b9c --- /dev/null +++ b/packages/kilo-jetbrains/settings.gradle.kts @@ -0,0 +1,13 @@ +rootProject.name = "kilo.jetbrains" + +include("shared") +include("frontend") +include("backend") + +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies/") + } +} diff --git a/packages/kilo-jetbrains/shared/build.gradle.kts b/packages/kilo-jetbrains/shared/build.gradle.kts new file mode 100644 index 00000000000..6e02f979264 --- /dev/null +++ b/packages/kilo-jetbrains/shared/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + alias(libs.plugins.kotlin) +} + +kotlin { + jvmToolchain(21) +} + +dependencies { + intellijPlatform { + intellijIdea(libs.versions.intellij.platform) + } +} diff --git a/packages/kilo-jetbrains/shared/src/main/resources/kilo.jetbrains.shared.xml b/packages/kilo-jetbrains/shared/src/main/resources/kilo.jetbrains.shared.xml new file mode 100644 index 00000000000..164f46cfcfb --- /dev/null +++ b/packages/kilo-jetbrains/shared/src/main/resources/kilo.jetbrains.shared.xml @@ -0,0 +1,2 @@ + + diff --git a/packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml b/packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml new file mode 100644 index 00000000000..c64e38ed23b --- /dev/null +++ b/packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,19 @@ + + ai.kilocode.jetbrains + Kilo Code + 7.0.1 + Kilo Code + + + + + + + + + diff --git a/packages/kilo-jetbrains/src/main/resources/META-INF/pluginIcon.svg b/packages/kilo-jetbrains/src/main/resources/META-INF/pluginIcon.svg new file mode 100644 index 00000000000..f20188a670a --- /dev/null +++ b/packages/kilo-jetbrains/src/main/resources/META-INF/pluginIcon.svg @@ -0,0 +1,4 @@ + + + + From 04de4ad6fd9503a711928a1f8d80aa5c5e8e7e3a Mon Sep 17 00:00:00 2001 From: kirillk Date: Wed, 1 Apr 2026 23:13:25 -0400 Subject: [PATCH 03/83] chore(jetbrains): ignore .ai/ (JetBrains Junie AI agent config) --- packages/kilo-jetbrains/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/kilo-jetbrains/.gitignore b/packages/kilo-jetbrains/.gitignore index c496940e432..8eaae9e5aa4 100644 --- a/packages/kilo-jetbrains/.gitignore +++ b/packages/kilo-jetbrains/.gitignore @@ -1,4 +1,5 @@ .gradle/ build/ .intellijPlatform/ +.ai/ !gradle/wrapper/gradle-wrapper.jar From d5b1fa8a94d7b49fbe22e70cf39fb40be37834e7 Mon Sep 17 00:00:00 2001 From: Ligia Zanchet Date: Thu, 2 Apr 2026 14:23:57 +0200 Subject: [PATCH 04/83] docs(kilo-docs): replace video callouts with embedded YouTube players --- packages/kilo-docs/markdoc/tags/index.ts | 1 + packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md | 6 +----- .../kilo-docs/pages/kiloclaw/chat-platforms/telegram.md | 7 +------ .../kilo-docs/pages/kiloclaw/development-tools/google.md | 6 +----- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/packages/kilo-docs/markdoc/tags/index.ts b/packages/kilo-docs/markdoc/tags/index.ts index e45e013c7d1..8405992fee9 100644 --- a/packages/kilo-docs/markdoc/tags/index.ts +++ b/packages/kilo-docs/markdoc/tags/index.ts @@ -6,3 +6,4 @@ export * from "./icon.markdoc" export * from "./image.markdoc" export * from "./kilo-code-icon.markdoc" export * from "./youtube.markdoc" + diff --git a/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md b/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md index 075a7c65ad3..4826ef7c3fe 100644 --- a/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md +++ b/packages/kilo-docs/pages/kiloclaw/chat-platforms/slack.md @@ -5,11 +5,7 @@ description: "Connect your KiloClaw agent to Slack" # Slack -{% callout type="info" title="Setup Video Guide" %} -Watch this video to see how to connect your KiloClaw agent to Slack step by step. - -**[▶ Watch Setup Video](https://screen.studio/share/lPVmA6Ld)** -{% /callout %} +{% youtube url="https://youtu.be/Q5bt-qH-_pY" title="Slack Setup Guide" caption="How to connect your KiloClaw agent to Slack" /%} Connect your KiloClaw agent to Slack by creating a Slack app from the OpenClaw manifest and linking it to your KiloClaw dashboard. diff --git a/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md b/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md index b95ca8882f0..71e0b204701 100644 --- a/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md +++ b/packages/kilo-docs/pages/kiloclaw/chat-platforms/telegram.md @@ -5,12 +5,7 @@ description: "Connect your KiloClaw agent to Telegram" # Telegram -{% callout type="info" title="Setup Video Guide" %} -Watch this video to see how to connect your KiloClaw agent to Telegram step by step. - -**[▶ Watch Setup Video](https://screen.studio/share/ihxlwf4g)** - -{% /callout %} +{% youtube url="https://youtu.be/hIfKz073hGw" title="Telegram Setup Guide" caption="How to connect your KiloClaw agent to Telegram" /%} Connect your KiloClaw agent to Telegram by creating a bot via BotFather and linking it to your KiloClaw dashboard. diff --git a/packages/kilo-docs/pages/kiloclaw/development-tools/google.md b/packages/kilo-docs/pages/kiloclaw/development-tools/google.md index 1b4553d97fb..3a7cdce83ac 100644 --- a/packages/kilo-docs/pages/kiloclaw/development-tools/google.md +++ b/packages/kilo-docs/pages/kiloclaw/development-tools/google.md @@ -42,11 +42,7 @@ Before you begin, make sure you have: ## Setup -{% callout type="info" title="Setup Video Guide" %} -Watch this video to see how to connect your Google account to KiloClaw step by step. - -**[▶ Watch Setup Video](https://screen.studio/share/cU8B3K4N)** -{% /callout %} +{% youtube url="https://youtu.be/PX444_j3O4I" title="Google Workspace Setup Guide" caption="How to connect your Google account to KiloClaw" /%} 1. Go to the **Settings** tab on your [KiloClaw dashboard](/docs/kiloclaw/dashboard) 2. Find the **Google Account** section From 569d452a9baa59d412f22e2160ea9938c468b216 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 12:41:22 +0000 Subject: [PATCH 05/83] feat(gateway): include version in User-Agent header Change User-Agent from static 'opencode-kilo-provider' to 'opencode-kilo-provider/' using the KILOCODE_VERSION env var. Rename USER_AGENT constant to USER_AGENT_BASE and convert DEFAULT_HEADERS from a static object to getDefaultHeaders() function so the version is resolved at call time. --- packages/kilo-gateway/src/api/constants.ts | 4 ++-- packages/kilo-gateway/src/api/models.ts | 4 ++-- packages/kilo-gateway/src/api/modes.ts | 4 ++-- packages/kilo-gateway/src/headers.ts | 19 +++++++++++++++---- packages/kilo-gateway/src/index.ts | 4 ++-- packages/kilo-gateway/src/provider-debug.ts | 4 ++-- packages/kilo-gateway/src/provider.ts | 4 ++-- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/kilo-gateway/src/api/constants.ts b/packages/kilo-gateway/src/api/constants.ts index f2f08dc92ad..1c9a72dcf40 100644 --- a/packages/kilo-gateway/src/api/constants.ts +++ b/packages/kilo-gateway/src/api/constants.ts @@ -27,8 +27,8 @@ export const DEFAULT_FREE_MODEL = "kilo-auto/free" /** Token expiration duration in milliseconds (1 year) */ export const TOKEN_EXPIRATION_MS = 365 * 24 * 60 * 60 * 1000 -/** User-Agent header value for requests */ -export const USER_AGENT = "opencode-kilo-provider" +/** User-Agent header base value for requests */ +export const USER_AGENT_BASE = "opencode-kilo-provider" /** Content-Type header value for requests */ export const CONTENT_TYPE = "application/json" diff --git a/packages/kilo-gateway/src/api/models.ts b/packages/kilo-gateway/src/api/models.ts index 8229966bf83..fb86344075d 100644 --- a/packages/kilo-gateway/src/api/models.ts +++ b/packages/kilo-gateway/src/api/models.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { getKiloUrlFromToken } from "../auth/token.js" -import { DEFAULT_HEADERS } from "../headers.js" +import { getDefaultHeaders } from "../headers.js" import { KILO_API_BASE, KILO_OPENROUTER_BASE, MODELS_FETCH_TIMEOUT_MS, PROMPTS, AI_SDK_PROVIDERS } from "./constants.js" /** @@ -88,7 +88,7 @@ export async function fetchKiloModels(options?: { // Fetch models with timeout const response = await fetch(modelsURL, { headers: { - ...DEFAULT_HEADERS, + ...getDefaultHeaders(), ...(token ? { Authorization: `Bearer ${token}` } : {}), }, signal: AbortSignal.timeout(MODELS_FETCH_TIMEOUT_MS), diff --git a/packages/kilo-gateway/src/api/modes.ts b/packages/kilo-gateway/src/api/modes.ts index 18557ab50f4..85493804c52 100644 --- a/packages/kilo-gateway/src/api/modes.ts +++ b/packages/kilo-gateway/src/api/modes.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { KILO_API_BASE, MODELS_FETCH_TIMEOUT_MS } from "./constants.js" -import { DEFAULT_HEADERS } from "../headers.js" +import { getDefaultHeaders } from "../headers.js" /** * Group entry in an organization mode config. @@ -70,7 +70,7 @@ export async function fetchOrganizationModes(token: string, organizationId: stri const url = `${KILO_API_BASE}/api/organizations/${encodeURIComponent(organizationId)}/modes` const response = await fetch(url, { headers: { - ...DEFAULT_HEADERS, + ...getDefaultHeaders(), Authorization: `Bearer ${token}`, }, signal: AbortSignal.timeout(MODELS_FETCH_TIMEOUT_MS), diff --git a/packages/kilo-gateway/src/headers.ts b/packages/kilo-gateway/src/headers.ts index 6170c427e7e..814f3d538d3 100644 --- a/packages/kilo-gateway/src/headers.ts +++ b/packages/kilo-gateway/src/headers.ts @@ -6,7 +6,7 @@ import { HEADER_EDITORNAME, HEADER_MACHINEID, HEADER_FEATURE, - USER_AGENT, + USER_AGENT_BASE, CONTENT_TYPE, DEFAULT_EDITOR_NAME, ENV_EDITOR_NAME, @@ -36,12 +36,23 @@ export function getFeatureHeader(): string | undefined { return process.env[ENV_FEATURE] || undefined } +/** + * Get User-Agent header value. + * Appends the version from KILOCODE_VERSION when available. + */ +export function getUserAgent(): string { + const version = process.env[ENV_VERSION] + return version ? `${USER_AGENT_BASE}/${version}` : USER_AGENT_BASE +} + /** * Default headers for KiloCode requests */ -export const DEFAULT_HEADERS = { - "User-Agent": USER_AGENT, - "Content-Type": CONTENT_TYPE, +export function getDefaultHeaders(): Record { + return { + "User-Agent": getUserAgent(), + "Content-Type": CONTENT_TYPE, + } } /** diff --git a/packages/kilo-gateway/src/index.ts b/packages/kilo-gateway/src/index.ts index c441cc5a6c1..04dbd7d5128 100644 --- a/packages/kilo-gateway/src/index.ts +++ b/packages/kilo-gateway/src/index.ts @@ -9,7 +9,7 @@ export { KiloAuthPlugin, default } from "./plugin.js" export { createKilo } from "./provider.js" export { createKiloDebug } from "./provider-debug.js" export { kiloCustomLoader } from "./loader.js" -export { buildKiloHeaders, getEditorNameHeader, getFeatureHeader, DEFAULT_HEADERS } from "./headers.js" +export { buildKiloHeaders, getEditorNameHeader, getFeatureHeader, getDefaultHeaders, getUserAgent } from "./headers.js" // ============================================================================ // Auth @@ -86,7 +86,7 @@ export { DEFAULT_MODEL, DEFAULT_FREE_MODEL, TOKEN_EXPIRATION_MS, - USER_AGENT, + USER_AGENT_BASE, CONTENT_TYPE, DEFAULT_PROVIDER_NAME, ANONYMOUS_API_KEY, diff --git a/packages/kilo-gateway/src/provider-debug.ts b/packages/kilo-gateway/src/provider-debug.ts index 240d8492fbf..37abac857b8 100644 --- a/packages/kilo-gateway/src/provider-debug.ts +++ b/packages/kilo-gateway/src/provider-debug.ts @@ -2,7 +2,7 @@ import { createOpenRouter } from "@openrouter/ai-sdk-provider" import type { Provider as SDK } from "ai" import type { KiloProviderOptions } from "./types.js" import { getKiloUrlFromToken, getApiKey } from "./auth/token.js" -import { buildKiloHeaders, DEFAULT_HEADERS } from "./headers.js" +import { buildKiloHeaders, getDefaultHeaders } from "./headers.js" import { KILO_API_BASE, ANONYMOUS_API_KEY } from "./api/constants.js" /** @@ -32,7 +32,7 @@ export function createKiloDebug(options: KiloProviderOptions = {}): SDK { // Merge custom headers with defaults const customHeaders = { - ...DEFAULT_HEADERS, + ...getDefaultHeaders(), ...buildKiloHeaders(undefined, { kilocodeOrganizationId: options.kilocodeOrganizationId, kilocodeTesterWarningsDisabledUntil: undefined, diff --git a/packages/kilo-gateway/src/provider.ts b/packages/kilo-gateway/src/provider.ts index 618360a4c35..e6a43bf0f42 100644 --- a/packages/kilo-gateway/src/provider.ts +++ b/packages/kilo-gateway/src/provider.ts @@ -4,7 +4,7 @@ import { createOpenAI } from "@ai-sdk/openai" import { createOpenAICompatible } from "@ai-sdk/openai-compatible" import type { KiloProvider, KiloProviderOptions } from "./types.js" import { getKiloUrlFromToken, getApiKey } from "./auth/token.js" -import { buildKiloHeaders, DEFAULT_HEADERS } from "./headers.js" +import { buildKiloHeaders, getDefaultHeaders } from "./headers.js" import { KILO_API_BASE, ANONYMOUS_API_KEY } from "./api/constants.js" /** @@ -39,7 +39,7 @@ export function createKilo(options: KiloProviderOptions = {}): KiloProvider { // Merge custom headers with defaults const customHeaders = { - ...DEFAULT_HEADERS, + ...getDefaultHeaders(), ...buildKiloHeaders(undefined, { kilocodeOrganizationId: options.kilocodeOrganizationId, kilocodeTesterWarningsDisabledUntil: undefined, From 16471c6fa4f208843795925c3b73bdfb9fdf0296 Mon Sep 17 00:00:00 2001 From: kirillk Date: Thu, 2 Apr 2026 09:31:43 -0400 Subject: [PATCH 06/83] chore(jetbrains): target IntelliJ IDEA Community edition --- packages/kilo-jetbrains/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kilo-jetbrains/build.gradle.kts b/packages/kilo-jetbrains/build.gradle.kts index 6613904d6dc..0c1e4946008 100644 --- a/packages/kilo-jetbrains/build.gradle.kts +++ b/packages/kilo-jetbrains/build.gradle.kts @@ -46,7 +46,7 @@ intellijPlatform { pluginVerification { ides { - create(IntelliJPlatformType.IntellijIdeaUltimate, libs.versions.intellij.platform) + create(IntelliJPlatformType.IntellijIdeaCommunity, libs.versions.intellij.platform) } } } From 4cd3d15317f26dcbaa8bcc08e46857d99bb5c4ec Mon Sep 17 00:00:00 2001 From: kirillk Date: Thu, 2 Apr 2026 09:34:03 -0400 Subject: [PATCH 07/83] chore(jetbrains): remove id and version from plugin.xml (patched on build) --- packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml b/packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml index c64e38ed23b..96e28986525 100644 --- a/packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml +++ b/packages/kilo-jetbrains/src/main/resources/META-INF/plugin.xml @@ -1,7 +1,5 @@ - ai.kilocode.jetbrains Kilo Code - 7.0.1 Kilo Code Date: Thu, 2 Apr 2026 13:48:45 +0000 Subject: [PATCH 08/83] feat(vscode): add pre-release publishing support to marketplace workflow Add a pre_release checkbox to the publish workflow that passes --pre-release to vsce package, vsce publish, and ovsx publish. This enables publishing to the VS Code Marketplace pre-release channel without requiring a separate versioning scheme. Closes #8156 --- .github/workflows/publish.yml | 9 ++++++++- packages/kilo-vscode/script/build.ts | 9 ++++++--- packages/kilo-vscode/script/publish.ts | 14 +++++++++----- script/release | 3 ++- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aa6bcfa45c3..8b64bf4ed5d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,5 +1,5 @@ name: publish -run-name: "${{ format('release {0}', inputs.bump) }}" +run-name: "${{ format('{0} {1}', inputs.pre_release && 'pre-release' || 'release', inputs.bump) }}" on: # push: @@ -22,6 +22,11 @@ on: description: "Override version (optional)" required: false type: string + pre_release: + description: "Publish as pre-release (VS Code marketplace)" + required: false + type: boolean + default: false concurrency: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.version || inputs.bump }} @@ -117,6 +122,7 @@ jobs: env: CLI_DIST_DIR: ../../packages/opencode/dist KILO_VERSION: ${{ needs.build-cli.outputs.version }} + KILO_PRE_RELEASE: ${{ inputs.pre_release }} GH_REPO: ${{ github.repository }} - uses: actions/upload-artifact@v4 @@ -394,6 +400,7 @@ jobs: env: KILO_VERSION: ${{ needs.version.outputs.version }} KILO_RELEASE: ${{ needs.version.outputs.release }} + KILO_PRE_RELEASE: ${{ inputs.pre_release }} GH_REPO: ${{ github.repository }} AUR_KEY: ${{ secrets.AUR_KEY }} GITHUB_TOKEN: ${{ steps.committer.outputs.token }} diff --git a/packages/kilo-vscode/script/build.ts b/packages/kilo-vscode/script/build.ts index ee00dbb778e..cb285b327b4 100644 --- a/packages/kilo-vscode/script/build.ts +++ b/packages/kilo-vscode/script/build.ts @@ -6,8 +6,9 @@ import { existsSync, mkdirSync, rmSync, chmodSync } from "node:fs" const packageJsonPath = join(import.meta.dir, "..", "package.json") const packageJson = await Bun.file(packageJsonPath).json() const version = process.env.KILO_VERSION ? process.env.KILO_VERSION : packageJson.version +const prerelease = process.env.KILO_PRE_RELEASE === "true" -console.log(`Building VSCode extension version: ${version}`) +console.log(`Building VSCode extension version: ${version}${prerelease ? " (pre-release)" : ""}`) if (packageJson.version !== version) { console.log(`Updating package.json version from ${packageJson.version} to ${version}`) @@ -80,9 +81,11 @@ for (const config of targets) { console.log(` ✅ Binary ready at ${targetBinary}`) - console.log(` 📦 Packaging .vsix for ${config.target}...`) + console.log(` 📦 Packaging .vsix for ${config.target}${prerelease ? " (pre-release)" : ""}...`) const vsixPath = join(outDir, `kilo-vscode-${config.target}.vsix`) - await $`vsce package --no-dependencies --skip-license --target ${config.target} -o ${vsixPath}`.env({ + const args = ["--no-dependencies", "--skip-license", "--target", config.target, "-o", vsixPath] + if (prerelease) args.push("--pre-release") + await $`vsce package ${args}`.env({ ...process.env, npm_config_ignore_scripts: "true", }) diff --git a/packages/kilo-vscode/script/publish.ts b/packages/kilo-vscode/script/publish.ts index ef891606266..8741734e5a1 100755 --- a/packages/kilo-vscode/script/publish.ts +++ b/packages/kilo-vscode/script/publish.ts @@ -4,7 +4,9 @@ import { join } from "node:path" import { existsSync } from "node:fs" import { Script } from "@opencode-ai/script" -console.log(`Publishing VSCode extension for release: v${Script.version}`) +const prerelease = process.env.KILO_PRE_RELEASE === "true" + +console.log(`Publishing VSCode extension for ${prerelease ? "pre-release" : "release"}: v${Script.version}`) const outDir = process.env.VSIX_DIR || join(import.meta.dir, "..", "out") @@ -36,14 +38,16 @@ for (const target of targets) { console.log(`\nFound ${vsixFiles.length} VSIX files`) +const flag = prerelease ? ["--pre-release"] : [] + for (const target of targets) { const vsixPath = join(outDir, `kilo-vscode-${target}.vsix`) - console.log(`\n🚀 Publishing ${target} to VS Code Marketplace...`) - await $`vsce publish --packagePath ${vsixPath}` + console.log(`\n🚀 Publishing ${target} to VS Code Marketplace${prerelease ? " (pre-release)" : ""}...`) + await $`vsce publish ${flag} --packagePath ${vsixPath}` console.log(` ✅ Published ${target} to VS Code Marketplace`) - console.log(`\n📤 Publishing ${target} to Open VSX...`) - await $`npx ovsx publish --pat ${process.env.OPENVSX_TOKEN} --packagePath ${vsixPath}` + console.log(`\n📤 Publishing ${target} to Open VSX${prerelease ? " (pre-release)" : ""}...`) + await $`npx ovsx publish ${flag} --pat ${process.env.OPENVSX_TOKEN} --packagePath ${vsixPath}` console.log(` ✅ Published ${target} to Open VSX`) } diff --git a/script/release b/script/release index 13761a1ec0b..044a2c59d6a 100755 --- a/script/release +++ b/script/release @@ -1,5 +1,6 @@ #!/usr/bin/env bash BUMP_TYPE=${1:-patch} +PRE_RELEASE=${2:-false} -gh workflow run publish.yml -f bump="$BUMP_TYPE" +gh workflow run publish.yml -f bump="$BUMP_TYPE" -f pre_release="$PRE_RELEASE" From 56f73d8778e09c3856d21f3b07e1c73e83f513e4 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 10:16:52 +0000 Subject: [PATCH 09/83] docs: update local code reviews section to three-tab layout --- .../pages/automate/code-reviews/overview.md | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/kilo-docs/pages/automate/code-reviews/overview.md b/packages/kilo-docs/pages/automate/code-reviews/overview.md index c89e043a9a4..5b04e1137d5 100644 --- a/packages/kilo-docs/pages/automate/code-reviews/overview.md +++ b/packages/kilo-docs/pages/automate/code-reviews/overview.md @@ -56,19 +56,32 @@ Once configured, the Review Agent runs automatically on PR/MR events. For platfo Code Reviewer is also available locally. This is valuable for developers who want to review their code before pushing a pull request to their team publicly, or for developers who want reviews and don't need to ship a pull request to GitHub. -### VS Code +{% tabs %} +{% tab label="VSCode" %} -Select 'Review' from the mode dropdown after making local changes, and click 'Send' for AI-powered feedback and suggestions. - -![VS Code interface showing Review option in mode dropdown](/docs/img/code-reviewer/review-mode.png "Review Mode") - -### CLI - -The CLI provides two commands for local code reviews: +Two slash commands are available for local code reviews: - **`/local-review`** — Review all changes on your current branch vs the base branch - **`/local-review-uncommitted`** — Review uncommitted changes (staged + unstaged) +{% /tab %} +{% tab label="CLI" %} + +Two slash commands are available for local code reviews: + +- **`/local-review`** — Review all changes on your current branch vs the base branch +- **`/local-review-uncommitted`** — Review uncommitted changes (staged + unstaged) + +{% /tab %} +{% tab label="VSCode (Legacy)" %} + +Select 'Review' from the mode dropdown after making local changes, and click 'Send' for AI-powered feedback and suggestions. + +{% image src="/docs/img/code-reviewer/review-mode.png" alt="VS Code interface showing Review option in mode dropdown" width="800" caption="Review Mode" /%} + +{% /tab %} +{% /tabs %} + ## How Code Reviews Work When a pull request or merge request is opened or updated: From f72b3fa3e716ae824a694b16d5125120c12b6459 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 15:42:04 +0000 Subject: [PATCH 10/83] fix(kilo-docs): exclude consistently timing-out URLs from link checker --- packages/kilo-docs/lychee.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/kilo-docs/lychee.toml b/packages/kilo-docs/lychee.toml index 9d082c95adb..f86612c02b0 100644 --- a/packages/kilo-docs/lychee.toml +++ b/packages/kilo-docs/lychee.toml @@ -36,4 +36,7 @@ exclude = [ '^https?://api\.apertis\.ai/v1/?$', # Redirects to authenticated Google Cloud console '^https?://console\.cloud\.google\.com', + # Consistently times out in CI + '^https?://opncd\.ai', + '^https?://zod\.dev/v4/changelog', ] From c06d8e0fa69f308e4be2364140ce3bf20795354a Mon Sep 17 00:00:00 2001 From: kirillk Date: Thu, 2 Apr 2026 12:10:12 -0400 Subject: [PATCH 11/83] feat(jetbrains): add CLI binary bundling and build pipeline Adds a build system that compiles Kilo CLI binaries and packages them into the backend jar at /cli/{os}/kilo for runtime extraction. - script/build.ts: orchestrates CLI build + Gradle plugin build - Local mode (bun run build): builds current platform only - Production mode (bun run build:production): requires all 6 platforms - Gradle checkCli task validates binaries before processResources - Turbo integration via @kilocode/kilo-jetbrains#build - README with setup and build instructions --- bun.lock | 5 + packages/kilo-jetbrains/README.md | 69 ++++++++++ .../kilo-jetbrains/backend/build.gradle.kts | 49 +++++++ packages/kilo-jetbrains/build.gradle.kts | 2 + packages/kilo-jetbrains/package.json | 8 ++ packages/kilo-jetbrains/script/build.ts | 128 ++++++++++++++++++ turbo.json | 4 + 7 files changed, 265 insertions(+) create mode 100644 packages/kilo-jetbrains/README.md create mode 100644 packages/kilo-jetbrains/package.json create mode 100644 packages/kilo-jetbrains/script/build.ts diff --git a/bun.lock b/bun.lock index a78c9245ce4..9b06a85a6ce 100644 --- a/bun.lock +++ b/bun.lock @@ -214,6 +214,9 @@ "typescript": "catalog:", }, }, + "packages/kilo-jetbrains": { + "name": "@kilocode/kilo-jetbrains", + }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", "version": "7.1.17", @@ -1211,6 +1214,8 @@ "@kilocode/kilo-i18n": ["@kilocode/kilo-i18n@workspace:packages/kilo-i18n"], + "@kilocode/kilo-jetbrains": ["@kilocode/kilo-jetbrains@workspace:packages/kilo-jetbrains"], + "@kilocode/kilo-telemetry": ["@kilocode/kilo-telemetry@workspace:packages/kilo-telemetry"], "@kilocode/kilo-ui": ["@kilocode/kilo-ui@workspace:packages/kilo-ui"], diff --git a/packages/kilo-jetbrains/README.md b/packages/kilo-jetbrains/README.md new file mode 100644 index 00000000000..85cef069ea7 --- /dev/null +++ b/packages/kilo-jetbrains/README.md @@ -0,0 +1,69 @@ +# Kilo JetBrains + +AI coding agent plugin for JetBrains IDEs. + +--- + +## Set up your environment + +### Prerequisites + +- **Bun** -- used to build CLI binaries and run build scripts +- **JDK 21+** -- required by Gradle and the IntelliJ Platform SDK +- **IntelliJ IDEA** -- to run the plugin in a sandboxed IDE + +--- + +## Open in IntelliJ + +When you open the monorepo root in IntelliJ IDEA, the Gradle project at `packages/kilo-jetbrains/` should be auto-detected via `.idea/gradle.xml`. If not, link it manually: **File > Settings > Build Tools > Gradle > +** and select `packages/kilo-jetbrains/settings.gradle.kts`. + +--- + +## Build locally + +From `packages/kilo-jetbrains/`: + +``` +bun run build +``` + +This builds the CLI binary for your current OS/arch only, copies it into the backend module resources, and runs `./gradlew buildPlugin`. The plugin archive is output to `build/distributions/`. + +Or via Turbo from the repo root: + +``` +bun turbo build --filter=@kilocode/kilo-jetbrains +``` + +--- + +## Build for production + +From `packages/kilo-jetbrains/`: + +``` +bun run build:production +``` + +This builds CLI binaries for all 6 desktop platforms (darwin-arm64, darwin-x64, linux-arm64, linux-x64, windows-x64, windows-arm64), copies them all into the backend jar, and fails if any are missing. Gradle also validates all platforms are present via `-Pproduction=true`. + +--- + +## Run the plugin + +After building, use the `runIde` Gradle task (available in the Gradle tool window or via the "Run JetBrains Plugin" run configuration) to launch a sandboxed IntelliJ instance with the plugin installed. + +Note: `runIde` does not build CLI binaries -- run `bun run build` at least once before using it. Subsequent Kotlin/Gradle changes can be iterated with `runIde` directly. + +--- + +## Run Gradle directly + +You can run `./gradlew buildPlugin` directly if CLI binaries are already in `backend/build/generated/cli/`. Gradle will fail with a clear error if they are missing. + +For production verification: + +``` +./gradlew buildPlugin -Pproduction=true +``` diff --git a/packages/kilo-jetbrains/backend/build.gradle.kts b/packages/kilo-jetbrains/backend/build.gradle.kts index 71c776146af..383a5497ee1 100644 --- a/packages/kilo-jetbrains/backend/build.gradle.kts +++ b/packages/kilo-jetbrains/backend/build.gradle.kts @@ -6,6 +6,55 @@ kotlin { jvmToolchain(21) } +sourceSets { + main { + resources.srcDir(layout.buildDirectory.dir("generated/cli")) + } +} + +val cliDir = layout.buildDirectory.dir("generated/cli/cli") +val production = providers.gradleProperty("production").map { it.toBoolean() }.orElse(false) + +val requiredPlatforms = listOf( + "darwin-arm64", + "darwin-x64", + "linux-arm64", + "linux-x64", + "windows-x64", + "windows-arm64", +) + +val checkCli by tasks.registering { + description = "Verify CLI binaries exist before building" + val dir = cliDir.map { it.asFile } + val prod = production.get() + val platforms = requiredPlatforms.toList() + doLast { + val resolved = dir.get() + if (!resolved.exists() || resolved.listFiles()?.isEmpty() != false) { + throw GradleException( + "CLI binaries not found at ${resolved.absolutePath}.\n" + + "Run 'bun run build' from packages/kilo-jetbrains/ to build CLI and plugin together." + ) + } + if (prod) { + val present = resolved.listFiles()?.map { it.name }?.toSet() ?: emptySet() + val missing = platforms.filter { it !in present } + if (missing.isNotEmpty()) { + throw GradleException( + "Production build requires all platform CLI binaries.\n" + + "Missing: ${missing.joinToString(", ")}\n" + + "Run 'bun run build:production' to build all platforms." + ) + } + } + } +} + +tasks.processResources { + dependsOn(checkCli) +} + dependencies { intellijPlatform { intellijIdea(libs.versions.intellij.platform) diff --git a/packages/kilo-jetbrains/build.gradle.kts b/packages/kilo-jetbrains/build.gradle.kts index 0c1e4946008..893575eb1f1 100644 --- a/packages/kilo-jetbrains/build.gradle.kts +++ b/packages/kilo-jetbrains/build.gradle.kts @@ -50,3 +50,5 @@ intellijPlatform { } } } + + diff --git a/packages/kilo-jetbrains/package.json b/packages/kilo-jetbrains/package.json new file mode 100644 index 00000000000..34b33a8422a --- /dev/null +++ b/packages/kilo-jetbrains/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kilocode/kilo-jetbrains", + "private": true, + "scripts": { + "build": "bun script/build.ts", + "build:production": "bun script/build.ts --production" + } +} diff --git a/packages/kilo-jetbrains/script/build.ts b/packages/kilo-jetbrains/script/build.ts new file mode 100644 index 00000000000..fe0dfb1d2c3 --- /dev/null +++ b/packages/kilo-jetbrains/script/build.ts @@ -0,0 +1,128 @@ +#!/usr/bin/env bun + +/** + * Build the Kilo JetBrains plugin. + * + * Usage: + * bun script/build.ts # Local build — only current platform binary required + * bun script/build.ts --production # Production build — all 6 platform binaries required + * + * Steps: + * 1. Builds CLI binaries (or uses prebuilt ones from dist/). + * Local: builds only current platform (--single). + * Production: builds all platforms. + * 2. Copies them into backend/build/generated/cli/cli/{os}/kilo[.exe] + * so they end up inside the backend jar at /cli/{os}/kilo. + * 3. Invokes Gradle to build the plugin. + */ + +import { $ } from "bun" +import { join, relative } from "node:path" +import { existsSync, mkdirSync, chmodSync, cpSync, rmSync } from "node:fs" + +const production = process.argv.includes("--production") + +const root = join(import.meta.dir, "..") +const packages = join(root, "..") +const opencodeDir = join(packages, "opencode") +const distDir = join(opencodeDir, "dist") +const cliDir = join(root, "backend", "build", "generated", "cli", "cli") + +/** All desktop platforms. */ +const platforms = [ + { os: "darwin-arm64", exe: "kilo" }, + { os: "darwin-x64", exe: "kilo" }, + { os: "linux-arm64", exe: "kilo" }, + { os: "linux-x64", exe: "kilo" }, + { os: "windows-x64", exe: "kilo.exe" }, + { os: "windows-arm64", exe: "kilo.exe" }, +] as const + +function localPlatformTag(): string { + const os = process.platform === "win32" ? "windows" : process.platform + return `${os}-${process.arch}` +} + +function log(msg: string) { + console.log(`[jetbrains-build] ${msg}`) +} + +function distBinPath(os: string, exe: string): string { + return join(distDir, `@kilocode/cli-${os}`, "bin", exe) +} + +function hasDist(): boolean { + if (production) { + return platforms.every((p) => existsSync(distBinPath(p.os, p.exe))) + } + const tag = localPlatformTag() + const local = platforms.find((p) => p.os === tag) + return local ? existsSync(distBinPath(local.os, local.exe)) : false +} + +async function prepareCli() { + const mode = production ? "production" : "local" + log(`Mode: ${mode}`) + + if (!hasDist()) { + log("Building CLI binaries via opencode...") + if (!existsSync(join(opencodeDir, "package.json"))) { + throw new Error(`Expected opencode package at ${opencodeDir}`) + } + const args = production ? [] : ["--single"] + await $`bun run build ${args}`.cwd(opencodeDir) + } else { + log("Found prebuilt CLI binaries in opencode/dist/, skipping CLI build") + } + + if (existsSync(cliDir)) { + rmSync(cliDir, { recursive: true }) + } + + const missing: string[] = [] + let copied = 0 + for (const p of platforms) { + const src = distBinPath(p.os, p.exe) + if (!existsSync(src)) { + missing.push(p.os) + continue + } + + const dir = join(cliDir, p.os) + mkdirSync(dir, { recursive: true }) + const dest = join(dir, p.exe) + cpSync(src, dest) + chmodSync(dest, 0o755) + copied++ + log(`Copied ${relative(root, src)} -> ${relative(root, dest)}`) + } + + if (copied === 0) { + throw new Error("No CLI binaries were copied — the build cannot proceed") + } + + if (production && missing.length > 0) { + throw new Error(`Production build requires all platform binaries. Missing: ${missing.join(", ")}`) + } + + if (missing.length > 0) { + log(`Skipped ${missing.length} platforms (not needed for local build): ${missing.join(", ")}`) + } + + log(`Copied ${copied}/${platforms.length} platform binaries`) +} + +async function buildPlugin() { + log("Building JetBrains plugin via Gradle...") + const args = production ? ["-Pproduction=true"] : [] + await $`./gradlew buildPlugin ${args}`.cwd(root) + log("Done. Plugin archive is in build/distributions/") +} + +try { + await prepareCli() + await buildPlugin() +} catch (err) { + console.error(`[jetbrains-build] ERROR: ${err instanceof Error ? err.message : String(err)}`) + process.exit(1) +} diff --git a/turbo.json b/turbo.json index bf1c18ab91e..03f3aa6dcaf 100644 --- a/turbo.json +++ b/turbo.json @@ -22,6 +22,10 @@ "dependsOn": ["^build"], "outputs": [".next/**"], "env": ["POSTHOG_API_KEY", "FREE_TIER_AMOUNT", "NEXT_PUBLIC_POSTHOG_KEY", "NEXT_PUBLIC_POSTHOG_HOST"] + }, + "@kilocode/kilo-jetbrains#build": { + "dependsOn": ["@kilocode/cli#build"], + "outputs": ["build/distributions/**"] } } } From 64cec90f89b4df856557b03a71e7785f50864bfe Mon Sep 17 00:00:00 2001 From: kirillk Date: Thu, 2 Apr 2026 12:20:31 -0400 Subject: [PATCH 12/83] fix(jetbrains): use gradlew.bat on Windows for Gradle invocation --- packages/kilo-jetbrains/script/build.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/kilo-jetbrains/script/build.ts b/packages/kilo-jetbrains/script/build.ts index fe0dfb1d2c3..8a82168276c 100644 --- a/packages/kilo-jetbrains/script/build.ts +++ b/packages/kilo-jetbrains/script/build.ts @@ -112,10 +112,12 @@ async function prepareCli() { log(`Copied ${copied}/${platforms.length} platform binaries`) } +const gradlew = process.platform === "win32" ? "gradlew.bat" : "./gradlew" + async function buildPlugin() { log("Building JetBrains plugin via Gradle...") const args = production ? ["-Pproduction=true"] : [] - await $`./gradlew buildPlugin ${args}`.cwd(root) + await $`${gradlew} buildPlugin ${args}`.cwd(root) log("Done. Plugin archive is in build/distributions/") } From 599f05288c8eacb2b002e0fcf37532183aa9d751 Mon Sep 17 00:00:00 2001 From: kirillk Date: Thu, 2 Apr 2026 12:22:20 -0400 Subject: [PATCH 13/83] fix(jetbrains): validate actual CLI executables exist, not just directories --- packages/kilo-jetbrains/backend/build.gradle.kts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/kilo-jetbrains/backend/build.gradle.kts b/packages/kilo-jetbrains/backend/build.gradle.kts index 383a5497ee1..296cd4e8d8f 100644 --- a/packages/kilo-jetbrains/backend/build.gradle.kts +++ b/packages/kilo-jetbrains/backend/build.gradle.kts @@ -38,8 +38,11 @@ val checkCli by tasks.registering { ) } if (prod) { - val present = resolved.listFiles()?.map { it.name }?.toSet() ?: emptySet() - val missing = platforms.filter { it !in present } + val missing = platforms.filter { platform -> + val dir = File(resolved, platform) + val exe = if (platform.startsWith("windows")) "kilo.exe" else "kilo" + !File(dir, exe).exists() + } if (missing.isNotEmpty()) { throw GradleException( "Production build requires all platform CLI binaries.\n" + From e3e6c96f20c9a04a199a971a4d3ce0f84e3c0a3a Mon Sep 17 00:00:00 2001 From: "kilo-code-bot[bot]" <240665456+kilo-code-bot[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:57:39 +0200 Subject: [PATCH 14/83] fix(vscode): update migration wizard blog announcement URL (#8217) * fix(vscode): update migration wizard blog announcement URL * chore(kilo-docs): regenerate source-links.md after blog URL change --------- Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com> --- packages/kilo-docs/source-links.md | 2 +- .../webview-ui/src/components/migration/MigrationWizard.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kilo-docs/source-links.md b/packages/kilo-docs/source-links.md index d6a23265bd3..47575601aa1 100644 --- a/packages/kilo-docs/source-links.md +++ b/packages/kilo-docs/source-links.md @@ -21,7 +21,7 @@ - -- +- - diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx b/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx index abad016a248..7900ef1de3f 100644 --- a/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx @@ -548,7 +548,7 @@ const MigrationWizard: Component = (props) => {

From 09a1faf21e9cf237dee60fa5333581106d4a0673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Catriel=20M=C3=BCller?= Date: Thu, 2 Apr 2026 14:22:40 -0300 Subject: [PATCH 15/83] feat(cli): add org support for /kiloclaw command Pass the selected organization context through to KiloClaw API endpoints so the /kiloclaw command resolves the correct org-scoped instance when a team is selected via /teams. --- packages/kilo-gateway/src/server/routes.ts | 38 ++++++++++++------- .../kilocode/components/dialog-claw-setup.tsx | 6 ++- .../components/dialog-claw-upgrade.tsx | 6 ++- .../opencode/src/kilocode/kilo-commands.tsx | 12 ++++-- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/packages/kilo-gateway/src/server/routes.ts b/packages/kilo-gateway/src/server/routes.ts index cb1890fe80f..e6f688913a8 100644 --- a/packages/kilo-gateway/src/server/routes.ts +++ b/packages/kilo-gateway/src/server/routes.ts @@ -8,7 +8,7 @@ import { fetchProfile, fetchBalance } from "../api/profile.js" import { fetchKilocodeNotifications, KilocodeNotificationSchema } from "../api/notifications.js" import { fetchOrganizationModes, clearModesCache } from "../api/modes.js" -import { KILO_API_BASE, HEADER_FEATURE } from "../api/constants.js" +import { KILO_API_BASE, HEADER_FEATURE, HEADER_ORGANIZATIONID } from "../api/constants.js" import { buildKiloHeaders } from "../headers.js" import type { ImportDeps, DrizzleDb } from "../cloud-sessions.js" import { fetchCloudSession, fetchCloudSessionForImport, importSessionToDb } from "../cloud-sessions.js" @@ -536,12 +536,18 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined if (!token) return c.json({ error: "No valid token found" }, 401) - const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/status`, { - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - }) + // kilocode_change start - pass org context for org-scoped instances + const orgId = auth.type === "oauth" ? auth.accountId : undefined + const headers: Record = { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + } + if (orgId) { + headers[HEADER_ORGANIZATIONID] = orgId + } + // kilocode_change end + + const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/status`, { headers }) if (!response.ok) { const text = await response.text() @@ -589,12 +595,18 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined if (!token) return c.json({ error: "No valid token found" }, 401) - const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/chat-credentials`, { - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - }) + // kilocode_change start - pass org context for org-scoped instances + const orgId = auth.type === "oauth" ? auth.accountId : undefined + const headers: Record = { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + } + if (orgId) { + headers[HEADER_ORGANIZATIONID] = orgId + } + // kilocode_change end + + const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/chat-credentials`, { headers }) if (!response.ok) { const text = await response.text() diff --git a/packages/opencode/src/kilocode/components/dialog-claw-setup.tsx b/packages/opencode/src/kilocode/components/dialog-claw-setup.tsx index 145777d026f..e9e000f046c 100644 --- a/packages/opencode/src/kilocode/components/dialog-claw-setup.tsx +++ b/packages/opencode/src/kilocode/components/dialog-claw-setup.tsx @@ -13,10 +13,12 @@ import { useTheme } from "@tui/context/theme" import { useDialog } from "@tui/ui/dialog" import { Link } from "@tui/ui/link" -export function DialogClawSetup() { +export function DialogClawSetup(props: { orgId?: string | null }) { const { theme } = useTheme() const dialog = useDialog() + const url = props.orgId ? `https://app.kilo.ai/organizations/${props.orgId}/claw` : "https://app.kilo.ai/claw" + useKeyboard((evt: any) => { if (evt.name === "return") { dialog.clear() @@ -56,7 +58,7 @@ export function DialogClawSetup() { {"🦀 "} - + Try KiloClaw diff --git a/packages/opencode/src/kilocode/components/dialog-claw-upgrade.tsx b/packages/opencode/src/kilocode/components/dialog-claw-upgrade.tsx index df07b48e139..5047901bcc4 100644 --- a/packages/opencode/src/kilocode/components/dialog-claw-upgrade.tsx +++ b/packages/opencode/src/kilocode/components/dialog-claw-upgrade.tsx @@ -13,10 +13,12 @@ import { useTheme } from "@tui/context/theme" import { useDialog } from "@tui/ui/dialog" import { Link } from "@tui/ui/link" -export function DialogClawUpgrade() { +export function DialogClawUpgrade(props: { orgId?: string | null }) { const { theme } = useTheme() const dialog = useDialog() + const url = props.orgId ? `https://app.kilo.ai/organizations/${props.orgId}/claw` : "https://app.kilo.ai/claw" + useKeyboard((evt: any) => { if (evt.name === "return") { dialog.clear() @@ -44,7 +46,7 @@ export function DialogClawUpgrade() { - + Dashboard diff --git a/packages/opencode/src/kilocode/kilo-commands.tsx b/packages/opencode/src/kilocode/kilo-commands.tsx index cb14f0ab009..e622b35ee22 100644 --- a/packages/opencode/src/kilocode/kilo-commands.tsx +++ b/packages/opencode/src/kilocode/kilo-commands.tsx @@ -52,13 +52,17 @@ export function registerKiloCommands(useSDK: () => UseSDK) { enabled: isKiloConnected(), hidden: !isKiloConnected(), onSelect: async () => { - // Check instance status first - const res = await sdk.client.kilo.claw.status().catch(() => null) + // Fetch profile (for org context) and instance status in parallel + const [profileRes, res] = await Promise.all([ + sdk.client.kilo.profile().catch(() => null), + sdk.client.kilo.claw.status().catch(() => null), + ]) + const orgId = profileRes?.data?.currentOrgId ?? null const status = res?.data as ClawStatus | undefined // No instance provisioned if (!status || !status.userId || res.error) { - dialog.replace(() => ) + dialog.replace(() => ) return } @@ -67,7 +71,7 @@ export function registerKiloCommands(useSDK: () => UseSDK) { if (!creds?.data || creds.error) { // Instance exists but no chat credentials — needs upgrade - dialog.replace(() => ) + dialog.replace(() => ) return } From 61ed399244c2fe1c61e249cc6cd35506d748645b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Catriel=20M=C3=BCller?= Date: Thu, 2 Apr 2026 14:28:23 -0300 Subject: [PATCH 16/83] refactor(gateway): rename orgId to organizationId for consistency Align variable naming with existing patterns in the same file (lines 326, 396). --- packages/kilo-gateway/src/server/routes.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/kilo-gateway/src/server/routes.ts b/packages/kilo-gateway/src/server/routes.ts index e6f688913a8..83848ca132a 100644 --- a/packages/kilo-gateway/src/server/routes.ts +++ b/packages/kilo-gateway/src/server/routes.ts @@ -537,13 +537,13 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { if (!token) return c.json({ error: "No valid token found" }, 401) // kilocode_change start - pass org context for org-scoped instances - const orgId = auth.type === "oauth" ? auth.accountId : undefined + const organizationId = auth.type === "oauth" ? auth.accountId : undefined const headers: Record = { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } - if (orgId) { - headers[HEADER_ORGANIZATIONID] = orgId + if (organizationId) { + headers[HEADER_ORGANIZATIONID] = organizationId } // kilocode_change end @@ -596,13 +596,13 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { if (!token) return c.json({ error: "No valid token found" }, 401) // kilocode_change start - pass org context for org-scoped instances - const orgId = auth.type === "oauth" ? auth.accountId : undefined + const organizationId = auth.type === "oauth" ? auth.accountId : undefined const headers: Record = { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } - if (orgId) { - headers[HEADER_ORGANIZATIONID] = orgId + if (organizationId) { + headers[HEADER_ORGANIZATIONID] = organizationId } // kilocode_change end From b91653bf97eb03be5a2d129215de56a9e7daaa46 Mon Sep 17 00:00:00 2001 From: "kilo-maintainer[bot]" Date: Thu, 2 Apr 2026 17:33:20 +0000 Subject: [PATCH 17/83] release: v7.1.20 --- bun.lock | 32 +++++++++++++------------- package.json | 2 +- packages/app/package.json | 2 +- packages/desktop-electron/package.json | 2 +- packages/desktop/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++----- packages/kilo-docs/package.json | 2 +- packages/kilo-gateway/package.json | 2 +- packages/kilo-i18n/package.json | 2 +- packages/kilo-telemetry/package.json | 2 +- packages/kilo-ui/package.json | 2 +- packages/kilo-vscode/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/script/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/storybook/package.json | 2 +- packages/ui/package.json | 2 +- packages/util/package.json | 2 +- script/upstream/package.json | 2 +- sdks/vscode/package.json | 2 +- 21 files changed, 41 insertions(+), 41 deletions(-) diff --git a/bun.lock b/bun.lock index e5716d0cfaa..b8f8ee25243 100644 --- a/bun.lock +++ b/bun.lock @@ -27,7 +27,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@kilocode/kilo-i18n": "workspace:*", "@kilocode/kilo-ui": "workspace:*", @@ -79,7 +79,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -112,7 +112,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -142,7 +142,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -171,7 +171,7 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@ai-sdk/anthropic": "2.0.65", "@ai-sdk/openai": "2.0.101", @@ -206,7 +206,7 @@ }, "packages/kilo-i18n": { "name": "@kilocode/kilo-i18n", - "version": "7.1.19", + "version": "7.1.20", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -216,7 +216,7 @@ }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "@opentelemetry/api": "1.9.0", @@ -236,7 +236,7 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@kobalte/core": "0.13.11", "@opencode-ai/util": "workspace:*", @@ -271,7 +271,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-i18n": "workspace:*", @@ -324,7 +324,7 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.1.19", + "version": "7.1.20", "bin": { "kilo": "./bin/kilo", "kilocode": "./bin/kilo", @@ -448,7 +448,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@kilocode/sdk": "workspace:*", "zod": "catalog:", @@ -462,14 +462,14 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.1.19", + "version": "7.1.20", "devDependencies": { "@types/bun": "catalog:", }, }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.1.19", + "version": "7.1.20", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -480,7 +480,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.1.19", + "version": "7.1.20", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -503,7 +503,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -550,7 +550,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "7.1.19", + "version": "7.1.20", "dependencies": { "zod": "catalog:", }, diff --git a/package.json b/package.json index 0db59b77198..904a5a290d6 100644 --- a/package.json +++ b/package.json @@ -112,6 +112,6 @@ "@openrouter/ai-sdk-provider@1.5.4": "patches/@openrouter%2Fai-sdk-provider@1.5.4.patch", "ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch" }, - "version": "7.1.19", + "version": "7.1.20", "peerDependencies": {} } diff --git a/packages/app/package.json b/packages/app/package.json index 54bf6419cef..5a118458382 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "7.1.19", + "version": "7.1.20", "description": "", "type": "module", "exports": { diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index 09598e2628b..fda4582038e 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 03ced8b0a1f..d13399bae9e 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index e3bdb625733..522d8ecbbb0 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "kilo" name = "Kilo" description = "The open source coding agent." -version = "7.1.19" +version = "7.1.20" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/Kilo-Org/kilocode" @@ -11,26 +11,26 @@ name = "Kilo" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.19/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.19/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.19/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.19/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.19/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/kilo-docs/package.json b/packages/kilo-docs/package.json index b5bf3730fb6..35af7893fb5 100644 --- a/packages/kilo-docs/package.json +++ b/packages/kilo-docs/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-docs", - "version": "7.1.19", + "version": "7.1.20", "private": true, "scripts": { "dev": "next dev --webpack --port 3002", diff --git a/packages/kilo-gateway/package.json b/packages/kilo-gateway/package.json index f7477216ac4..2fe42fe6c7d 100644 --- a/packages/kilo-gateway/package.json +++ b/packages/kilo-gateway/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-gateway", - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration", diff --git a/packages/kilo-i18n/package.json b/packages/kilo-i18n/package.json index 3c9608e562b..6799fd9ba2f 100644 --- a/packages/kilo-i18n/package.json +++ b/packages/kilo-i18n/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-i18n", - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "description": "Kilo-specific i18n translations and overrides", diff --git a/packages/kilo-telemetry/package.json b/packages/kilo-telemetry/package.json index b205063ae32..ce9af0d3fd7 100644 --- a/packages/kilo-telemetry/package.json +++ b/packages/kilo-telemetry/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-telemetry", - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "description": "Telemetry for Kilo CLI - PostHog analytics integration", diff --git a/packages/kilo-ui/package.json b/packages/kilo-ui/package.json index b38ea9d0383..fb213597db2 100644 --- a/packages/kilo-ui/package.json +++ b/packages/kilo-ui/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-ui", - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "exports": { diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 622dbc64b83..f6cc9503fdd 100644 --- a/packages/kilo-vscode/package.json +++ b/packages/kilo-vscode/package.json @@ -2,7 +2,7 @@ "name": "kilo-code", "displayName": "Kilo Code: AI Coding Agent, Copilot, and Autocomplete", "description": "Open Source AI coding agent that generates code from natural language, automates tasks, and runs terminal commands. Features inline autocomplete, browser automation, automated refactoring, and custom modes for planning, coding, and debugging. Supports 500+ AI models including Claude (Anthropic), Gemini, Grok, GPT, Codex and GLM.", - "version": "7.1.19", + "version": "7.1.20", "icon": "assets/icons/logo-outline-black.png", "galleryBanner": { "color": "#FFFFFF", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index de81dac67cc..ceaca556f92 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.1.19", + "version": "7.1.20", "name": "@kilocode/cli", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 4cd9efa4235..ff5eb6e80d2 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/plugin", - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/script/package.json b/packages/script/package.json index 410d9968035..1356f952e88 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -8,7 +8,7 @@ "exports": { ".": "./src/index.ts" }, - "version": "7.1.19", + "version": "7.1.20", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 039d64876a0..4423b02360f 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/sdk", - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/storybook/package.json b/packages/storybook/package.json index b1d1d8ea5a2..60ff61ce99e 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -26,7 +26,7 @@ "typescript": "catalog:", "vite": "catalog:" }, - "version": "7.1.19", + "version": "7.1.20", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/ui/package.json b/packages/ui/package.json index aaa5123237e..9e9f4f9db51 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "7.1.19", + "version": "7.1.20", "type": "module", "license": "MIT", "exports": { diff --git a/packages/util/package.json b/packages/util/package.json index ba7477b2624..7d91217bac9 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "7.1.19", + "version": "7.1.20", "private": true, "type": "module", "license": "MIT", diff --git a/script/upstream/package.json b/script/upstream/package.json index 58f7c06d8a9..01c7bf0ffc0 100644 --- a/script/upstream/package.json +++ b/script/upstream/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/upstream-merge", - "version": "7.1.19", + "version": "7.1.20", "private": true, "type": "module", "description": "Scripts for automating upstream opencode merges into Kilo", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 34b32c1b5d5..35bf406f11b 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "7.1.19", + "version": "7.1.20", "publisher": "sst-dev", "repository": { "type": "git", From e4d9f007d461c35494106bfd5f60d1393f5012ba Mon Sep 17 00:00:00 2001 From: kirillk Date: Thu, 2 Apr 2026 13:49:41 -0400 Subject: [PATCH 18/83] docs(jetbrains): add built plugin location to README --- packages/kilo-jetbrains/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/kilo-jetbrains/README.md b/packages/kilo-jetbrains/README.md index 85cef069ea7..d2543504aa4 100644 --- a/packages/kilo-jetbrains/README.md +++ b/packages/kilo-jetbrains/README.md @@ -48,6 +48,8 @@ bun run build:production This builds CLI binaries for all 6 desktop platforms (darwin-arm64, darwin-x64, linux-arm64, linux-x64, windows-x64, windows-arm64), copies them all into the backend jar, and fails if any are missing. Gradle also validates all platforms are present via `-Pproduction=true`. +The built plugin archive is at `build/distributions/kilo.jetbrains-.zip`. This zip can be installed in any JetBrains IDE via **Settings > Plugins > Install Plugin from Disk**. + --- ## Run the plugin From 26922a9b04d312cf7d238ae2fbb9191ab9bf6e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Catriel=20M=C3=BCller?= Date: Thu, 2 Apr 2026 15:10:06 -0300 Subject: [PATCH 19/83] feat: nix support for jetbrains plugin build --- flake.nix | 62 +++++++++++++++++------- packages/kilo-jetbrains/build.gradle.kts | 6 +++ 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/flake.nix b/flake.nix index ed9a99e8a6e..1fa4fae94e1 100644 --- a/flake.nix +++ b/flake.nix @@ -150,28 +150,54 @@ ''; in pkgs.mkShell { - packages = with pkgs; [ - bun - nodejs_20 - pkg-config - openssl - git - gh - playwright-driver.browsers - vsce - unzip - gnutar - gzip - patchelf - ripgrep - kilo-dev - kilo-install-bin - kilo-bin - ]; + packages = + with pkgs; + [ + bun + nodejs_20 + pkg-config + openssl + git + gh + playwright-driver.browsers + vsce + unzip + gnutar + gzip + patchelf + ripgrep + jetbrains.jdk + jdk21 + kilo-dev + kilo-install-bin + kilo-bin + ] + ++ lib.optionals stdenv.isLinux [ + libX11 + libXext + libXrender + libXtst + libXi + fontconfig + freetype + ]; shellHook = '' export KILO_ROOT="$PWD" export PLAYWRIGHT_BROWSERS_PATH="${pkgs.playwright-driver.browsers}" export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true + '' + + pkgs.lib.optionalString pkgs.stdenv.isLinux '' + export LD_LIBRARY_PATH="${ + pkgs.lib.makeLibraryPath [ + pkgs.libX11 + pkgs.libXext + pkgs.libXrender + pkgs.libXtst + pkgs.libXi + pkgs.fontconfig + pkgs.freetype + ] + }:$LD_LIBRARY_PATH" ''; }; }); diff --git a/packages/kilo-jetbrains/build.gradle.kts b/packages/kilo-jetbrains/build.gradle.kts index 893575eb1f1..671a4cd5e3a 100644 --- a/packages/kilo-jetbrains/build.gradle.kts +++ b/packages/kilo-jetbrains/build.gradle.kts @@ -51,4 +51,10 @@ intellijPlatform { } } +tasks.named("runIde") { + jvmArgumentProviders += CommandLineArgumentProvider { + listOf("-Dnosplash=true") + } +} + From eeebdb92b593c44a006368ff21a97e7d2a40c8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Catriel=20M=C3=BCller?= Date: Thu, 2 Apr 2026 15:22:15 -0300 Subject: [PATCH 20/83] refactor: remove markers --- packages/kilo-gateway/src/server/routes.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/kilo-gateway/src/server/routes.ts b/packages/kilo-gateway/src/server/routes.ts index 83848ca132a..44e36e3a3e3 100644 --- a/packages/kilo-gateway/src/server/routes.ts +++ b/packages/kilo-gateway/src/server/routes.ts @@ -536,7 +536,6 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined if (!token) return c.json({ error: "No valid token found" }, 401) - // kilocode_change start - pass org context for org-scoped instances const organizationId = auth.type === "oauth" ? auth.accountId : undefined const headers: Record = { Authorization: `Bearer ${token}`, @@ -545,7 +544,6 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { if (organizationId) { headers[HEADER_ORGANIZATIONID] = organizationId } - // kilocode_change end const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/status`, { headers }) @@ -595,7 +593,6 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined if (!token) return c.json({ error: "No valid token found" }, 401) - // kilocode_change start - pass org context for org-scoped instances const organizationId = auth.type === "oauth" ? auth.accountId : undefined const headers: Record = { Authorization: `Bearer ${token}`, @@ -604,7 +601,6 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { if (organizationId) { headers[HEADER_ORGANIZATIONID] = organizationId } - // kilocode_change end const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/chat-credentials`, { headers }) From bd7f7f3c4e65d128e1d85cc1d0e532fb0ff45842 Mon Sep 17 00:00:00 2001 From: Ligia Zanchet Date: Thu, 2 Apr 2026 21:33:36 +0200 Subject: [PATCH 21/83] fix(kilo-docs): add VideoEmbed component and video markdoc tag --- packages/kilo-docs/components/VideoEmbed.tsx | 92 +++++++++++++++++++ packages/kilo-docs/components/index.js | 1 + packages/kilo-docs/markdoc/tags/index.ts | 1 + .../kilo-docs/markdoc/tags/video.markdoc.ts | 21 +++++ 4 files changed, 115 insertions(+) create mode 100644 packages/kilo-docs/components/VideoEmbed.tsx create mode 100644 packages/kilo-docs/markdoc/tags/video.markdoc.ts diff --git a/packages/kilo-docs/components/VideoEmbed.tsx b/packages/kilo-docs/components/VideoEmbed.tsx new file mode 100644 index 00000000000..8b507d6a09e --- /dev/null +++ b/packages/kilo-docs/components/VideoEmbed.tsx @@ -0,0 +1,92 @@ +import React from "react" + +interface VideoEmbedProps { + url: string + title?: string + caption?: string +} + +function extractVideoId(url: string): string | null { + const patterns = [ + /(?:youtube\.com\/watch\?v=)([^&\s]+)/, + /(?:youtube\.com\/embed\/)([^?\s]+)/, + /(?:youtu\.be\/)([^?\s]+)/, + /(?:youtube\.com\/v\/)([^?\s]+)/, + ] + + for (const pattern of patterns) { + const match = url.match(pattern) + if (match) { + return match[1] ?? null + } + } + + return null +} + +export function VideoEmbed({ url, title = "Video", caption }: VideoEmbedProps) { + const videoId = extractVideoId(url) + + if (!videoId) { + return ( +
+ Invalid YouTube URL: {url} +
+ ) + } + + return ( +
+
+