mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
feat: merge opencode v1.2.19
This commit is contained in:
@@ -496,6 +496,7 @@
|
|||||||
"@solid-primitives/resize-observer": "2.1.3",
|
"@solid-primitives/resize-observer": "2.1.3",
|
||||||
"@solidjs/meta": "catalog:",
|
"@solidjs/meta": "catalog:",
|
||||||
"@solidjs/router": "catalog:",
|
"@solidjs/router": "catalog:",
|
||||||
|
"@typescript/native-preview": "catalog:",
|
||||||
"dompurify": "3.3.1",
|
"dompurify": "3.3.1",
|
||||||
"fuzzysort": "catalog:",
|
"fuzzysort": "catalog:",
|
||||||
"katex": "0.16.27",
|
"katex": "0.16.27",
|
||||||
|
|||||||
@@ -136,7 +136,8 @@ export const dict = {
|
|||||||
"provider.connect.oauth.code.invalid": "رمز التفويض غير صالح",
|
"provider.connect.oauth.code.invalid": "رمز التفويض غير صالح",
|
||||||
"provider.connect.oauth.auto.visit.prefix": "قم بزيارة ",
|
"provider.connect.oauth.auto.visit.prefix": "قم بزيارة ",
|
||||||
"provider.connect.oauth.auto.visit.link": "هذا الرابط",
|
"provider.connect.oauth.auto.visit.link": "هذا الرابط",
|
||||||
"provider.connect.oauth.auto.visit.suffix": " وأدخل الرمز أدناه لتوصيل حسابك واستخدام نماذج {{provider}} في Kilo.",
|
"provider.connect.oauth.auto.visit.suffix":
|
||||||
|
" وأدخل الرمز أدناه لتوصيل حسابك واستخدام نماذج {{provider}} في Kilo.",
|
||||||
"provider.connect.oauth.auto.confirmationCode": "رمز التأكيد",
|
"provider.connect.oauth.auto.confirmationCode": "رمز التأكيد",
|
||||||
"provider.connect.toast.connected.title": "تم توصيل {{provider}}",
|
"provider.connect.toast.connected.title": "تم توصيل {{provider}}",
|
||||||
"provider.connect.toast.connected.description": "نماذج {{provider}} متاحة الآن للاستخدام.",
|
"provider.connect.toast.connected.description": "نماذج {{provider}} متاحة الآن للاستخدام.",
|
||||||
|
|||||||
@@ -389,7 +389,8 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.description": "Une erreur s'est produite lors de l'annulation du partage de la session",
|
"toast.session.unshare.failed.description": "Une erreur s'est produite lors de l'annulation du partage de la session",
|
||||||
"toast.session.listFailed.title": "Échec du chargement des sessions pour {{project}}",
|
"toast.session.listFailed.title": "Échec du chargement des sessions pour {{project}}",
|
||||||
"toast.update.title": "Mise à jour disponible",
|
"toast.update.title": "Mise à jour disponible",
|
||||||
"toast.update.description": "Une nouvelle version d'Kilo ({{version}}) est maintenant disponible pour installation.",
|
"toast.update.description":
|
||||||
|
"Une nouvelle version d'Kilo ({{version}}) est maintenant disponible pour installation.",
|
||||||
"toast.update.action.installRestart": "Installer et redémarrer",
|
"toast.update.action.installRestart": "Installer et redémarrer",
|
||||||
"toast.update.action.notYet": "Pas encore",
|
"toast.update.action.notYet": "Pas encore",
|
||||||
"error.page.title": "Quelque chose s'est mal passé",
|
"error.page.title": "Quelque chose s'est mal passé",
|
||||||
@@ -523,7 +524,8 @@ export const dict = {
|
|||||||
"sidebar.workspaces.enable": "Activer les espaces de travail",
|
"sidebar.workspaces.enable": "Activer les espaces de travail",
|
||||||
"sidebar.workspaces.disable": "Désactiver les espaces de travail",
|
"sidebar.workspaces.disable": "Désactiver les espaces de travail",
|
||||||
"sidebar.gettingStarted.title": "Commencer",
|
"sidebar.gettingStarted.title": "Commencer",
|
||||||
"sidebar.gettingStarted.line1": "Kilo inclut des modèles gratuits pour que vous puissiez commencer immédiatement.",
|
"sidebar.gettingStarted.line1":
|
||||||
|
"Kilo inclut des modèles gratuits pour que vous puissiez commencer immédiatement.",
|
||||||
"sidebar.gettingStarted.line2":
|
"sidebar.gettingStarted.line2":
|
||||||
"Connectez n'importe quel fournisseur pour utiliser des modèles, y compris Claude, GPT, Gemini etc.",
|
"Connectez n'importe quel fournisseur pour utiliser des modèles, y compris Claude, GPT, Gemini etc.",
|
||||||
"sidebar.project.recentSessions": "Sessions récentes",
|
"sidebar.project.recentSessions": "Sessions récentes",
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ export const dict = {
|
|||||||
"provider.connect.oauth.code.invalid": "รหัสการอนุญาตไม่ถูกต้อง",
|
"provider.connect.oauth.code.invalid": "รหัสการอนุญาตไม่ถูกต้อง",
|
||||||
"provider.connect.oauth.auto.visit.prefix": "เยี่ยมชม ",
|
"provider.connect.oauth.auto.visit.prefix": "เยี่ยมชม ",
|
||||||
"provider.connect.oauth.auto.visit.link": "ลิงก์นี้",
|
"provider.connect.oauth.auto.visit.link": "ลิงก์นี้",
|
||||||
"provider.connect.oauth.auto.visit.suffix": " และป้อนรหัสด้านล่างเพื่อเชื่อมต่อบัญชีและใช้โมเดล {{provider}} ใน Kilo",
|
"provider.connect.oauth.auto.visit.suffix":
|
||||||
|
" และป้อนรหัสด้านล่างเพื่อเชื่อมต่อบัญชีและใช้โมเดล {{provider}} ใน Kilo",
|
||||||
"provider.connect.oauth.auto.confirmationCode": "รหัสยืนยัน",
|
"provider.connect.oauth.auto.confirmationCode": "รหัสยืนยัน",
|
||||||
"provider.connect.toast.connected.title": "{{provider}} ที่เชื่อมต่อแล้ว",
|
"provider.connect.toast.connected.title": "{{provider}} ที่เชื่อมต่อแล้ว",
|
||||||
"provider.connect.toast.connected.description": "โมเดล {{provider}} พร้อมใช้งานแล้ว",
|
"provider.connect.toast.connected.description": "โมเดล {{provider}} พร้อมใช้งานแล้ว",
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ export const dict = {
|
|||||||
"provider.connect.opencodeZen.visit.prefix": "",
|
"provider.connect.opencodeZen.visit.prefix": "",
|
||||||
"provider.connect.opencodeZen.visit.link": "opencode.ai/zen",
|
"provider.connect.opencodeZen.visit.link": "opencode.ai/zen",
|
||||||
"provider.connect.opencodeZen.visit.suffix": " adresini ziyaret ederek API anahtarınızı alın.",
|
"provider.connect.opencodeZen.visit.suffix": " adresini ziyaret ederek API anahtarınızı alın.",
|
||||||
"provider.connect.oauth.code.visit.prefix": "Hesabınızı bağlamak ve Kilo'da {{provider}} modellerini kullanmak için ",
|
"provider.connect.oauth.code.visit.prefix":
|
||||||
|
"Hesabınızı bağlamak ve Kilo'da {{provider}} modellerini kullanmak için ",
|
||||||
"provider.connect.oauth.code.visit.link": "bu bağlantıya",
|
"provider.connect.oauth.code.visit.link": "bu bağlantıya",
|
||||||
"provider.connect.oauth.code.visit.suffix": " tıklayarak yetkilendirme kodunuzu alın.",
|
"provider.connect.oauth.code.visit.suffix": " tıklayarak yetkilendirme kodunuzu alın.",
|
||||||
"provider.connect.oauth.code.label": "{{method}} yetkilendirme kodu",
|
"provider.connect.oauth.code.label": "{{method}} yetkilendirme kodu",
|
||||||
|
|||||||
@@ -149,7 +149,8 @@ export const dict = {
|
|||||||
"provider.connect.oauth.code.invalid": "授權碼無效",
|
"provider.connect.oauth.code.invalid": "授權碼無效",
|
||||||
"provider.connect.oauth.auto.visit.prefix": "造訪 ",
|
"provider.connect.oauth.auto.visit.prefix": "造訪 ",
|
||||||
"provider.connect.oauth.auto.visit.link": "此連結",
|
"provider.connect.oauth.auto.visit.link": "此連結",
|
||||||
"provider.connect.oauth.auto.visit.suffix": " 並輸入以下程式碼,以連線你的帳戶並在 Kilo 中使用 {{provider}} 模型。",
|
"provider.connect.oauth.auto.visit.suffix":
|
||||||
|
" 並輸入以下程式碼,以連線你的帳戶並在 Kilo 中使用 {{provider}} 模型。",
|
||||||
"provider.connect.oauth.auto.confirmationCode": "確認碼",
|
"provider.connect.oauth.auto.confirmationCode": "確認碼",
|
||||||
"provider.connect.toast.connected.title": "{{provider}} 已連線",
|
"provider.connect.toast.connected.title": "{{provider}} 已連線",
|
||||||
"provider.connect.toast.connected.description": "現在可以使用 {{provider}} 模型了。",
|
"provider.connect.toast.connected.description": "現在可以使用 {{provider}} 模型了。",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
|||||||
import { Button } from "@opencode-ai/ui/button"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
import { Icon } from "@opencode-ai/ui/icon"
|
import { Icon } from "@opencode-ai/ui/icon"
|
||||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||||
import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
|
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||||
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
|
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
|
||||||
import { Dialog } from "@opencode-ai/ui/dialog"
|
import { Dialog } from "@opencode-ai/ui/dialog"
|
||||||
import { getFilename } from "@opencode-ai/util/path"
|
import { getFilename } from "@opencode-ai/util/path"
|
||||||
@@ -1942,20 +1942,14 @@ export default function Layout(props: ParentProps) {
|
|||||||
fallback={
|
fallback={
|
||||||
<>
|
<>
|
||||||
<div class="shrink-0 py-4 px-3">
|
<div class="shrink-0 py-4 px-3">
|
||||||
<TooltipKeybind
|
<Button
|
||||||
title={language.t("command.session.new")}
|
size="large"
|
||||||
keybind={command.keybind("session.new")}
|
icon="plus-small"
|
||||||
placement="top"
|
class="w-full"
|
||||||
|
onClick={() => navigateWithSidebarReset(`/${base64Encode(p.worktree)}/session`)}
|
||||||
>
|
>
|
||||||
<Button
|
{language.t("command.session.new")}
|
||||||
size="large"
|
</Button>
|
||||||
icon="plus-small"
|
|
||||||
class="w-full"
|
|
||||||
onClick={() => navigateWithSidebarReset(`/${base64Encode(p.worktree)}/session`)}
|
|
||||||
>
|
|
||||||
{language.t("command.session.new")}
|
|
||||||
</Button>
|
|
||||||
</TooltipKeybind>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 min-h-0">
|
<div class="flex-1 min-h-0">
|
||||||
<LocalWorkspace
|
<LocalWorkspace
|
||||||
@@ -1970,15 +1964,9 @@ export default function Layout(props: ParentProps) {
|
|||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
<div class="shrink-0 py-4 px-3">
|
<div class="shrink-0 py-4 px-3">
|
||||||
<TooltipKeybind
|
<Button size="large" icon="plus-small" class="w-full" onClick={() => createWorkspace(p)}>
|
||||||
title={language.t("workspace.new")}
|
{language.t("workspace.new")}
|
||||||
keybind={command.keybind("workspace.new")}
|
</Button>
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<Button size="large" icon="plus-small" class="w-full" onClick={() => createWorkspace(p)}>
|
|
||||||
{language.t("workspace.new")}
|
|
||||||
</Button>
|
|
||||||
</TooltipKeybind>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="relative flex-1 min-h-0">
|
<div class="relative flex-1 min-h-0">
|
||||||
<DragDropProvider
|
<DragDropProvider
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ export const ProjectIcon = (props: { project: LocalProject; class?: string; noti
|
|||||||
<div class="size-full rounded overflow-clip">
|
<div class="size-full rounded overflow-clip">
|
||||||
<Avatar
|
<Avatar
|
||||||
fallback={name()}
|
fallback={name()}
|
||||||
src={props.project.id === KILO_PROJECT_ID ? "https://kilo.ai/favicon.svg" : props.project.icon?.override}
|
src={
|
||||||
|
props.project.id === KILO_PROJECT_ID ? "https://kilo.ai/favicon.svg" : props.project.icon?.override
|
||||||
|
}
|
||||||
{...getAvatarColors(props.project.icon?.color)}
|
{...getAvatarColors(props.project.icon?.color)}
|
||||||
class="size-full rounded"
|
class="size-full rounded"
|
||||||
classList={{ "badge-mask": notify() }}
|
classList={{ "badge-mask": notify() }}
|
||||||
|
|||||||
@@ -822,6 +822,7 @@ export default function Page() {
|
|||||||
showAllFiles,
|
showAllFiles,
|
||||||
tabForPath: file.tab,
|
tabForPath: file.tab,
|
||||||
openTab: tabs().open,
|
openTab: tabs().open,
|
||||||
|
setActive: tabs().setActive,
|
||||||
loadFile: file.load,
|
loadFile: file.load,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,13 @@ describe("createOpenReviewFile", () => {
|
|||||||
return `file://${path}`
|
return `file://${path}`
|
||||||
},
|
},
|
||||||
openTab: (tab) => calls.push(`open:${tab}`),
|
openTab: (tab) => calls.push(`open:${tab}`),
|
||||||
|
setActive: (tab) => calls.push(`active:${tab}`),
|
||||||
loadFile: (path) => calls.push(`load:${path}`),
|
loadFile: (path) => calls.push(`load:${path}`),
|
||||||
})
|
})
|
||||||
|
|
||||||
openReviewFile("src/a.ts")
|
openReviewFile("src/a.ts")
|
||||||
|
|
||||||
expect(calls).toEqual(["show", "load:src/a.ts", "tab:src/a.ts", "open:file://src/a.ts"])
|
expect(calls).toEqual(["show", "load:src/a.ts", "tab:src/a.ts", "open:file://src/a.ts", "active:file://src/a.ts"])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -24,15 +24,20 @@ export const createOpenReviewFile = (input: {
|
|||||||
showAllFiles: () => void
|
showAllFiles: () => void
|
||||||
tabForPath: (path: string) => string
|
tabForPath: (path: string) => string
|
||||||
openTab: (tab: string) => void
|
openTab: (tab: string) => void
|
||||||
|
setActive: (tab: string) => void
|
||||||
loadFile: (path: string) => any | Promise<void>
|
loadFile: (path: string) => any | Promise<void>
|
||||||
}) => {
|
}) => {
|
||||||
return (path: string) => {
|
return (path: string) => {
|
||||||
batch(() => {
|
batch(() => {
|
||||||
input.showAllFiles()
|
input.showAllFiles()
|
||||||
const maybePromise = input.loadFile(path)
|
const maybePromise = input.loadFile(path)
|
||||||
const openTab = () => input.openTab(input.tabForPath(path))
|
const open = () => {
|
||||||
if (maybePromise instanceof Promise) maybePromise.then(openTab)
|
const tab = input.tabForPath(path)
|
||||||
else openTab()
|
input.openTab(tab)
|
||||||
|
input.setActive(tab)
|
||||||
|
}
|
||||||
|
if (maybePromise instanceof Promise) maybePromise.then(open)
|
||||||
|
else open()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { For, createEffect, createMemo, on, onCleanup, Show, startTransition, Index, type JSX } from "solid-js"
|
import { For, createEffect, createMemo, on, onCleanup, Show, Index, type JSX } from "solid-js"
|
||||||
import { createStore, produce } from "solid-js/store"
|
import { createStore, produce } from "solid-js/store"
|
||||||
import { useNavigate, useParams } from "@solidjs/router"
|
import { useNavigate, useParams } from "@solidjs/router"
|
||||||
import { Button } from "@opencode-ai/ui/button"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
@@ -160,7 +160,7 @@ function createTimelineStaging(input: TimelineStageInput) {
|
|||||||
}
|
}
|
||||||
const currentTotal = input.messages().length
|
const currentTotal = input.messages().length
|
||||||
count = Math.min(currentTotal, count + input.config.batch)
|
count = Math.min(currentTotal, count + input.config.batch)
|
||||||
startTransition(() => setState("count", count))
|
setState("count", count)
|
||||||
if (count >= currentTotal) {
|
if (count >= currentTotal) {
|
||||||
setState({ completedSession: sessionKey, activeSession: "" })
|
setState({ completedSession: sessionKey, activeSession: "" })
|
||||||
frame = undefined
|
frame = undefined
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export const useSessionHashScroll = (input: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const scrollToMessage = (message: UserMessage, behavior: ScrollBehavior = "smooth") => {
|
const scrollToMessage = (message: UserMessage, behavior: ScrollBehavior = "smooth") => {
|
||||||
|
console.log({ message, behavior })
|
||||||
if (input.currentMessageId() !== message.id) input.setActiveMessage(message)
|
if (input.currentMessageId() !== message.id) input.setActiveMessage(message)
|
||||||
|
|
||||||
const index = messageIndex().get(message.id) ?? -1
|
const index = messageIndex().get(message.id) ?? -1
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ export const dict = {
|
|||||||
"desktop.menu.help.shareFeedback": "Feedback teilen",
|
"desktop.menu.help.shareFeedback": "Feedback teilen",
|
||||||
"desktop.menu.help.reportBug": "Einen Fehler melden",
|
"desktop.menu.help.reportBug": "Einen Fehler melden",
|
||||||
"desktop.cli.error.unsupportedPlatform": "Die CLI-Installation wird nur unter macOS und Linux unterstützt.",
|
"desktop.cli.error.unsupportedPlatform": "Die CLI-Installation wird nur unter macOS und Linux unterstützt.",
|
||||||
"desktop.cli.error.sidecarMissing": "Das Kilo CLI-Binary fehlt. Versuchen Sie, die Desktop-App neu zu installieren.",
|
"desktop.cli.error.sidecarMissing":
|
||||||
|
"Das Kilo CLI-Binary fehlt. Versuchen Sie, die Desktop-App neu zu installieren.",
|
||||||
"desktop.cli.error.scriptWriteFailed": "Das CLI-Installationsskript konnte nicht vorbereitet werden.",
|
"desktop.cli.error.scriptWriteFailed": "Das CLI-Installationsskript konnte nicht vorbereitet werden.",
|
||||||
"desktop.cli.error.scriptPermissionFailed": "Das CLI-Installationsskript konnte nicht ausführbar gemacht werden.",
|
"desktop.cli.error.scriptPermissionFailed": "Das CLI-Installationsskript konnte nicht ausführbar gemacht werden.",
|
||||||
"desktop.cli.error.scriptRunFailed": "Das CLI-Installationsskript konnte nicht ausgeführt werden.",
|
"desktop.cli.error.scriptRunFailed": "Das CLI-Installationsskript konnte nicht ausgeführt werden.",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "kilo"
|
id = "kilo"
|
||||||
name = "Kilo"
|
name = "Kilo"
|
||||||
description = "The open source coding agent."
|
description = "The open source coding agent."
|
||||||
version = "1.2.18"
|
version = "1.2.19"
|
||||||
schema_version = 1
|
schema_version = 1
|
||||||
authors = ["Anomaly"]
|
authors = ["Anomaly"]
|
||||||
repository = "https://github.com/Kilo-Org/kilocode"
|
repository = "https://github.com/Kilo-Org/kilocode"
|
||||||
@@ -11,26 +11,26 @@ name = "Kilo"
|
|||||||
icon = "./icons/opencode.svg"
|
icon = "./icons/opencode.svg"
|
||||||
|
|
||||||
[agent_servers.opencode.targets.darwin-aarch64]
|
[agent_servers.opencode.targets.darwin-aarch64]
|
||||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.18/opencode-darwin-arm64.zip"
|
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.19/opencode-darwin-arm64.zip"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.darwin-x86_64]
|
[agent_servers.opencode.targets.darwin-x86_64]
|
||||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.18/opencode-darwin-x64.zip"
|
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.19/opencode-darwin-x64.zip"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.linux-aarch64]
|
[agent_servers.opencode.targets.linux-aarch64]
|
||||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.18/opencode-linux-arm64.tar.gz"
|
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.19/opencode-linux-arm64.tar.gz"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.linux-x86_64]
|
[agent_servers.opencode.targets.linux-x86_64]
|
||||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.18/opencode-linux-x64.tar.gz"
|
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.19/opencode-linux-x64.tar.gz"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.windows-x86_64]
|
[agent_servers.opencode.targets.windows-x86_64]
|
||||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.18/opencode-windows-x64.zip"
|
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.19/opencode-windows-x64.zip"
|
||||||
cmd = "./opencode.exe"
|
cmd = "./opencode.exe"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Kilo Code supports accessing models through [Unbound](https://getunbound.ai/), a
|
|||||||
## Creating an Account
|
## Creating an Account
|
||||||
|
|
||||||
1. **Sign Up/Sign In:** Go to the [Unbound gateway](https://gateway.getunbound.ai). Create an account or sign in.
|
1. **Sign Up/Sign In:** Go to the [Unbound gateway](https://gateway.getunbound.ai). Create an account or sign in.
|
||||||
2. **Create an Application:** Go to the [Applications](https://gateway.getunbound.ai/ai-gateway-applications) page and hit the "Create Application" button.
|
2. **Create an Application:** Go to the [Applications](https://gateway.getunbound.ai/connect) page and select "Kilo Code".
|
||||||
3. **Copy the API Key:** Copy the API key to your clipboard.
|
3. **Copy the API Key:** Copy the API key to your clipboard.
|
||||||
|
|
||||||
## Supported Models
|
## Supported Models
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { pathToFileURL } from "bun"
|
import { pathToFileURL } from "bun"
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
|
import { Hash } from "../util/hash"
|
||||||
import { ACPSessionManager } from "./session"
|
import { ACPSessionManager } from "./session"
|
||||||
import type { ACPConfig } from "./types"
|
import type { ACPConfig } from "./types"
|
||||||
import { Provider } from "../provider/provider"
|
import { Provider } from "../provider/provider"
|
||||||
@@ -283,7 +284,7 @@ export namespace ACP {
|
|||||||
const output = this.bashOutput(part)
|
const output = this.bashOutput(part)
|
||||||
const content: ToolCallContent[] = []
|
const content: ToolCallContent[] = []
|
||||||
if (output) {
|
if (output) {
|
||||||
const hash = String(Bun.hash(output))
|
const hash = Hash.fast(output)
|
||||||
if (part.tool === "bash") {
|
if (part.tool === "bash") {
|
||||||
if (this.bashSnapshots.get(part.callID) === hash) {
|
if (this.bashSnapshots.get(part.callID) === hash) {
|
||||||
await this.connection
|
await this.connection
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { Instance } from "../../project/instance"
|
|||||||
import type { Hooks } from "@kilocode/plugin"
|
import type { Hooks } from "@kilocode/plugin"
|
||||||
import { Process } from "../../util/process"
|
import { Process } from "../../util/process"
|
||||||
import { text } from "node:stream/consumers"
|
import { text } from "node:stream/consumers"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
type PluginAuth = NonNullable<Hooks["auth"]>
|
type PluginAuth = NonNullable<Hooks["auth"]>
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string,
|
|||||||
const method = plugin.auth.methods[index]
|
const method = plugin.auth.methods[index]
|
||||||
|
|
||||||
// Handle prompts for all auth types
|
// Handle prompts for all auth types
|
||||||
await Bun.sleep(10)
|
await sleep(10)
|
||||||
const inputs: Record<string, string> = {}
|
const inputs: Record<string, string> = {}
|
||||||
if (method.prompts) {
|
if (method.prompts) {
|
||||||
for (const prompt of method.prompts) {
|
for (const prompt of method.prompts) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { bootstrap } from "../../bootstrap"
|
|||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
import { Log } from "../../../util/log"
|
import { Log } from "../../../util/log"
|
||||||
import { EOL } from "os"
|
import { EOL } from "os"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
export const LSPCommand = cmd({
|
export const LSPCommand = cmd({
|
||||||
command: "lsp",
|
command: "lsp",
|
||||||
@@ -19,7 +20,7 @@ const DiagnosticsCommand = cmd({
|
|||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
await LSP.touchFile(args.file, true)
|
await LSP.touchFile(args.file, true)
|
||||||
await Bun.sleep(1000)
|
await sleep(1000)
|
||||||
process.stdout.write(JSON.stringify(await LSP.diagnostics(), null, 2) + EOL)
|
process.stdout.write(JSON.stringify(await LSP.diagnostics(), null, 2) + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { Bus } from "../../bus"
|
|||||||
import { MessageV2 } from "../../session/message-v2"
|
import { MessageV2 } from "../../session/message-v2"
|
||||||
import { SessionPrompt } from "@/session/prompt"
|
import { SessionPrompt } from "@/session/prompt"
|
||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
type GitHubAuthor = {
|
type GitHubAuthor = {
|
||||||
login: string
|
login: string
|
||||||
@@ -353,7 +354,7 @@ export const GithubInstallCommand = cmd({
|
|||||||
}
|
}
|
||||||
|
|
||||||
retries++
|
retries++
|
||||||
await Bun.sleep(1000)
|
await sleep(1000)
|
||||||
} while (true)
|
} while (true)
|
||||||
|
|
||||||
s.stop("Installed GitHub app")
|
s.stop("Installed GitHub app")
|
||||||
@@ -1384,7 +1385,7 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (retries > 0) {
|
if (retries > 0) {
|
||||||
console.log(`Retrying after ${delayMs}ms...`)
|
console.log(`Retrying after ${delayMs}ms...`)
|
||||||
await Bun.sleep(delayMs)
|
await sleep(delayMs)
|
||||||
return withRetry(fn, retries - 1, delayMs)
|
return withRetry(fn, retries - 1, delayMs)
|
||||||
}
|
}
|
||||||
throw e
|
throw e
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { cmd } from "./cmd"
|
|||||||
import { Flag } from "../../flag/flag"
|
import { Flag } from "../../flag/flag"
|
||||||
import { bootstrap } from "../bootstrap"
|
import { bootstrap } from "../bootstrap"
|
||||||
import { EOL } from "os"
|
import { EOL } from "os"
|
||||||
|
import { text as streamText } from "node:stream/consumers"
|
||||||
import { Filesystem } from "../../util/filesystem"
|
import { Filesystem } from "../../util/filesystem"
|
||||||
import { createKiloClient, type Message, type KiloClient, type ToolPart } from "@kilocode/sdk/v2"
|
import { createKiloClient, type Message, type KiloClient, type ToolPart } from "@kilocode/sdk/v2"
|
||||||
import { Server } from "../../server/server"
|
import { Server } from "../../server/server"
|
||||||
@@ -351,7 +352,7 @@ export const RunCommand = cmd({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process.stdin.isTTY) message += "\n" + (await Bun.stdin.text())
|
if (!process.stdin.isTTY) message += "\n" + (await streamText(process.stdin))
|
||||||
|
|
||||||
if (message.trim().length === 0 && !args.command) {
|
if (message.trim().length === 0 && !args.command) {
|
||||||
UI.error("You must provide a message or a command")
|
UI.error("You must provide a message or a command")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { tui } from "./app"
|
|||||||
import { Rpc } from "@/util/rpc"
|
import { Rpc } from "@/util/rpc"
|
||||||
import { type rpc } from "./worker"
|
import { type rpc } from "./worker"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
import { text as streamText } from "node:stream/consumers"
|
||||||
import { fileURLToPath } from "url"
|
import { fileURLToPath } from "url"
|
||||||
import { UI } from "@/cli/ui"
|
import { UI } from "@/cli/ui"
|
||||||
import { Log } from "@/util/log"
|
import { Log } from "@/util/log"
|
||||||
@@ -55,7 +56,7 @@ async function target() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function input(value?: string) {
|
async function input(value?: string) {
|
||||||
const piped = process.stdin.isTTY ? undefined : await Bun.stdin.text()
|
const piped = process.stdin.isTTY ? undefined : await streamText(process.stdin)
|
||||||
if (!value) return piped
|
if (!value) return piped
|
||||||
if (!piped) return value
|
if (!piped) return value
|
||||||
return piped + "\n" + value
|
return piped + "\n" + value
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { GlobalBus } from "@/bus/global"
|
|||||||
import { createKiloClient, type Event } from "@kilocode/sdk/v2"
|
import { createKiloClient, type Event } from "@kilocode/sdk/v2"
|
||||||
import type { BunWebSocketData } from "hono/bun"
|
import type { BunWebSocketData } from "hono/bun"
|
||||||
import { Flag } from "@/flag/flag"
|
import { Flag } from "@/flag/flag"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
await Log.init({
|
await Log.init({
|
||||||
print: process.argv.includes("--print-logs"),
|
print: process.argv.includes("--print-logs"),
|
||||||
@@ -75,7 +76,7 @@ const startEventStream = (directory: string) => {
|
|||||||
).catch(() => undefined)
|
).catch(() => undefined)
|
||||||
|
|
||||||
if (!events) {
|
if (!events) {
|
||||||
await Bun.sleep(250)
|
await sleep(250)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +85,7 @@ const startEventStream = (directory: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!signal.aborted) {
|
if (!signal.aborted) {
|
||||||
await Bun.sleep(250)
|
await sleep(250)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})().catch((error) => {
|
})().catch((error) => {
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ export namespace UI {
|
|||||||
|
|
||||||
export function println(...message: string[]) {
|
export function println(...message: string[]) {
|
||||||
print(...message)
|
print(...message)
|
||||||
Bun.stderr.write(EOL)
|
process.stderr.write(EOL)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function print(...message: string[]) {
|
export function print(...message: string[]) {
|
||||||
blank = false
|
blank = false
|
||||||
Bun.stderr.write(message.join(" "))
|
process.stderr.write(message.join(" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
let blank = false
|
let blank = false
|
||||||
@@ -45,7 +45,7 @@ export namespace UI {
|
|||||||
const result: string[] = []
|
const result: string[] = []
|
||||||
const reset = "\x1b[0m"
|
const reset = "\x1b[0m"
|
||||||
const left = {
|
const left = {
|
||||||
fg: Bun.color("gray", "ansi") ?? "",
|
fg: "\x1b[90m",
|
||||||
shadow: "\x1b[38;5;235m",
|
shadow: "\x1b[38;5;235m",
|
||||||
bg: "\x1b[48;5;235m",
|
bg: "\x1b[48;5;235m",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1375,7 +1375,7 @@ export namespace Config {
|
|||||||
if (!parsed.data.$schema && isFile) {
|
if (!parsed.data.$schema && isFile) {
|
||||||
parsed.data.$schema = "https://app.kilo.ai/config.json" // kilocode_change
|
parsed.data.$schema = "https://app.kilo.ai/config.json" // kilocode_change
|
||||||
const updated = original.replace(/^\s*\{/, '{\n "$schema": "https://app.kilo.ai/config.json",') // kilocode_change
|
const updated = original.replace(/^\s*\{/, '{\n "$schema": "https://app.kilo.ai/config.json",') // kilocode_change
|
||||||
await Bun.write(options.path, updated).catch(() => {})
|
await Filesystem.write(options.path, updated).catch(() => {})
|
||||||
}
|
}
|
||||||
const data = parsed.data
|
const data = parsed.data
|
||||||
if (data.plugin && isFile) {
|
if (data.plugin && isFile) {
|
||||||
@@ -1571,3 +1571,5 @@ export namespace Config {
|
|||||||
return state().then((x) => x.directories)
|
return state().then((x) => x.directories)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Filesystem.write
|
||||||
|
Filesystem.write
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export async function migrateTuiConfig(input: MigrateInput) {
|
|||||||
if (extracted.keybinds !== undefined) payload.keybinds = extracted.keybinds
|
if (extracted.keybinds !== undefined) payload.keybinds = extracted.keybinds
|
||||||
if (tui) Object.assign(payload, tui)
|
if (tui) Object.assign(payload, tui)
|
||||||
|
|
||||||
const wrote = await Bun.write(target, JSON.stringify(payload, null, 2))
|
const wrote = await Filesystem.write(target, JSON.stringify(payload, null, 2))
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
log.warn("failed to write tui migration target", { from: file, to: target, error })
|
log.warn("failed to write tui migration target", { from: file, to: target, error })
|
||||||
@@ -104,7 +104,7 @@ async function backupAndStripLegacy(file: string, source: string) {
|
|||||||
const hasBackup = await Filesystem.exists(backup)
|
const hasBackup = await Filesystem.exists(backup)
|
||||||
const backed = hasBackup
|
const backed = hasBackup
|
||||||
? true
|
? true
|
||||||
: await Bun.write(backup, source)
|
: await Filesystem.write(backup, source)
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
log.warn("failed to backup source config during tui migration", { path: file, backup, error })
|
log.warn("failed to backup source config during tui migration", { path: file, backup, error })
|
||||||
@@ -123,7 +123,7 @@ async function backupAndStripLegacy(file: string, source: string) {
|
|||||||
return applyEdits(acc, edits)
|
return applyEdits(acc, edits)
|
||||||
}, source)
|
}, source)
|
||||||
|
|
||||||
return Bun.write(file, text)
|
return Filesystem.write(file, text)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
log.info("stripped tui keys from server config", { path: file, backup })
|
log.info("stripped tui keys from server config", { path: file, backup })
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { createConnection } from "net"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH } from "./oauth-provider"
|
import { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH } from "./oauth-provider"
|
||||||
|
|
||||||
@@ -166,21 +167,12 @@ export namespace McpOAuthCallback {
|
|||||||
|
|
||||||
export async function isPortInUse(): Promise<boolean> {
|
export async function isPortInUse(): Promise<boolean> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
Bun.connect({
|
const socket = createConnection(OAUTH_CALLBACK_PORT, "127.0.0.1")
|
||||||
hostname: "127.0.0.1",
|
socket.on("connect", () => {
|
||||||
port: OAUTH_CALLBACK_PORT,
|
socket.destroy()
|
||||||
socket: {
|
resolve(true)
|
||||||
open(socket) {
|
})
|
||||||
socket.end()
|
socket.on("error", () => {
|
||||||
resolve(true)
|
|
||||||
},
|
|
||||||
error() {
|
|
||||||
resolve(false)
|
|
||||||
},
|
|
||||||
data() {},
|
|
||||||
close() {},
|
|
||||||
},
|
|
||||||
}).catch(() => {
|
|
||||||
resolve(false)
|
resolve(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Installation } from "../installation"
|
|||||||
import { Auth, OAUTH_DUMMY_KEY } from "../auth"
|
import { Auth, OAUTH_DUMMY_KEY } from "../auth"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
import { ProviderTransform } from "@/provider/transform"
|
import { ProviderTransform } from "@/provider/transform"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
const log = Log.create({ service: "plugin.codex" })
|
const log = Log.create({ service: "plugin.codex" })
|
||||||
|
|
||||||
@@ -367,6 +368,7 @@ export async function CodexAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|||||||
"gpt-5.1-codex-max",
|
"gpt-5.1-codex-max",
|
||||||
"gpt-5.1-codex-mini",
|
"gpt-5.1-codex-mini",
|
||||||
"gpt-5.2",
|
"gpt-5.2",
|
||||||
|
"gpt-5.4",
|
||||||
"gpt-5.2-codex",
|
"gpt-5.2-codex",
|
||||||
"gpt-5.3-codex",
|
"gpt-5.3-codex",
|
||||||
"gpt-5.1-codex",
|
"gpt-5.1-codex",
|
||||||
@@ -608,7 +610,7 @@ export async function CodexAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|||||||
return { type: "failed" as const }
|
return { type: "failed" as const }
|
||||||
}
|
}
|
||||||
|
|
||||||
await Bun.sleep(interval + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
await sleep(interval + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Hooks, PluginInput } from "@kilocode/plugin"
|
import type { Hooks, PluginInput } from "@kilocode/plugin"
|
||||||
import { Installation } from "@/installation"
|
import { Installation } from "@/installation"
|
||||||
import { iife } from "@/util/iife"
|
import { iife } from "@/util/iife"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
const CLIENT_ID = "Ov23li8tweQw6odWQebz"
|
const CLIENT_ID = "Ov23li8tweQw6odWQebz"
|
||||||
// Add a small safety buffer when polling to avoid hitting the server
|
// Add a small safety buffer when polling to avoid hitting the server
|
||||||
@@ -270,7 +271,7 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.error === "authorization_pending") {
|
if (data.error === "authorization_pending") {
|
||||||
await Bun.sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
await sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,13 +287,13 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|||||||
newInterval = serverInterval * 1000
|
newInterval = serverInterval * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
await Bun.sleep(newInterval + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
await sleep(newInterval + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.error) return { type: "failed" as const }
|
if (data.error) return { type: "failed" as const }
|
||||||
|
|
||||||
await Bun.sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
await sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda"
|
|||||||
import { NoSuchModelError, type Provider as SDK } from "ai"
|
import { NoSuchModelError, type Provider as SDK } from "ai"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { BunProc } from "../bun"
|
import { BunProc } from "../bun"
|
||||||
|
import { Hash } from "../util/hash"
|
||||||
import { Plugin } from "../plugin"
|
import { Plugin } from "../plugin"
|
||||||
import {
|
import {
|
||||||
ModelsDev,
|
ModelsDev,
|
||||||
@@ -816,7 +817,7 @@ export namespace Provider {
|
|||||||
const modelLoaders: {
|
const modelLoaders: {
|
||||||
[providerID: string]: CustomModelLoader
|
[providerID: string]: CustomModelLoader
|
||||||
} = {}
|
} = {}
|
||||||
const sdk = new Map<number, SDK>()
|
const sdk = new Map<string, SDK>()
|
||||||
|
|
||||||
log.info("init")
|
log.info("init")
|
||||||
|
|
||||||
@@ -1111,7 +1112,7 @@ export namespace Provider {
|
|||||||
...model.headers,
|
...model.headers,
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = Bun.hash.xxHash32(JSON.stringify({ providerID: model.providerID, npm: model.api.npm, options }))
|
const key = Hash.fast(JSON.stringify({ providerID: model.providerID, npm: model.api.npm, options }))
|
||||||
const existing = s.sdk.get(key)
|
const existing = s.sdk.get(key)
|
||||||
if (existing) return existing
|
if (existing) return existing
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { lazy } from "@/util/lazy"
|
|||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { spawn, type ChildProcess } from "child_process"
|
import { spawn, type ChildProcess } from "child_process"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
const SIGKILL_TIMEOUT_MS = 200
|
const SIGKILL_TIMEOUT_MS = 200
|
||||||
|
|
||||||
@@ -22,13 +23,13 @@ export namespace Shell {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
process.kill(-pid, "SIGTERM")
|
process.kill(-pid, "SIGTERM")
|
||||||
await Bun.sleep(SIGKILL_TIMEOUT_MS)
|
await sleep(SIGKILL_TIMEOUT_MS)
|
||||||
if (!opts?.exited?.()) {
|
if (!opts?.exited?.()) {
|
||||||
process.kill(-pid, "SIGKILL")
|
process.kill(-pid, "SIGKILL")
|
||||||
}
|
}
|
||||||
} catch (_e) {
|
} catch (_e) {
|
||||||
proc.kill("SIGTERM")
|
proc.kill("SIGTERM")
|
||||||
await Bun.sleep(SIGKILL_TIMEOUT_MS)
|
await sleep(SIGKILL_TIMEOUT_MS)
|
||||||
if (!opts?.exited?.()) {
|
if (!opts?.exited?.()) {
|
||||||
proc.kill("SIGKILL")
|
proc.kill("SIGKILL")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
|
import { Filesystem } from "../util/filesystem"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
@@ -271,13 +272,12 @@ export namespace Snapshot {
|
|||||||
const target = path.join(git, "info", "exclude")
|
const target = path.join(git, "info", "exclude")
|
||||||
await fs.mkdir(path.join(git, "info"), { recursive: true })
|
await fs.mkdir(path.join(git, "info"), { recursive: true })
|
||||||
if (!file) {
|
if (!file) {
|
||||||
await Bun.write(target, "")
|
await Filesystem.write(target, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const text = await Bun.file(file)
|
const text = await Filesystem.readText(file).catch(() => "")
|
||||||
.text()
|
|
||||||
.catch(() => "")
|
await Filesystem.write(target, text)
|
||||||
await Bun.write(target, text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function excludes() {
|
async function excludes() {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { createHash } from "crypto"
|
||||||
|
|
||||||
|
export namespace Hash {
|
||||||
|
export function fast(input: string | Buffer): string {
|
||||||
|
return createHash("sha1").update(input).digest("hex")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
import os from "os"
|
import os from "os"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
import { afterAll } from "bun:test"
|
import { afterAll } from "bun:test"
|
||||||
|
|
||||||
// Set XDG env vars FIRST, before any src/ imports
|
// Set XDG env vars FIRST, before any src/ imports
|
||||||
@@ -15,7 +16,7 @@ afterAll(async () => {
|
|||||||
typeof error === "object" && error !== null && "code" in error && error.code === "EBUSY"
|
typeof error === "object" && error !== null && "code" in error && error.code === "EBUSY"
|
||||||
const rm = async (left: number): Promise<void> => {
|
const rm = async (left: number): Promise<void> => {
|
||||||
Bun.gc(true)
|
Bun.gc(true)
|
||||||
await Bun.sleep(100)
|
await sleep(100)
|
||||||
return fs.rm(dir, { recursive: true, force: true }).catch((error) => {
|
return fs.rm(dir, { recursive: true, force: true }).catch((error) => {
|
||||||
if (!busy(error)) throw error
|
if (!busy(error)) throw error
|
||||||
if (left <= 1) throw error
|
if (left <= 1) throw error
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
|
|||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Pty } from "../../src/pty"
|
import { Pty } from "../../src/pty"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
|
|
||||||
describe("pty", () => {
|
describe("pty", () => {
|
||||||
test("does not leak output when websocket objects are reused", async () => {
|
test("does not leak output when websocket objects are reused", async () => {
|
||||||
@@ -43,7 +44,7 @@ describe("pty", () => {
|
|||||||
|
|
||||||
// Output from a must never show up in b.
|
// Output from a must never show up in b.
|
||||||
Pty.write(a.id, "AAA\n")
|
Pty.write(a.id, "AAA\n")
|
||||||
await Bun.sleep(100)
|
await sleep(100)
|
||||||
|
|
||||||
expect(outB.join("")).not.toContain("AAA")
|
expect(outB.join("")).not.toContain("AAA")
|
||||||
} finally {
|
} finally {
|
||||||
@@ -88,7 +89,7 @@ describe("pty", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Pty.write(a.id, "AAA\n")
|
Pty.write(a.id, "AAA\n")
|
||||||
await Bun.sleep(100)
|
await sleep(100)
|
||||||
|
|
||||||
expect(outB.join("")).not.toContain("AAA")
|
expect(outB.join("")).not.toContain("AAA")
|
||||||
} finally {
|
} finally {
|
||||||
@@ -128,7 +129,7 @@ describe("pty", () => {
|
|||||||
ctx.connId = 2
|
ctx.connId = 2
|
||||||
|
|
||||||
Pty.write(a.id, "AAA\n")
|
Pty.write(a.id, "AAA\n")
|
||||||
await Bun.sleep(100)
|
await sleep(100)
|
||||||
|
|
||||||
expect(out.join("")).toContain("AAA")
|
expect(out.join("")).toContain("AAA")
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import type { NamedError } from "@opencode-ai/util/error"
|
import type { NamedError } from "@opencode-ai/util/error"
|
||||||
import { APICallError } from "ai"
|
import { APICallError } from "ai"
|
||||||
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
import { SessionRetry } from "../../src/session/retry"
|
import { SessionRetry } from "../../src/session/retry"
|
||||||
import { MessageV2 } from "../../src/session/message-v2"
|
import { MessageV2 } from "../../src/session/message-v2"
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ describe("session.message-v2.fromError", () => {
|
|||||||
new ReadableStream({
|
new ReadableStream({
|
||||||
async pull(controller) {
|
async pull(controller) {
|
||||||
controller.enqueue("Hello,")
|
controller.enqueue("Hello,")
|
||||||
await Bun.sleep(10000)
|
await sleep(10000)
|
||||||
controller.enqueue(" World!")
|
controller.enqueue(" World!")
|
||||||
controller.close()
|
controller.close()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -68,7 +68,8 @@
|
|||||||
"solid-js": "catalog:",
|
"solid-js": "catalog:",
|
||||||
"solid-list": "catalog:",
|
"solid-list": "catalog:",
|
||||||
"strip-ansi": "7.1.2",
|
"strip-ansi": "7.1.2",
|
||||||
"virtua": "catalog:"
|
"virtua": "catalog:",
|
||||||
|
"@typescript/native-preview": "catalog:"
|
||||||
},
|
},
|
||||||
"peerDependencies": {}
|
"peerDependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
* 3. Injecting Kilo-specific dependencies
|
* 3. Injecting Kilo-specific dependencies
|
||||||
* 4. Preserving Kilo's version number
|
* 4. Preserving Kilo's version number
|
||||||
* 5. Preserving overrides and patchedDependencies
|
* 5. Preserving overrides and patchedDependencies
|
||||||
* 6. Using "newest wins" strategy for dependency versions
|
* 6. Preserving Kilo's repository configuration
|
||||||
|
* 7. Using "newest wins" strategy for dependency versions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
@@ -333,7 +334,14 @@ export async function transformPackageJson(file: string, options: PackageJsonOpt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Handle workspaces for root package.json
|
// 6. Preserve repository (Kilo-specific, upstream doesn't have this)
|
||||||
|
const ourRepo = ourPkg.repository
|
||||||
|
if (ourRepo && JSON.stringify(pkg.repository) !== JSON.stringify(ourRepo)) {
|
||||||
|
pkg.repository = ourRepo
|
||||||
|
changes.push(`repository: preserved Kilo's repository configuration`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Handle workspaces for root package.json
|
||||||
// Kilo has removed hosted platform packages (console/*, slack, etc.)
|
// Kilo has removed hosted platform packages (console/*, slack, etc.)
|
||||||
// so we need to preserve Kilo's workspace configuration instead of taking upstream's
|
// so we need to preserve Kilo's workspace configuration instead of taking upstream's
|
||||||
const ourWorkspaces = ourPkg.workspaces as { packages?: string[]; catalog?: Record<string, string> } | undefined
|
const ourWorkspaces = ourPkg.workspaces as { packages?: string[]; catalog?: Record<string, string> } | undefined
|
||||||
@@ -534,7 +542,14 @@ export async function transformAllPackageJson(options: PackageJsonOptions = {}):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Handle workspaces for root package.json
|
// 6. Preserve repository (Kilo-specific, upstream doesn't have this)
|
||||||
|
const kiloRepo = kiloPkg.repository
|
||||||
|
if (kiloRepo && JSON.stringify(pkg.repository) !== JSON.stringify(kiloRepo)) {
|
||||||
|
pkg.repository = kiloRepo
|
||||||
|
changes.push(`repository: preserved Kilo's repository configuration`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Handle workspaces for root package.json
|
||||||
// Kilo has removed hosted platform packages (console/*, slack, etc.)
|
// Kilo has removed hosted platform packages (console/*, slack, etc.)
|
||||||
// so we need to preserve Kilo's workspace configuration instead of taking upstream's
|
// so we need to preserve Kilo's workspace configuration instead of taking upstream's
|
||||||
const kiloWorkspaces = kiloPkg.workspaces as
|
const kiloWorkspaces = kiloPkg.workspaces as
|
||||||
|
|||||||
Reference in New Issue
Block a user