Merge pull request #9881 from Kilo-Org/catrielmuller/fix-9511

fix(vscode): route Kilo Gateway sign-in through Profile view
This commit is contained in:
Catriel Müller
2026-05-05 09:22:35 -03:00
committed by GitHub
11 changed files with 59 additions and 6 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---
Route the "Sign In" action from the Providers settings tab, provider picker, and chat auth errors to the Profile view so the device-auth code, QR, and cancel button are always visible.
+5
View File
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---
Trust the OS certificate store and honor corporate CA bundles for the bundled Kilo backend. The extension now defaults `NODE_USE_SYSTEM_CA=1` on the spawned CLI process so users behind MITM proxies (Zscaler, Netskope, Palo Alto, etc.) no longer hit TLS errors on sign-in. A new `kilo-code.new.extraCaCerts` setting accepts a PEM file path for additional CAs, and `http.proxyStrictSSL=false` is honored as an opt-out from verification.
+5
View File
@@ -781,6 +781,11 @@
"default": false,
"description": "Load CLAUDE.md instructions and skills from your Claude Code configuration directory into Kilo sessions. Enable this if you want Kilo to use your Claude Code instructions and skills."
},
"kilo-code.new.extraCaCerts": {
"type": "string",
"default": "",
"description": "Absolute path to a PEM file containing extra CA certificates to trust when the Kilo backend makes HTTPS requests (sets NODE_EXTRA_CA_CERTS on the CLI process). Use this if you're behind a corporate proxy that performs SSL inspection. Leave empty to rely on the OS trust store."
},
"kilo-code.new.autoApprove.enabled": {
"type": "boolean",
"default": false,
@@ -66,12 +66,28 @@ export class ServerManager {
return new Promise((resolve, reject) => {
console.log("[Kilo New] ServerManager: 🎬 Spawning CLI process:", cliPath, ["serve", "--port", "0"])
const claudeCompat = vscode.workspace.getConfiguration("kilo-code.new").get<boolean>("claudeCodeCompat", false)
const cfg = vscode.workspace.getConfiguration("kilo-code.new")
const claudeCompat = cfg.get<boolean>("claudeCodeCompat", false)
// Pin cwd so the CLI doesn't inherit the extension host's cwd ("/" under F5 debug)
const spawnCwd = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? process.env.HOME ?? require("os").homedir()
// TLS / corporate-proxy support:
// - Default NODE_USE_SYSTEM_CA=1 so the bundled Bun CLI trusts the OS
// trust store (Windows cert store, macOS keychain, Linux /etc/ssl).
// Mirrors VS Code's `http.systemCertificates` default (true).
// - Allow users behind MITM proxies to point at a custom CA bundle via
// `kilo-code.new.extraCaCerts` (NODE_EXTRA_CA_CERTS).
// - Honor VS Code's `http.proxyStrictSSL=false` as an explicit opt-out
// from verification, matching what VS Code already does for its own
// requests. Users explicitly set that; we don't flip it ourselves.
// All three are overridable by the user's environment.
const extraCaCerts = cfg.get<string>("extraCaCerts", "").trim()
const proxyStrictSSL = vscode.workspace.getConfiguration("http").get<boolean>("proxyStrictSSL", true)
const serverProcess = spawn(cliPath, ["serve", "--port", "0"], {
cwd: spawnCwd,
env: {
NODE_USE_SYSTEM_CA: "1",
...(extraCaCerts && { NODE_EXTRA_CA_CERTS: extraCaCerts }),
...(!proxyStrictSSL && { NODE_TLS_REJECT_UNAUTHORIZED: "0" }),
...process.env,
// Force mimalloc (the allocator Bun ships with) to return freed pages
// to the OS immediately instead of retaining them in its arenas.
@@ -281,7 +281,7 @@ export const VscodeSessionTurn: Component<VscodeSessionTurnProps> = (props) => {
{/* Error handling */}
<Show when={error()}>
{(err) => <ErrorDisplay error={err() as ErrorDisplayProps["error"]} onLogin={server.startLogin} />}
{(err) => <ErrorDisplay error={err() as ErrorDisplayProps["error"]} onLogin={server.goToLogin} />}
</Show>
</div>
)}
@@ -61,7 +61,8 @@ const ProviderSelectDialog = () => {
if (item.id === KILO_PROVIDER_ID) {
dialog.close()
server.startLogin()
// Navigate to the Profile view so the full device-auth UI is visible.
server.goToLogin()
return
}
@@ -140,7 +140,11 @@ const ProvidersTab: Component = () => {
function connectProvider(item: Provider) {
if (item.id === KILO_PROVIDER_ID) {
server.startLogin()
// Route Kilo Gateway sign-in through the Profile view so the user sees
// the full device-auth UI (URL, QR, code, timer, cancel). Triggering
// `startLogin()` from here alone would run the flow silently with no
// way to recover if the browser is dismissed.
server.goToLogin()
return
}
dialog.show(() => <ProviderConnectDialog providerID={item.id} />)
@@ -177,7 +181,7 @@ const ProvidersTab: Component = () => {
<Show
when={kiloLoggedIn()}
fallback={
<Button size="small" variant="secondary" onClick={() => server.startLogin()}>
<Button size="small" variant="secondary" onClick={() => server.goToLogin()}>
{language.t("common.signIn")}
</Button>
}
@@ -17,6 +17,7 @@ interface ServerContextValue {
profileData: Accessor<ProfileData | null>
deviceAuth: Accessor<DeviceAuthState>
startLogin: () => void
goToLogin: () => void
vscodeLanguage: Accessor<string | undefined>
languageOverride: Accessor<string | undefined>
workspaceDirectory: Accessor<string>
@@ -147,6 +148,19 @@ export const ServerProvider: ParentComponent = (props) => {
vscode.postMessage({ type: "login" })
}
/**
* Route any "Sign In" action through the Profile view so the user always
* sees the device-auth UI (URL, QR, code, timer, cancel). Entry points
* outside the Profile page — e.g. the Kilo Gateway card in the Providers
* settings tab, or the provider picker — must call this helper instead of
* `startLogin()` directly. Otherwise the login flow runs silently and the
* user has no way to see the code or cancel if the browser is dismissed.
*/
const goToLogin = () => {
window.postMessage({ type: "navigate", view: "profile" }, "*")
startLogin()
}
const value: ServerContextValue = {
connectionState,
serverInfo,
@@ -157,6 +171,7 @@ export const ServerProvider: ParentComponent = (props) => {
profileData,
deviceAuth,
startLogin,
goToLogin,
vscodeLanguage,
languageOverride,
workspaceDirectory,
@@ -676,6 +676,7 @@ const mockServer = {
}),
deviceAuth: () => ({ status: "idle" as const }),
startLogin: () => {},
goToLogin: () => {},
vscodeLanguage: () => "en",
languageOverride: () => undefined,
workspaceDirectory: () => "/project",
@@ -1189,6 +1189,7 @@ export const DiffSummaryCollapsed: Story = {
profileData: () => null,
deviceAuth: () => ({ status: "idle" as const }),
startLogin: () => {},
goToLogin: () => {},
vscodeLanguage: () => "en",
languageOverride: () => undefined,
workspaceDirectory: () => "/project",
@@ -759,7 +759,7 @@ it.live(
3_000,
)
it.live(
unix( // kilocode_change - skip flaky cancel test on Windows CI
"cancel records MessageAbortedError on interrupted process",
() =>
provideTmpdirServer(