Skip to content

feat(gateway): add Kilo device login and team selection - #15111

Merged
marius-kilocode merged 46 commits into
v2from
gateway-login-v2
Oct 15, 2026
Merged

marius-kilocode merged 46 commits into
v2from
gateway-login-v2

Conversation

@marius-kilocode

Copy link
Copy Markdown
Collaborator

Stacked on #15060.
Part of #14991 (and #13750), PR 1 of the Gateway series. Plan unit U-E1-03 (login and team foundation). Supersedes #14998.

What Problem This Solves

On the v2 branch, the kilo provider used upstream's packages/core/src/plugin/provider/kilo.ts, which only sends HTTP-Referer: https://opencode.ai/ and X-Title: opencode. It had no device authorization flow, no profile or team selection, no X-KILOCODE-ORGANIZATIONID header, and no anonymous fallback when signed out. script/dev-isolated.ts worked around this by reading the v1 login from ~/.local/share/kilo/auth.json.

Why This Change Was Made

Following the architecture in #14991 and #15060:

  1. Pure Gateway logic in packages/kilo-gateway-core (@kilocode/gateway-core) with zero @opencode/* imports (enforced by test/boundary.test.ts):
    • KiloServer: server URL from KILO_API_URL (default https://api.kilo.ai) or embedded before the final : of a development token (fromToken), and /api/gateway base URL.
    • KiloDevice: device authorization (POST /api/device-auth/codes and GET /api/device-auth/codes/{code}), request timeouts capped at the remaining code lifetime, interruption support, and exponential backoff on network errors, timeouts, 408, 429, or 5xx until code expiry.
    • KiloProfile: GET /api/profile decoding (supporting both nested user and flat shapes) and the v1 defaultOrganizationId rule (prefer selectedOrganizationId when valid, otherwise fall back to the first team only when hasPersonalAccount === false).
    • KiloAccount: environment token lookup (KILO_API_KEY > KILOCODE_TOKEN > KILO_AUTH_CONTENT), server and team precedence (token-embedded server > login server > KILO_API_URL; KILO_ORG_ID > selected team > login default), and ANONYMOUS_KEY = "anonymous".
    • KiloHeaders: HTTP-Referer: https://kilocode.ai, X-Title: Kilo Code, X-KILOCODE-EDITORNAME, X-KILOCODE-FEATURE, and X-KILOCODE-ORGANIZATIONID.
    • src/testing.ts: local Gateway fixture exported as @kilocode/gateway-core/testing (compiled into dist/testing.js so verify-package.ts tarball packing resolves it cleanly).
  2. Thin v2 plugin adapter (packages/core/src/kilocode/gateway.ts, gateway-rpc.ts):
    • Replaces KiloPlugin in packages/core/src/plugin/provider.ts.
    • Registers the device OAuth method (Kilo Gateway (Device Authorization)), sets baseURL and Kilo provider headers, gives environment tokens (KILO_API_KEY, KILOCODE_TOKEN, KILO_AUTH_CONTENT) precedence over stored credentials, and enables kilo with apiKey: "anonymous" when signed out.
    • Registers kilocode.gateway RPC (profile and organization.set), persists the team choice per connection in plugin storage, and broadcasts rpc.kilocode.gateway.organization globally via Bus.Service ({ global: true }) so all open locations reload.
  3. TUI account picker and /teams (packages/tui/src/kilocode/gateway.tsx):
    • Prompts for Personal Account vs Team after device login (Select Account (<email>)) when the user belongs to one or more teams.
    • Registers /teams (team, org, orgs) to switch between Personal Account and teams at any time.
  4. Isolated bun dev (script/dev-isolated.ts):
    • Removes the v1 ~/.local/share/kilo/auth.json token reuse so bun dev starts cleanly signed out with kilo/kilo-auto/free.

Shared upstream files changed

File Option Missing seam
packages/core/src/plugin/provider.ts 2 (host registration, temporary) Replace KiloPlugin with KiloGatewayPlugin until the Kilo host registers built-in plugins via SdkPlugins.register (U-E0-01).
packages/core/test/plugin/provider-kilo.test.ts 3 (seam patch) Expect kilocode.gateway in ProviderPlugins in place of opencode.provider.kilo.
packages/core/package.json 3 (seam patch) Runtime dependency on @kilocode/gateway-core for the built-in adapter.
packages/sdk/script/verify-package.ts 3 (seam patch) Pack kilo-gateway-core before core in the SDK pack check.
turbo.json 3 (seam patch) Register @kilocode/gateway-core#test so bun turbo test --affected runs the package tests in CI.
packages/tui/src/component/dialog-integration.tsx 3 (seam patch) Run chooseKiloAccount after a Kilo Gateway login completes (TuiPlugin has no post-connect hook).
packages/tui/src/plugin/builtins.ts 2 (host registration, temporary) Register KiloTeams (/teams) until the Kilo host owns the TUI built-in list (U-E0-01).

User Impact

  • /connect -> Kilo Gateway offers Kilo Gateway (Device Authorization) alongside API key.
  • Approving the device code signs in, selects the backend default team, and opens the Select Account picker when the user belongs to teams.
  • /teams (/team, /org, /orgs) switches between Personal Account and teams.
  • Signed out, kilo/kilo-auto/free works out of the box with the anonymous key and a paid model returns "You need to sign in to use this model."

Evidence

Automated checks

  • bun script/check-opencode-annotations.ts: ok (39 shared files against 4d9678a79d6)
  • bun script/check-shared-patches.ts: ok
  • bun run --cwd packages/kilo-gateway-core typecheck && bun run --cwd packages/kilo-gateway-core build: pass
  • bun run --cwd packages/core typecheck: pass
  • bun run --cwd packages/tui typecheck: pass
  • bun test --cwd packages/kilo-gateway-core: 18 pass, 0 fail
  • bun test --cwd packages/core test/kilocode/gateway.test.ts test/plugin/provider-kilo.test.ts: 11 pass, 0 fail
  • bun test --cwd packages/tui test/kilocode/gateway.test.ts: 2 pass, 0 fail

CLI & TUI Self-Test

  1. Signed-out free model (kilo/kilo-auto/free):
    • env KILO_V2_PROFILE=$(mktemp -d) bun dev run --standalone "Reply with only the word PONG." -> PONG (pass).
  2. Signed-out paid model (kilo/deepseek/deepseek-v4.1-flash):
    • env KILO_V2_PROFILE=$(mktemp -d) bun dev run --standalone -m kilo/deepseek/deepseek-v4.1-flash "Reply with only PONG." -> Error: You need to sign in to use this model. (pass).
  3. Signed-in paid model (KILO_API_KEY + KILO_ORG_ID):
    • env KILO_API_KEY=... KILO_ORG_ID=... KILO_V2_PROFILE=$(mktemp -d) bun dev run --standalone -m kilo/deepseek/deepseek-v4.1-flash "Reply with only the word PONG." -> PONG (pass).
  4. TUI device login, post-login account picker, and /teams dialog:

Kilo Gateway device authorization screen in TUI

Post-login Select Account picker in TUI

/teams Select Team dialog in TUI

feat(gateway): add Kilo device login and team selection
@github-actions github-actions Bot added area:cli CLI, TUI and core engine area:gateway Kilo Gateway and auth area:sdk SDK labels Oct 15, 2026
Base automatically changed from gateway-plan to v2 October 15, 2026 11:31
Comment thread packages/kilo-gateway-core/src/server.ts Outdated
Comment thread packages/kilo-gateway-core/src/account.ts Outdated
Comment thread packages/kilo-gateway-core/src/device.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (12 files)
  • packages/core/src/kilocode/gateway.ts
  • packages/core/src/kilocode/gateway-rpc.ts
  • packages/core/test/kilocode/gateway.test.ts
  • packages/kilo-gateway-core/src/account.ts
  • packages/kilo-gateway-core/src/defaults.ts
  • packages/kilo-gateway-core/src/device.ts
  • packages/kilo-gateway-core/src/index.ts
  • packages/kilo-gateway-core/src/models.ts
  • packages/kilo-gateway-core/src/server.ts
  • packages/kilo-gateway-core/src/testing.ts
  • packages/kilo-gateway-core/test/account.test.ts
  • packages/kilo-gateway-core/test/models.test.ts

The three findings from the previous review are resolved in this increment: the token regex now matches v1 ([^:]+ host, no lookahead) and covers numeric secrets, KiloAccount.resolve restores the organization-from-token-URL fallback, and an approved device poll now requires userEmail. No new critical, warning, or suggestion issues were found on the changed lines (plugin fiber/scope usage, catalog snapshot bounding, URL construction, and schema handling all check out).

Previous Review Summary (commit 9535ebe)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 9535ebe)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-gateway-core/src/server.ts 7 Token regex lookahead misparses tokens with a numeric secret (drops port / returns undefined), unlike v1 getKiloUrlFromToken.
packages/kilo-gateway-core/src/account.ts 53 resolve drops v1's organization-from-token-URL fallback, so the org header and routing are lost for such tokens.

SUGGESTION

File Line Issue
packages/kilo-gateway-core/src/device.ts 108 Approved device poll accepted without userEmail, unlike v1; yields an empty credential label.
Files Reviewed (31 files)
  • .kilo/skills/v2-migration/SKILL.md
  • bun.lock
  • packages/core/package.json
  • packages/core/src/kilocode/gateway-rpc.ts
  • packages/core/src/kilocode/gateway.ts
  • packages/core/src/plugin/provider.ts
  • packages/core/test/kilocode/gateway.test.ts
  • packages/core/test/plugin/provider-kilo.test.ts
  • packages/kilo-gateway-core/package.json
  • packages/kilo-gateway-core/src/account.ts
  • packages/kilo-gateway-core/src/device.ts
  • packages/kilo-gateway-core/src/headers.ts
  • packages/kilo-gateway-core/src/http.ts
  • packages/kilo-gateway-core/src/index.ts
  • packages/kilo-gateway-core/src/profile.ts
  • packages/kilo-gateway-core/src/server.ts
  • packages/kilo-gateway-core/src/testing.ts
  • packages/kilo-gateway-core/test/account.test.ts
  • packages/kilo-gateway-core/test/boundary.test.ts
  • packages/kilo-gateway-core/test/device.test.ts
  • packages/kilo-gateway-core/test/profile.test.ts
  • packages/kilo-gateway-core/tsconfig.build.json
  • packages/kilo-gateway-core/tsconfig.json
  • packages/sdk/script/verify-package.ts
  • packages/tui/src/component/dialog-integration.tsx
  • packages/tui/src/kilocode/gateway.tsx
  • packages/tui/src/plugin/builtins.ts
  • packages/tui/test/kilocode/gateway.test.ts
  • script/dev-isolated.ts
  • script/upstream/shared-patches.json
  • turbo.json

Notes: the plugin/RPC/TUI wiring was verified against the actual plugin API and v1 sources; the provider.replace, organization.set, event reload, dialog cancellation, and keymap.layer usage are all correct with no leaks. The accountOptions/current pre-selection in packages/tui/src/kilocode/gateway.tsx matches v1 (getDefaultOrganizationSelection preselects the first team, getOrganizationOptions marks Personal as current), so it was not flagged. The stacked plan doc (migration-tracking/plans/kilo-gateway-v2-plan.md) is present in the base branch and therefore outside this PR's diff.

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 97.9K · Output: 28.4K · Cached: 1.2M

@WebReflection

Copy link
Copy Markdown
Contributor

@marius-kilocode my counter-verification showed no issues whatsoever but I think having no Kilo bot warnings around would be good?

@marius-kilocode

Copy link
Copy Markdown
Collaborator Author

@WebReflection thanks, rechecked and fixed the bot comments. Let's get this merged before it scope creeps.

feat(gateway): add per-request Kilo headers, body sanitization, and error contract
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:cli CLI, TUI and core engine area:gateway Kilo Gateway and auth area:sdk SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants