Skip to content

make it possible to configure the url of the kilocode api #1193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,18 @@
"type": "string",
"default": "",
"description": "%settings.autoImportSettingsPath.description%"
},
"kilo-code.baseUrl": {
"type": "string",
"default": "https://kilocode.ai",
"description": "TEST Base URL for Kilo Code backend services (Advanced)",
"scope": "application",
"tags": [
"advanced",
"usesOnlineServices"
],
"order": 999,
"editPresentation": "multilineText"
}
}
}
Expand Down
168 changes: 168 additions & 0 deletions webview-ui/src/components/kilocode/__tests__/helpers.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"

const mockPostMessage = vi.fn()
vi.mock("@/utils/vscode", () => ({
vscode: {
postMessage: mockPostMessage,
},
}))

describe("helpers", () => {
let originalAddEventListener: typeof window.addEventListener
let mockEventListener: ReturnType<typeof vi.fn>

beforeEach(() => {
mockPostMessage.mockClear()
originalAddEventListener = window.addEventListener
mockEventListener = vi.fn()
window.addEventListener = mockEventListener
vi.resetModules()
})

afterEach(() => {
window.addEventListener = originalAddEventListener
})

describe("getKiloCodeBackendSignInUrl", () => {
it("should return sign-in URL with default base URL", async () => {
const { getKiloCodeBackendSignInUrl } = await import("../helpers")

const result = getKiloCodeBackendSignInUrl()

expect(result).toBe("https://kilocode.ai/users/sign_in?source=vscode")
expect(mockPostMessage).toHaveBeenCalledWith({
type: "getVSCodeSetting",
setting: "kilo-code.baseUrl",
})
})

it("should use cached base URL after setting is received", async () => {
const { getKiloCodeBackendSignInUrl } = await import("../helpers")

// Simulate receiving a setting update
const messageEvent = new MessageEvent("message", {
data: {
type: "vsCodeSetting",
setting: "kilo-code.baseUrl",
value: "https://custom.example.com",
},
})

// Get the event listener that was registered
expect(mockEventListener).toHaveBeenCalledWith("message", expect.any(Function))
const eventHandler = mockEventListener.mock.calls[0][1]

// Trigger the event handler
eventHandler(messageEvent)

const result = getKiloCodeBackendSignInUrl()
expect(result).toBe("https://custom.example.com/users/sign_in?source=vscode")
})

it("should fallback to default when setting value is empty", async () => {
const { getKiloCodeBackendSignInUrl } = await import("../helpers")

// Simulate receiving an empty setting value
const messageEvent = new MessageEvent("message", {
data: {
type: "vsCodeSetting",
setting: "kilo-code.baseUrl",
value: "",
},
})

const eventHandler = mockEventListener.mock.calls[0][1]
eventHandler(messageEvent)

const result = getKiloCodeBackendSignInUrl()
expect(result).toBe("https://kilocode.ai/users/sign_in?source=vscode")
})

it("should support custom uriScheme and uiKind parameters", async () => {
const { getKiloCodeBackendSignInUrl } = await import("../helpers")

const result = getKiloCodeBackendSignInUrl("custom-scheme", "Web")
expect(result).toBe("https://kilocode.ai/users/sign_in?source=web")
})
})

describe("getKiloCodeBackendSignUpUrl", () => {
it("should return sign-up URL with default base URL", async () => {
const { getKiloCodeBackendSignUpUrl } = await import("../helpers")

const result = getKiloCodeBackendSignUpUrl()

expect(result).toBe("https://kilocode.ai/users/sign_up?source=vscode")
expect(mockPostMessage).toHaveBeenCalledWith({
type: "getVSCodeSetting",
setting: "kilo-code.baseUrl",
})
})

it("should use cached base URL after setting is received", async () => {
const { getKiloCodeBackendSignUpUrl } = await import("../helpers")

// Simulate receiving a setting update
const messageEvent = new MessageEvent("message", {
data: {
type: "vsCodeSetting",
setting: "kilo-code.baseUrl",
value: "https://custom.example.com",
},
})

const eventHandler = mockEventListener.mock.calls[0][1]
eventHandler(messageEvent)

const result = getKiloCodeBackendSignUpUrl()
expect(result).toBe("https://custom.example.com/users/sign_up?source=vscode")
})

it("should support custom uriScheme and uiKind parameters", async () => {
const { getKiloCodeBackendSignUpUrl } = await import("../helpers")

const result = getKiloCodeBackendSignUpUrl("custom-scheme", "Web")
expect(result).toBe("https://kilocode.ai/users/sign_up?source=web")
})
})

describe("message event handling", () => {
it("should ignore non-vsCodeSetting messages", async () => {
await import("../helpers")

const messageEvent = new MessageEvent("message", {
data: {
type: "otherMessage",
setting: "kilo-code.baseUrl",
value: "https://should-be-ignored.com",
},
})

const eventHandler = mockEventListener.mock.calls[0][1]
eventHandler(messageEvent)

const { getKiloCodeBackendSignInUrl } = await import("../helpers")
const result = getKiloCodeBackendSignInUrl()
expect(result).toBe("https://kilocode.ai/users/sign_in?source=vscode")
})

it("should ignore messages for different settings", async () => {
await import("../helpers")

const messageEvent = new MessageEvent("message", {
data: {
type: "vsCodeSetting",
setting: "other.setting",
value: "https://should-be-ignored.com",
},
})

const eventHandler = mockEventListener.mock.calls[0][1]
eventHandler(messageEvent)

const { getKiloCodeBackendSignInUrl } = await import("../helpers")
const result = getKiloCodeBackendSignInUrl()
expect(result).toBe("https://kilocode.ai/users/sign_in?source=vscode")
})
})
})
30 changes: 28 additions & 2 deletions webview-ui/src/components/kilocode/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
import { vscode } from "@/utils/vscode"

// Global state for base URL
let cachedBaseUrl: string = "https://kilocode.ai"
let hasRequestedSetting = false

// Request the setting from VS Code on first use
function ensureBaseUrlRequested() {
if (!hasRequestedSetting) {
hasRequestedSetting = true
vscode.postMessage({ type: "getVSCodeSetting", setting: "kilo-code.baseUrl" })
}
}

// Listen for VS Code setting responses
window.addEventListener("message", (event) => {
if (event.data?.type === "vsCodeSetting" && event.data?.setting === "kilo-code.baseUrl") {
cachedBaseUrl = event.data.value || "https://kilocode.ai"
}
})

function getBaseUrl(): string {
ensureBaseUrlRequested()
return cachedBaseUrl
}

export function getKiloCodeBackendSignInUrl(uriScheme: string = "vscode", uiKind: string = "Desktop") {
const baseUrl = "https://kilocode.ai"
const baseUrl = getBaseUrl()
const source = uiKind === "Web" ? "web" : uriScheme
return `${baseUrl}/users/sign_in?source=${source}`
}

export function getKiloCodeBackendSignUpUrl(uriScheme: string = "vscode", uiKind: string = "Desktop") {
const baseUrl = "https://kilocode.ai"
const baseUrl = getBaseUrl()
const source = uiKind === "Web" ? "web" : uriScheme
return `${baseUrl}/users/sign_up?source=${source}`
}
Loading