"use client"; import { useCallback, useEffect, useState } from "react"; import { IconInfoCircle } from "@tabler/icons-react"; import { Button } from "@kandev/ui/button"; import { CardContent } from "@kandev/ui/card"; import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, DrawerTrigger, } from "@kandev/ui/drawer"; import { RadioGroup, RadioGroupItem } from "@kandev/ui/radio-group"; import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip"; import { SettingsCard } from "@/components/settings/settings-card"; import { SettingsSection } from "@/components/settings/settings-section"; import { useSettingsSaveContributor } from "@/components/settings/settings-save-provider"; import { useToast } from "@/components/toast-provider"; import { useTouchDrawer } from "@/hooks/use-compact-task-chrome"; import { fetchGitHubWorkspaceSettings, updateGitHubWorkspaceSettings, } from "@/lib/api/domains/github-api"; import type { TaskGitCredentialsMode } from "@/lib/types/github"; const deliveryHelp = "PAT, named GitHub CLI, and GitHub App connections choose Kandev's workspace automation identity. In managed mode Kandev brokers that identity to the task for GitHub HTTPS and gh. Inherit executor credentials leaves task Git and gh to the selected executor. An explicit executor-profile GH_TOKEN or GITHUB_TOKEN takes precedence in managed mode."; function TaskCredentialsHelp() { const usesDrawer = useTouchDrawer(); const [open, setOpen] = useState(false); const button = ( ); const trigger = {button}; return ( {usesDrawer ? ( trigger ) : ( {trigger} {deliveryHelp} )} How task Git credentials work {deliveryHelp} ); } export function GitHubTaskCredentialsSection({ workspaceId }: { workspaceId: string }) { const { toast } = useToast(); const [mode, setMode] = useState("managed"); const [baseline, setBaseline] = useState("managed"); const [loading, setLoading] = useState(true); useEffect(() => { let cancelled = false; setLoading(true); void fetchGitHubWorkspaceSettings(workspaceId) .then((settings) => { if (!cancelled) { const next = settings.task_git_credentials_mode ?? "managed"; setMode(next); setBaseline(next); } }) .catch(() => { if (!cancelled) toast({ description: "Failed to load task Git credential settings", variant: "error" }); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [toast, workspaceId]); const save = useCallback(async () => { try { const updated = await updateGitHubWorkspaceSettings({ workspace_id: workspaceId, task_git_credentials_mode: mode, }); const next = updated.task_git_credentials_mode ?? "managed"; setBaseline(next); setMode((current) => (current === mode ? next : current)); toast({ description: "Task Git credential settings saved", variant: "success" }); } catch { toast({ description: "Failed to save task Git credential settings", variant: "error" }); throw new Error("Failed to save task Git credential settings"); } }, [mode, toast, workspaceId]); const dirty = mode !== baseline; useSettingsSaveContributor({ id: `github-task-credentials:${workspaceId}`, revision: mode, isDirty: dirty, canSave: !loading, save, discard: () => setMode(baseline), }); return ( } > setMode(value as TaskGitCredentialsMode)} disabled={loading} data-testid="github-task-credentials-mode" >

An executor-profile GH_TOKEN or GITHUB_TOKEN overrides managed workspace credentials for that task.

); }