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 1/3] 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 2/3] 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 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 3/3] 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 })