Merge pull request #8218 from Kilo-Org/catrielmuller/kiloclaw-chat-orgs

feat(cli): add org support for /kiloclaw command
This commit is contained in:
Catriel Müller
2026-04-02 15:48:25 -03:00
committed by GitHub
4 changed files with 37 additions and 21 deletions
+21 -13
View File
@@ -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,16 @@ 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",
},
})
const organizationId = auth.type === "oauth" ? auth.accountId : undefined
const headers: Record<string, string> = {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
}
if (organizationId) {
headers[HEADER_ORGANIZATIONID] = organizationId
}
const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/status`, { headers })
if (!response.ok) {
const text = await response.text()
@@ -589,12 +593,16 @@ 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",
},
})
const organizationId = auth.type === "oauth" ? auth.accountId : undefined
const headers: Record<string, string> = {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
}
if (organizationId) {
headers[HEADER_ORGANIZATIONID] = organizationId
}
const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/chat-credentials`, { headers })
if (!response.ok) {
const text = await response.text()
@@ -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() {
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
<box paddingLeft={3} paddingRight={3} backgroundColor={theme.primary} flexDirection="row">
<text fg={theme.text}>{"🦀 "}</text>
<Link href="https://app.kilo.ai/claw" fg={theme.selectedListItemText}>
<Link href={url} fg={theme.selectedListItemText}>
Try KiloClaw
</Link>
</box>
@@ -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() {
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
<box paddingLeft={3} paddingRight={3} backgroundColor={theme.primary}>
<Link href="https://app.kilo.ai/claw" fg={theme.selectedListItemText}>
<Link href={url} fg={theme.selectedListItemText}>
Dashboard
</Link>
</box>
@@ -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(() => <DialogClawSetup />)
dialog.replace(() => <DialogClawSetup orgId={orgId} />)
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(() => <DialogClawUpgrade />)
dialog.replace(() => <DialogClawUpgrade orgId={orgId} />)
return
}