diff --git a/src/renderer/src/components/editor/CheckRunDetailsPanel.tsx b/src/renderer/src/components/editor/CheckRunDetailsPanel.tsx
index db8dbcade..754837a67 100644
--- a/src/renderer/src/components/editor/CheckRunDetailsPanel.tsx
+++ b/src/renderer/src/components/editor/CheckRunDetailsPanel.tsx
@@ -1,10 +1,13 @@
import React from 'react'
import { ExternalLink, LoaderCircle, RefreshCw } from 'lucide-react'
+import { toast } from 'sonner'
import { Button } from '@/components/ui/button'
import CommentMarkdown from '@/components/sidebar/CommentMarkdown'
import type { PRCheckDetail, PRCheckRunDetails } from '../../../../shared/types'
import { CheckJobLogTail } from '@/components/right-sidebar/check-job-log-tail'
+import { SourceControlFixSplitButton } from '@/components/right-sidebar/source-control-fix-split-button'
import { translate } from '@/i18n/i18n'
+import { useCheckRunDetailsFixWithAI } from './check-run-details-fix-with-ai'
function formatCheckTimestamp(value: string | null | undefined): string | null {
if (!value) {
@@ -52,6 +55,7 @@ export function CheckRunDetailsPanel({
loading,
error,
openUrl,
+ worktreeId,
onRefresh
}: {
check: PRCheckDetail
@@ -59,8 +63,28 @@ export function CheckRunDetailsPanel({
loading: boolean
error: string | null
openUrl: string | null | undefined
+ worktreeId: string | null
onRefresh?: () => void
}): React.JSX.Element {
+ const {
+ canFixWithAI,
+ disabledReason,
+ isFixing,
+ fixPrompt,
+ repoId,
+ connectionId,
+ launchPlatform,
+ savedAgentId,
+ savedCommandInputTemplate,
+ savedAgentArgs,
+ saveLaunchActionDefault,
+ openSourceControlAiSettings,
+ fixWithAI
+ } = useCheckRunDetailsFixWithAI({
+ worktreeId,
+ check,
+ details
+ })
const startedAt = formatCheckTimestamp(details?.startedAt)
const completedAt = formatCheckTimestamp(details?.completedAt)
const detailsStatusCheck: PRCheckDetail = {
@@ -85,19 +109,86 @@ export function CheckRunDetailsPanel({
{check.name}
- {onRefresh && (
-
-
- {translate('auto.components.editor.CheckRunDetailsPanel.b7f5e2c91a', 'Refresh')}
-
- )}
+
+ {canFixWithAI && (
+
+ toast.success(
+ translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.2ef90c9819',
+ 'Started an AI agent for this check.'
+ )
+ )
+ }
+ />
+ )}
+ {onRefresh && (
+
+
+ {translate('auto.components.editor.CheckRunDetailsPanel.b7f5e2c91a', 'Refresh')}
+
+ )}
+
diff --git a/src/renderer/src/components/editor/EditorContent.tsx b/src/renderer/src/components/editor/EditorContent.tsx
index 48d2c812d..a322f72e4 100644
--- a/src/renderer/src/components/editor/EditorContent.tsx
+++ b/src/renderer/src/components/editor/EditorContent.tsx
@@ -637,6 +637,7 @@ export function EditorContent({
loading={checkRunDetails.loading}
error={checkRunDetails.error}
openUrl={openUrl}
+ worktreeId={activeFile.worktreeId}
onRefresh={() => {
void reloadOpenCheckRunDetailsTab(activeFile.id)
}}
diff --git a/src/renderer/src/components/editor/check-run-details-fix-context.ts b/src/renderer/src/components/editor/check-run-details-fix-context.ts
new file mode 100644
index 000000000..7f0881109
--- /dev/null
+++ b/src/renderer/src/components/editor/check-run-details-fix-context.ts
@@ -0,0 +1,153 @@
+import {
+ buildFixBrokenChecksPrompt,
+ getBrokenChecks,
+ getCheckDetailsPromptKey
+} from '@/components/pr-checks-fix-prompt'
+import { gitHubPRToChecksPanelReview } from '@/components/right-sidebar/checks-panel-review'
+import { getWorktreeGitIdentityDisplay } from '@/lib/worktree-git-identity-display'
+import { useAppStore } from '@/store'
+import { getGitHubPRCacheKey } from '@/store/slices/github-cache-key'
+import { getHostedReviewCacheKey } from '@/store/slices/hosted-review-cache-identity'
+import { findWorktreeById } from '@/store/slices/worktree-helpers'
+import type { HostedReviewInfo } from '../../../../shared/hosted-review'
+import type { PRCheckDetail, PRCheckRunDetails, Repo } from '../../../../shared/types'
+import { translate } from '@/i18n/i18n'
+
+export function resolveCheckRunDetailsFixCheck(
+ check: PRCheckDetail,
+ details: PRCheckRunDetails | null
+): PRCheckDetail {
+ if (!details) {
+ return check
+ }
+ return {
+ ...check,
+ status: (details.status as PRCheckDetail['status'] | undefined) ?? check.status,
+ conclusion: (details.conclusion as PRCheckDetail['conclusion'] | undefined) ?? check.conclusion
+ }
+}
+
+export function isCheckRunDetailsFixCandidate(
+ check: PRCheckDetail,
+ details: PRCheckRunDetails | null = null
+): boolean {
+ return getBrokenChecks([resolveCheckRunDetailsFixCheck(check, details)]).length > 0
+}
+
+export function resolveHostedReviewForCheckRunDetailsFix(
+ worktreeId: string
+): HostedReviewInfo | null {
+ const store = useAppStore.getState()
+ const worktree = findWorktreeById(store.worktreesByRepo, worktreeId)
+ if (!worktree) {
+ return null
+ }
+ const repo = store.repos.find((candidate) => candidate.id === worktree.repoId) ?? null
+ if (!repo) {
+ return null
+ }
+ const identity = getWorktreeGitIdentityDisplay(worktree)
+ const branch = identity?.kind === 'branch' ? identity.branchName : null
+ if (!branch) {
+ return null
+ }
+ const settings = store.settings
+ const prCacheKey = getGitHubPRCacheKey(
+ repo.path,
+ repo.id,
+ branch,
+ settings,
+ repo.connectionId,
+ repo.executionHostId
+ )
+ const hostedReviewCacheKey = getHostedReviewCacheKey(
+ repo.path,
+ branch,
+ settings,
+ repo.id,
+ repo.connectionId,
+ repo.executionHostId
+ )
+ const pr = prCacheKey ? (store.prCache[prCacheKey]?.data ?? null) : null
+ const hostedReview = hostedReviewCacheKey
+ ? (store.hostedReviewCache[hostedReviewCacheKey]?.data ?? null)
+ : null
+ const gitLabHostedReview = hostedReview?.provider === 'gitlab' ? hostedReview : null
+ const linkedGitLabMR = worktree.linkedGitLabMR ?? null
+ if (gitLabHostedReview) {
+ return gitLabHostedReview
+ }
+ if (linkedGitLabMR !== null) {
+ return null
+ }
+ return pr ? gitHubPRToChecksPanelReview(pr) : null
+}
+
+export function buildCheckRunDetailsFixBasePrompt(args: {
+ worktreeId: string
+ check: PRCheckDetail
+ details: PRCheckRunDetails | null
+}): string | null {
+ const review = resolveHostedReviewForCheckRunDetailsFix(args.worktreeId)
+ if (!review) {
+ return null
+ }
+ const resolvedCheck = resolveCheckRunDetailsFixCheck(args.check, args.details)
+ if (!isCheckRunDetailsFixCandidate(resolvedCheck)) {
+ return null
+ }
+ const checkRunDetailsByCheckKey = args.details
+ ? { [getCheckDetailsPromptKey(resolvedCheck, 0)]: args.details }
+ : undefined
+ return buildFixBrokenChecksPrompt({
+ reviewKind: review.provider === 'gitlab' ? 'MR' : 'PR',
+ reviewNumber: review.number,
+ reviewTitle: review.title,
+ reviewUrl: review.url,
+ checks: [resolvedCheck],
+ checkRunDetailsByCheckKey
+ })
+}
+
+export function getCheckRunDetailsFixDisabledReason(worktreeId: string | null): string | undefined {
+ if (!worktreeId) {
+ return translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.1a8c4e2b90',
+ 'Select a workspace before launching an AI action.'
+ )
+ }
+ const store = useAppStore.getState()
+ const worktree = findWorktreeById(store.worktreesByRepo, worktreeId)
+ if (!worktree) {
+ return translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.1a8c4e2b90',
+ 'Select a workspace before launching an AI action.'
+ )
+ }
+ const repo = store.repos.find((candidate) => candidate.id === worktree.repoId) ?? null
+ if (!repo) {
+ return translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.4f2d9a8c17',
+ 'Select a repository before launching an AI action.'
+ )
+ }
+ if (!resolveHostedReviewForCheckRunDetailsFix(worktreeId)) {
+ return translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.7c3e1b5d42',
+ 'Open a PR or MR before launching an AI fix.'
+ )
+ }
+ return undefined
+}
+
+export function resolveCheckRunDetailsFixRepo(worktreeId: string | null): Repo | null {
+ if (!worktreeId) {
+ return null
+ }
+ const store = useAppStore.getState()
+ const worktree = findWorktreeById(store.worktreesByRepo, worktreeId)
+ if (!worktree) {
+ return null
+ }
+ return store.repos.find((candidate) => candidate.id === worktree.repoId) ?? null
+}
diff --git a/src/renderer/src/components/editor/check-run-details-fix-with-ai.test.ts b/src/renderer/src/components/editor/check-run-details-fix-with-ai.test.ts
new file mode 100644
index 000000000..10531e222
--- /dev/null
+++ b/src/renderer/src/components/editor/check-run-details-fix-with-ai.test.ts
@@ -0,0 +1,203 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import type {
+ PRCheckDetail,
+ PRCheckRunDetails,
+ PRInfo,
+ Repo,
+ Worktree
+} from '../../../../shared/types'
+import {
+ getCheckRunDetailsFixDisabledReason,
+ isCheckRunDetailsFixCandidate,
+ resolveCheckRunDetailsFixCheck,
+ resolveHostedReviewForCheckRunDetailsFix,
+ startCheckRunDetailsFixWithAI
+} from './check-run-details-fix-with-ai'
+
+const startFixChecksAgent = vi.fn()
+
+const fixtures = vi.hoisted(() => {
+ const repo: Repo = {
+ id: 'repo-1',
+ path: '/tmp/repo',
+ displayName: 'repo',
+ badgeColor: '#2563eb',
+ addedAt: 1,
+ connectionId: null,
+ executionHostId: null
+ }
+ const worktree: Worktree = {
+ id: 'repo-1::/tmp/repo/feature',
+ repoId: 'repo-1',
+ path: '/tmp/repo/feature',
+ head: 'abc123',
+ branch: 'feature',
+ isBare: false,
+ isMainWorktree: false,
+ displayName: 'feature',
+ comment: '',
+ linkedIssue: null,
+ linkedPR: 42,
+ linkedLinearIssue: null,
+ isArchived: false,
+ isUnread: false,
+ isPinned: false,
+ sortOrder: 0,
+ lastActivityAt: 0
+ }
+ const pr: PRInfo = {
+ number: 42,
+ title: 'Fix CI',
+ state: 'open',
+ url: 'https://github.com/acme/widgets/pull/42',
+ checksStatus: 'failure',
+ updatedAt: '2026-06-16T00:00:00Z',
+ mergeable: 'MERGEABLE'
+ }
+ const failingCheck: PRCheckDetail = {
+ name: 'verify',
+ status: 'completed',
+ conclusion: 'failure',
+ url: null,
+ checkRunId: 42
+ }
+ const checkDetails: PRCheckRunDetails = {
+ name: 'verify',
+ status: 'completed',
+ conclusion: 'failure',
+ url: null,
+ detailsUrl: null,
+ startedAt: null,
+ completedAt: null,
+ title: null,
+ summary: null,
+ text: null,
+ annotations: [],
+ jobs: [
+ {
+ id: 1,
+ name: 'test',
+ status: 'completed',
+ conclusion: 'failure',
+ startedAt: null,
+ completedAt: null,
+ url: null,
+ steps: [],
+ logTail: 'assertion failed'
+ }
+ ]
+ }
+ const prCacheKey = 'repo-1::feature'
+ return { repo, worktree, pr, failingCheck, checkDetails, prCacheKey }
+})
+
+const storeState = vi.hoisted(() => ({
+ worktreesByRepo: { 'repo-1': [fixtures.worktree] } as Record,
+ repos: [fixtures.repo] as Repo[],
+ settings: {},
+ prCache: {
+ [fixtures.prCacheKey]: { data: fixtures.pr, fetchedAt: 1 }
+ } as Record,
+ hostedReviewCache: {} as Record
+}))
+
+vi.mock('@/lib/worktree-git-identity-display', () => ({
+ getWorktreeGitIdentityDisplay: () => ({ kind: 'branch', branchName: 'feature' })
+}))
+
+vi.mock('@/store', () => ({
+ useAppStore: Object.assign(
+ (selector: (state: typeof storeState) => unknown) => selector(storeState),
+ {
+ getState: () => storeState
+ }
+ )
+}))
+
+vi.mock('@/lib/fix-checks-agent-launch', () => ({
+ startFixChecksAgent: (...args: unknown[]) => startFixChecksAgent(...args)
+}))
+
+vi.mock('sonner', () => ({
+ toast: {
+ message: vi.fn(),
+ success: vi.fn()
+ }
+}))
+
+beforeEach(() => {
+ startFixChecksAgent.mockReset()
+ startFixChecksAgent.mockResolvedValue(true)
+ storeState.worktreesByRepo = { 'repo-1': [fixtures.worktree] }
+ storeState.repos = [fixtures.repo]
+ storeState.prCache = {
+ [fixtures.prCacheKey]: { data: fixtures.pr, fetchedAt: 1 }
+ }
+ storeState.hostedReviewCache = {}
+})
+
+describe('check-run-details-fix-with-ai', () => {
+ it('detects failing checks as fix candidates', () => {
+ expect(isCheckRunDetailsFixCandidate(fixtures.failingCheck)).toBe(true)
+ expect(
+ isCheckRunDetailsFixCandidate({
+ ...fixtures.failingCheck,
+ conclusion: 'success'
+ })
+ ).toBe(false)
+ })
+
+ it('prefers loaded details conclusion over the list-level check', () => {
+ const listFailure = fixtures.failingCheck
+ const passingDetails: PRCheckRunDetails = {
+ ...fixtures.checkDetails,
+ conclusion: 'success',
+ status: 'completed'
+ }
+ expect(isCheckRunDetailsFixCandidate(listFailure, passingDetails)).toBe(false)
+ expect(
+ resolveCheckRunDetailsFixCheck(
+ { ...fixtures.failingCheck, conclusion: 'success' },
+ fixtures.checkDetails
+ ).conclusion
+ ).toBe('failure')
+ expect(
+ isCheckRunDetailsFixCandidate(
+ { ...fixtures.failingCheck, conclusion: 'success' },
+ fixtures.checkDetails
+ )
+ ).toBe(true)
+ })
+
+ it('resolves hosted review metadata from the worktree PR cache', () => {
+ expect(resolveHostedReviewForCheckRunDetailsFix(fixtures.worktree.id)).toMatchObject({
+ number: 42,
+ title: 'Fix CI',
+ url: 'https://github.com/acme/widgets/pull/42'
+ })
+ })
+
+ it('requires a hosted review before launching an AI fix', () => {
+ storeState.prCache = {}
+ expect(getCheckRunDetailsFixDisabledReason(fixtures.worktree.id)).toContain('PR or MR')
+ })
+
+ it('starts a single-check AI fix prompt for the owning worktree', async () => {
+ await startCheckRunDetailsFixWithAI({
+ worktreeId: fixtures.worktree.id,
+ check: fixtures.failingCheck,
+ details: fixtures.checkDetails
+ })
+
+ expect(startFixChecksAgent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ repoId: 'repo-1',
+ worktreeId: fixtures.worktree.id,
+ groupId: fixtures.worktree.id,
+ launchSource: 'task_page',
+ basePrompt: expect.stringContaining('"name": "verify"')
+ })
+ )
+ expect(startFixChecksAgent.mock.calls[0]?.[0]?.basePrompt).toContain('assertion failed')
+ })
+})
diff --git a/src/renderer/src/components/editor/check-run-details-fix-with-ai.ts b/src/renderer/src/components/editor/check-run-details-fix-with-ai.ts
new file mode 100644
index 000000000..80059758c
--- /dev/null
+++ b/src/renderer/src/components/editor/check-run-details-fix-with-ai.ts
@@ -0,0 +1,232 @@
+import { toast } from 'sonner'
+import { useCallback, useMemo, useState } from 'react'
+import {
+ buildCheckRunDetailsFixBasePrompt,
+ getCheckRunDetailsFixDisabledReason,
+ isCheckRunDetailsFixCandidate,
+ resolveCheckRunDetailsFixCheck,
+ resolveHostedReviewForCheckRunDetailsFix,
+ resolveCheckRunDetailsFixRepo
+} from './check-run-details-fix-context'
+import { openSourceControlAiSettingsTarget } from '@/components/right-sidebar/source-control-ai-settings-navigation'
+import { getConnectionId } from '@/lib/connection-context'
+import { startFixChecksAgent } from '@/lib/fix-checks-agent-launch'
+import { readSourceControlLaunchRecipeAgentId } from '@/lib/source-control-launch-agent-selection'
+import { resolveSourceControlLaunchPlatform } from '@/lib/source-control-launch-platform'
+import { useAppStore } from '@/store'
+import { findWorktreeById } from '@/store/slices/worktree-helpers'
+import { resolveSourceControlActionRecipe } from '../../../../shared/source-control-ai'
+import {
+ saveSourceControlActionRecipe,
+ type SourceControlAiWriteTarget
+} from '../../../../shared/source-control-ai-recipe-save'
+import type {
+ SourceControlActionRecipe,
+ SourceControlLaunchActionId
+} from '../../../../shared/source-control-ai-actions'
+import type { PRCheckDetail, PRCheckRunDetails } from '../../../../shared/types'
+import { translate } from '@/i18n/i18n'
+
+export {
+ buildCheckRunDetailsFixBasePrompt,
+ getCheckRunDetailsFixDisabledReason,
+ isCheckRunDetailsFixCandidate,
+ resolveCheckRunDetailsFixCheck,
+ resolveHostedReviewForCheckRunDetailsFix
+} from './check-run-details-fix-context'
+
+export async function startCheckRunDetailsFixWithAI(args: {
+ worktreeId: string
+ check: PRCheckDetail
+ details: PRCheckRunDetails | null
+}): Promise {
+ const disabledReason = getCheckRunDetailsFixDisabledReason(args.worktreeId)
+ if (disabledReason) {
+ toast.message(disabledReason)
+ return false
+ }
+ const resolvedCheck = resolveCheckRunDetailsFixCheck(args.check, args.details)
+ if (!isCheckRunDetailsFixCandidate(resolvedCheck)) {
+ toast.message(
+ translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.9b2f6d4a81',
+ 'This check is not failing.'
+ )
+ )
+ return false
+ }
+ const review = resolveHostedReviewForCheckRunDetailsFix(args.worktreeId)
+ if (!review) {
+ toast.message(
+ translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.7c3e1b5d42',
+ 'Open a PR or MR before launching an AI fix.'
+ )
+ )
+ return false
+ }
+ const repoId = resolveCheckRunDetailsFixRepo(args.worktreeId)?.id
+ if (!repoId) {
+ return false
+ }
+ const basePrompt =
+ buildCheckRunDetailsFixBasePrompt({
+ worktreeId: args.worktreeId,
+ check: args.check,
+ details: args.details
+ }) ?? ''
+ if (!basePrompt) {
+ return false
+ }
+ const started = await startFixChecksAgent({
+ repoId,
+ basePrompt,
+ worktreeId: args.worktreeId,
+ groupId: args.worktreeId,
+ launchSource: 'task_page'
+ })
+ if (started) {
+ toast.success(
+ translate(
+ 'auto.components.editor.check.run.details.fix.with.ai.2ef90c9819',
+ 'Started an AI agent for this check.'
+ )
+ )
+ }
+ return started
+}
+
+export function useCheckRunDetailsFixWithAI(args: {
+ worktreeId: string | null
+ check: PRCheckDetail
+ details: PRCheckRunDetails | null
+}): {
+ canFixWithAI: boolean
+ disabledReason: string | undefined
+ isFixing: boolean
+ fixPrompt: string | null
+ repoId: string | null
+ connectionId: string | null | undefined
+ launchPlatform: NodeJS.Platform | undefined
+ savedAgentId: ReturnType
+ savedCommandInputTemplate: string | null
+ savedAgentArgs: string | null
+ saveLaunchActionDefault: (
+ target: SourceControlAiWriteTarget,
+ actionId: SourceControlLaunchActionId,
+ recipe: SourceControlActionRecipe
+ ) => Promise
+ openSourceControlAiSettings: () => void
+ fixWithAI: () => Promise
+} {
+ const [isFixing, setIsFixing] = useState(false)
+ const settings = useAppStore((state) => state.settings)
+ const updateSettings = useAppStore((state) => state.updateSettings)
+ const updateRepo = useAppStore((state) => state.updateRepo)
+ const openSettingsTarget = useAppStore((state) => state.openSettingsTarget)
+ const openSettingsPage = useAppStore((state) => state.openSettingsPage)
+ const repo = useMemo(() => resolveCheckRunDetailsFixRepo(args.worktreeId), [args.worktreeId])
+ const worktree = useMemo(() => {
+ if (!args.worktreeId) {
+ return null
+ }
+ return findWorktreeById(useAppStore.getState().worktreesByRepo, args.worktreeId)
+ }, [args.worktreeId])
+ const canFixWithAI = isCheckRunDetailsFixCandidate(args.check, args.details)
+ const disabledReason = getCheckRunDetailsFixDisabledReason(args.worktreeId)
+ const fixPrompt = useMemo(() => {
+ if (!args.worktreeId || !canFixWithAI) {
+ return null
+ }
+ return buildCheckRunDetailsFixBasePrompt({
+ worktreeId: args.worktreeId,
+ check: args.check,
+ details: args.details
+ })
+ }, [args.check, args.details, args.worktreeId, canFixWithAI])
+ const connectionId = args.worktreeId
+ ? (getConnectionId(args.worktreeId) ?? repo?.connectionId ?? null)
+ : null
+ const launchPlatform = resolveSourceControlLaunchPlatform({
+ connectionId,
+ worktreePath: worktree?.path ?? null
+ })
+ const fixChecksRecipe = useMemo(
+ () =>
+ resolveSourceControlActionRecipe({
+ settings,
+ repo,
+ actionId: 'fixChecks'
+ }),
+ [repo, settings]
+ )
+ const saveLaunchActionDefault = useCallback(
+ async (
+ target: SourceControlAiWriteTarget,
+ actionId: SourceControlLaunchActionId,
+ recipe: SourceControlActionRecipe
+ ): Promise => {
+ const state = useAppStore.getState()
+ const latestSettings = state.settings
+ if (!latestSettings) {
+ throw new Error('Settings are not loaded.')
+ }
+ const latestRepo =
+ target.type === 'repo'
+ ? (state.repos.find((candidate) => candidate.id === target.repoId) ?? null)
+ : null
+ const result = saveSourceControlActionRecipe({
+ target,
+ settings: latestSettings,
+ repo: latestRepo,
+ actionId,
+ recipe
+ })
+ if ('sourceControlAi' in result) {
+ await updateSettings({ sourceControlAi: result.sourceControlAi })
+ return
+ }
+ await updateRepo(result.target.repoId, result.update)
+ },
+ [updateRepo, updateSettings]
+ )
+ const openSourceControlAiSettings = useCallback((): void => {
+ openSourceControlAiSettingsTarget({
+ activeRepo: repo,
+ openSettingsTarget,
+ openSettingsPage
+ })
+ }, [openSettingsPage, openSettingsTarget, repo])
+
+ const fixWithAI = useCallback(async (): Promise => {
+ if (!args.worktreeId || isFixing || disabledReason) {
+ return false
+ }
+ setIsFixing(true)
+ try {
+ return await startCheckRunDetailsFixWithAI({
+ worktreeId: args.worktreeId,
+ check: args.check,
+ details: args.details
+ })
+ } finally {
+ setIsFixing(false)
+ }
+ }, [args.check, args.details, args.worktreeId, disabledReason, isFixing])
+
+ return {
+ canFixWithAI,
+ disabledReason,
+ isFixing,
+ fixPrompt,
+ repoId: repo?.id ?? null,
+ connectionId,
+ launchPlatform,
+ savedAgentId: readSourceControlLaunchRecipeAgentId(fixChecksRecipe),
+ savedCommandInputTemplate: fixChecksRecipe.commandInputTemplate ?? null,
+ savedAgentArgs: fixChecksRecipe.agentArgs ?? null,
+ saveLaunchActionDefault,
+ openSourceControlAiSettings,
+ fixWithAI
+ }
+}
diff --git a/src/renderer/src/components/right-sidebar/FolderWorkspacePrChecksRow.tsx b/src/renderer/src/components/right-sidebar/FolderWorkspacePrChecksRow.tsx
index bc9966b7e..13796a63b 100644
--- a/src/renderer/src/components/right-sidebar/FolderWorkspacePrChecksRow.tsx
+++ b/src/renderer/src/components/right-sidebar/FolderWorkspacePrChecksRow.tsx
@@ -114,6 +114,8 @@ export function FolderWorkspacePrChecksRow({
checksLoading={row.isRefreshing}
checkDetailsContextKey={row.refreshIdentity}
onLoadCheckDetails={onLoadCheckDetails}
+ worktreeId={row.worktree.id}
+ detailsStickySurface="card"
/>
) : null}
diff --git a/src/renderer/src/components/right-sidebar/checks-list-expanded-details.test.tsx b/src/renderer/src/components/right-sidebar/checks-list-expanded-details.test.tsx
new file mode 100644
index 000000000..e7ee2002d
--- /dev/null
+++ b/src/renderer/src/components/right-sidebar/checks-list-expanded-details.test.tsx
@@ -0,0 +1,213 @@
+// @vitest-environment happy-dom
+
+import { act } from 'react'
+import { createRoot, type Root } from 'react-dom/client'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { TooltipProvider } from '@/components/ui/tooltip'
+import type { PRCheckDetail, PRCheckRunDetails } from '../../../../shared/types'
+import { ChecksList } from './checks-panel-content'
+
+const openCheckRunDetails = vi.fn()
+const patchOpenCheckRunDetails = vi.fn()
+const activeWorktreeState = vi.hoisted(() => ({
+ current: null as { id: string } | null
+}))
+
+vi.mock('@/store', () => ({
+ useAppStore: (selector: (state: Record) => unknown) =>
+ selector({
+ openCheckRunDetails,
+ patchOpenCheckRunDetails
+ })
+}))
+
+vi.mock('@/store/selectors', () => ({
+ useActiveWorktree: () => activeWorktreeState.current
+}))
+
+let container: HTMLDivElement
+let root: Root
+
+const failingCheck: PRCheckDetail = {
+ name: 'verify',
+ status: 'completed',
+ conclusion: 'failure',
+ url: null,
+ checkRunId: 42,
+ workflowRunId: 7
+}
+
+const checkDetails: PRCheckRunDetails = {
+ name: 'verify',
+ status: 'completed',
+ conclusion: 'failure',
+ url: null,
+ detailsUrl: null,
+ startedAt: '2026-06-16T12:00:00Z',
+ completedAt: '2026-06-16T12:05:00Z',
+ title: 'Verify failed',
+ summary: null,
+ text: null,
+ annotations: [],
+ jobs: [
+ {
+ id: 1,
+ name: 'test',
+ status: 'completed',
+ conclusion: 'failure',
+ startedAt: null,
+ completedAt: null,
+ url: null,
+ steps: [],
+ logTail: 'Error: assertion failed'
+ }
+ ]
+}
+
+beforeEach(() => {
+ activeWorktreeState.current = null
+ openCheckRunDetails.mockReset()
+ patchOpenCheckRunDetails.mockReset()
+ container = document.createElement('div')
+ document.body.appendChild(container)
+ root = createRoot(container)
+})
+
+afterEach(() => {
+ act(() => {
+ root.unmount()
+ })
+ container.remove()
+})
+
+function renderChecksList(
+ props: Partial<{
+ worktreeId: string
+ detailsStickySurface: 'sidebar' | 'card'
+ onLoadCheckDetails: (check: PRCheckDetail) => Promise
+ }> = {}
+): void {
+ act(() => {
+ root.render(
+
+ {
+ await Promise.resolve()
+ return checkDetails
+ })
+ }
+ />
+
+ )
+ })
+}
+
+describe('ChecksList expanded check details', () => {
+ it('pins a contextual full-details action with the correct sticky surface', async () => {
+ renderChecksList({ worktreeId: 'wt-child-1', detailsStickySurface: 'card' })
+
+ await act(async () => {
+ await Promise.resolve()
+ })
+
+ const stickyBar = container.querySelector('.sticky.top-0')
+ expect(stickyBar).not.toBeNull()
+ expect(stickyBar?.className).toContain('bg-card/95')
+ expect(stickyBar?.textContent).toContain('verify')
+ expect(stickyBar?.textContent).toContain('View full logs')
+ expect(container.innerHTML).toContain('lucide-panel-right')
+ expect(container.innerHTML).toContain('data-variant="outline"')
+ })
+
+ it('uses the sidebar sticky surface by default in the hosted checks panel', async () => {
+ activeWorktreeState.current = { id: 'wt-active-1' }
+ renderChecksList()
+
+ await act(async () => {
+ await Promise.resolve()
+ })
+
+ const stickyBar = container.querySelector('.sticky.top-0')
+ expect(stickyBar?.className).toContain('bg-sidebar/95')
+ })
+
+ it('falls back to the active worktree when no worktree override is provided', async () => {
+ activeWorktreeState.current = { id: 'wt-active-1' }
+ renderChecksList()
+
+ await act(async () => {
+ await Promise.resolve()
+ })
+
+ const button = [...container.querySelectorAll('button')].find((candidate) =>
+ candidate.textContent?.includes('View full logs')
+ )
+ expect(button).toBeDefined()
+
+ act(() => {
+ button!.dispatchEvent(new MouseEvent('click', { bubbles: true }))
+ })
+
+ expect(openCheckRunDetails).toHaveBeenCalledWith(
+ 'wt-active-1',
+ 'repo:42',
+ failingCheck,
+ expect.objectContaining({
+ details: checkDetails,
+ loading: false,
+ error: null
+ })
+ )
+ })
+
+ it('opens full details on the provided worktree instead of the active worktree', async () => {
+ activeWorktreeState.current = { id: 'wt-active-1' }
+ renderChecksList({ worktreeId: 'wt-attached-9' })
+
+ await act(async () => {
+ await Promise.resolve()
+ })
+
+ const button = [...container.querySelectorAll('button')].find((candidate) =>
+ candidate.textContent?.includes('View full logs')
+ )
+ expect(button).toBeDefined()
+
+ act(() => {
+ button!.dispatchEvent(new MouseEvent('click', { bubbles: true }))
+ })
+
+ expect(openCheckRunDetails).toHaveBeenCalledWith(
+ 'wt-attached-9',
+ 'repo:42',
+ failingCheck,
+ expect.objectContaining({
+ details: checkDetails,
+ loading: false,
+ error: null
+ })
+ )
+ })
+
+ it('keeps the generic label while inline details are still loading', async () => {
+ renderChecksList({
+ worktreeId: 'wt-child-1',
+ onLoadCheckDetails: () => new Promise(() => {})
+ })
+
+ await act(async () => {
+ await Promise.resolve()
+ })
+
+ const stickyBar = container.querySelector('.sticky.top-0')
+ expect(stickyBar?.textContent).toContain('View full details')
+ expect(stickyBar?.textContent).not.toContain('View full logs')
+ })
+})
diff --git a/src/renderer/src/components/right-sidebar/checks-panel-content.tsx b/src/renderer/src/components/right-sidebar/checks-panel-content.tsx
index 1e0391a9c..6c8627bb5 100644
--- a/src/renderer/src/components/right-sidebar/checks-panel-content.tsx
+++ b/src/renderer/src/components/right-sidebar/checks-panel-content.tsx
@@ -15,6 +15,7 @@ import {
Plus,
ChevronDown,
ChevronRight,
+ PanelRight,
SendHorizontal,
Sparkles,
RefreshCw,
@@ -469,16 +470,46 @@ export function getFailedChecksForDetails(checks: PRCheckDetail[]): PRCheckDetai
return checks.filter(isFailedCheck)
}
+type CheckDetailsStickySurface = 'sidebar' | 'card'
+
+function getCheckDetailsStickySurfaceClass(surface: CheckDetailsStickySurface): string {
+ return surface === 'card' ? 'bg-card/95' : 'bg-sidebar/95'
+}
+
+function ViewFullCheckDetailsButton({
+ onClick,
+ label
+}: {
+ onClick: (event: React.MouseEvent) => void
+ label: string
+}): React.JSX.Element {
+ return (
+
+
+ {label}
+
+ )
+}
+
function CheckRunDetails({
check,
state,
- checkDetailsContextKey
+ checkDetailsContextKey,
+ worktreeId,
+ detailsStickySurface = 'sidebar'
}: {
check: PRCheckDetail
state: CheckDetailsLoadState | undefined
checkDetailsContextKey: string
+ worktreeId: string | null
+ detailsStickySurface?: CheckDetailsStickySurface
}): React.JSX.Element {
- const activeWorktree = useActiveWorktree()
const openCheckRunDetails = useAppStore((s) => s.openCheckRunDetails)
const details = state?.details
const startedAt = formatCheckTimestamp(details?.startedAt)
@@ -499,19 +530,49 @@ function CheckRunDetails({
const hasJobs = jobs.length > 0
const hasLogTail = jobs.some((job) => Boolean(job.logTail))
+ // Why: wait until inline details finish loading before switching to the logs label
+ // so the sticky button does not resize mid-fetch.
+ const fullDetailsLabel =
+ !state?.loading && hasLogTail
+ ? translate('auto.components.right.sidebar.checks.panel.content.b8c4e2a1f7', 'View full logs')
+ : translate(
+ 'auto.components.right.sidebar.checks.panel.content.e4e3af15ee',
+ 'View full details'
+ )
+
const openFullDetailsTab = (): void => {
- if (!activeWorktree) {
+ if (!worktreeId) {
return
}
- openCheckRunDetails(activeWorktree.id, checkDetailsContextKey, check, {
+ openCheckRunDetails(worktreeId, checkDetailsContextKey, check, {
details: state?.details ?? null,
loading: state?.loading ?? false,
error: state?.error ?? null
})
}
+ const handleOpenFullDetails = (event: React.MouseEvent): void => {
+ event.stopPropagation()
+ openFullDetailsTab()
+ }
+
return (
+ {worktreeId && (
+ // Why: inline check details can be long; pinning the affordance keeps it
+ // visible while scrolling through annotations and job output.
+
+
+ {check.name}
+
+
+
+ )}
{state?.loading ? (
@@ -521,25 +582,6 @@ function CheckRunDetails({
'Loading check details…'
)}
- {activeWorktree && (
-
- {
- event.stopPropagation()
- openFullDetailsTab()
- }}
- >
- {translate(
- 'auto.components.right.sidebar.checks.panel.content.e4e3af15ee',
- 'View full details'
- )}
-
-
- )}
) : (
@@ -744,26 +786,6 @@ function CheckRunDetails({
)}
)}
-
-
- {activeWorktree && (
- {
- event.stopPropagation()
- openFullDetailsTab()
- }}
- >
- {translate(
- 'auto.components.right.sidebar.checks.panel.content.e4e3af15ee',
- 'View full details'
- )}
-
- )}
-
)}
@@ -777,14 +799,20 @@ export function ChecksList({
checks,
checksLoading,
checkDetailsContextKey,
- onLoadCheckDetails
+ onLoadCheckDetails,
+ worktreeId: worktreeIdOverride,
+ detailsStickySurface = 'sidebar'
}: {
checks: PRCheckDetail[]
checksLoading: boolean
checkDetailsContextKey: string
onLoadCheckDetails?: (check: PRCheckDetail) => Promise
+ /** Why: folder-workspace PR checks render rows for attached worktrees, not the active one. */
+ worktreeId?: string
+ detailsStickySurface?: CheckDetailsStickySurface
}): React.JSX.Element {
const activeWorktree = useActiveWorktree()
+ const resolvedWorktreeId = worktreeIdOverride ?? activeWorktree?.id ?? null
const patchOpenCheckRunDetails = useAppStore((s) => s.patchOpenCheckRunDetails)
const [checksExpanded, setChecksExpanded] = useState(true)
const [expandedCheckKeys, setExpandedCheckKeys] = useState>(new Set())
@@ -952,7 +980,7 @@ export function ChecksList({
}, [checksExpanded, detailsByCheckKey, expandedCheckKeys, requestCheckDetails, rows])
useEffect(() => {
- if (!activeWorktree) {
+ if (!resolvedWorktreeId) {
return
}
for (const row of rows) {
@@ -960,13 +988,19 @@ export function ChecksList({
if (!detailsState) {
continue
}
- patchOpenCheckRunDetails(activeWorktree.id, checkDetailsContextKey, row.check, {
+ patchOpenCheckRunDetails(resolvedWorktreeId, checkDetailsContextKey, row.check, {
details: detailsState.details ?? null,
loading: detailsState.loading ?? false,
error: detailsState.error ?? null
})
}
- }, [activeWorktree, checkDetailsContextKey, detailsByCheckKey, patchOpenCheckRunDetails, rows])
+ }, [
+ checkDetailsContextKey,
+ detailsByCheckKey,
+ patchOpenCheckRunDetails,
+ resolvedWorktreeId,
+ rows
+ ])
const toggleCheckExpanded = useCallback(
(row: { check: PRCheckDetail; key: string }) => {
@@ -1124,6 +1158,8 @@ export function ChecksList({
check={check}
state={detailsByCheckKey[row.key]}
checkDetailsContextKey={checkDetailsContextKey}
+ worktreeId={resolvedWorktreeId}
+ detailsStickySurface={detailsStickySurface}
/>
)}
diff --git a/src/renderer/src/components/right-sidebar/source-control-fix-split-button.tsx b/src/renderer/src/components/right-sidebar/source-control-fix-split-button.tsx
new file mode 100644
index 000000000..26fed7960
--- /dev/null
+++ b/src/renderer/src/components/right-sidebar/source-control-fix-split-button.tsx
@@ -0,0 +1,171 @@
+import React, { useState } from 'react'
+import { ChevronDown, RefreshCw, SlidersHorizontal, Sparkle } from 'lucide-react'
+import { Button } from '@/components/ui/button'
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger
+} from '@/components/ui/dropdown-menu'
+import { cn } from '@/lib/utils'
+import type {
+ SourceControlActionRecipe,
+ SourceControlLaunchActionId
+} from '../../../../shared/source-control-ai-actions'
+import type { TuiAgent } from '../../../../shared/types'
+import type { LaunchSource } from '../../../../shared/telemetry-events'
+import type { SourceControlAiWriteTarget } from '../../../../shared/source-control-ai-recipe-save'
+import { translate } from '@/i18n/i18n'
+import { SourceControlAgentActionDialog } from './SourceControlAgentActionDialog'
+
+export type SourceControlFixSplitButtonProps = {
+ label: string
+ actionId: SourceControlLaunchActionId
+ dialogTitle: string
+ dialogDescription: string
+ launchSource: LaunchSource
+ contextUnavailableLabel: string
+ primaryTitle: string
+ primaryAriaLabel: string
+ chevronTitle: string
+ chevronAriaLabel: string
+ worktreeId: string | null
+ groupId: string | null
+ connectionId?: string | null
+ repoId?: string | null
+ launchPlatform?: NodeJS.Platform
+ prompt: string | null
+ isLaunching: boolean
+ disabledReason?: string
+ variant: React.ComponentProps['variant']
+ size: React.ComponentProps['size']
+ iconClassName: string
+ primaryClassName?: string
+ chevronClassName?: string
+ savedAgentId?: TuiAgent | null
+ savedCommandInputTemplate?: string | null
+ savedAgentArgs?: string | null
+ onSaveAgentDefault?: (
+ target: SourceControlAiWriteTarget,
+ actionId: SourceControlLaunchActionId,
+ recipe: SourceControlActionRecipe
+ ) => void | Promise
+ onOpenSettings?: () => void
+ onFixWithDefaultAgent: (promptOverride?: string) => Promise | boolean
+ onPromptDelivered?: () => void
+}
+
+export function SourceControlFixSplitButton({
+ label,
+ actionId,
+ dialogTitle,
+ dialogDescription,
+ launchSource,
+ contextUnavailableLabel,
+ primaryTitle,
+ primaryAriaLabel,
+ chevronTitle,
+ chevronAriaLabel,
+ worktreeId,
+ groupId,
+ connectionId,
+ repoId,
+ launchPlatform,
+ prompt,
+ isLaunching,
+ disabledReason,
+ variant,
+ size,
+ iconClassName,
+ primaryClassName,
+ chevronClassName,
+ savedAgentId,
+ savedCommandInputTemplate,
+ savedAgentArgs,
+ onSaveAgentDefault,
+ onOpenSettings,
+ onFixWithDefaultAgent,
+ onPromptDelivered
+}: SourceControlFixSplitButtonProps): React.JSX.Element {
+ const [composerOpen, setComposerOpen] = useState(false)
+ const canLaunch = Boolean(worktreeId && groupId && prompt && !disabledReason)
+ const dividerClass = variant === 'default' ? 'border-primary-foreground/20' : 'border-border'
+
+ return (
+ <>
+
+
+ void onFixWithDefaultAgent()}
+ >
+ {isLaunching ? (
+
+ ) : (
+
+ )}
+ {label}
+
+
+
+
+
+
+
+
+ {worktreeId && groupId && prompt && !disabledReason ? (
+ setComposerOpen(true)}
+ className="gap-2 rounded-[7px] px-2 py-1.5 text-[12px] leading-5 font-medium"
+ >
+
+ {translate(
+ 'auto.components.right.sidebar.SourceControl.f0a2dc9e46',
+ 'Customize launch...'
+ )}
+
+ ) : (
+ {contextUnavailableLabel}
+ )}
+
+
+ {worktreeId && groupId && prompt ? (
+
+ ) : null}
+ >
+ )
+}
diff --git a/src/renderer/src/components/tab-bar/tab-title-tooltip.test.tsx b/src/renderer/src/components/tab-bar/tab-title-tooltip.test.tsx
index ed5176c27..de2cb6ca3 100644
--- a/src/renderer/src/components/tab-bar/tab-title-tooltip.test.tsx
+++ b/src/renderer/src/components/tab-bar/tab-title-tooltip.test.tsx
@@ -61,6 +61,7 @@ vi.mock('@/components/ui/dropdown-menu', () => ({
DropdownMenuContent: () => null,
DropdownMenuItem: ({ children }: { children?: ReactNode }) => <>{children}>,
DropdownMenuSeparator: () => null,
+ DropdownMenuShortcut: ({ children }: { children?: ReactNode }) => <>{children}>,
DropdownMenuTrigger: ({ children }: { children: ReactNode }) => <>{children}>
}))
diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json
index 28a46f758..7ae5aa002 100644
--- a/src/renderer/src/i18n/locales/en.json
+++ b/src/renderer/src/i18n/locales/en.json
@@ -8471,6 +8471,7 @@
"fd46a70f1a": "Started",
"a54ae21c6f": "Status:",
"e4e3af15ee": "View full details",
+ "b8c4e2a1f7": "View full logs",
"2524d1fb83": "Log tail available in full details.",
"a2fb3f4408": "Showing first 100 jobs",
"df137989b3": "Showing first 20 annotations",
@@ -10438,7 +10439,30 @@
"49731703ea": "Jobs",
"ee07b33924": "unknown",
"07eccfa397": "No details are available for this check.",
- "a916648574": "Open details"
+ "a916648574": "Open details",
+ "834cb3f23d": "Fix with AI",
+ "c8f1a2d4e7": "Choose the agent and edit the full command input before launch.",
+ "b3e7f9a1c2": "Check fix context unavailable",
+ "d5a8c2f1b9": "Start the default AI agent to fix this check",
+ "e2b4d7c8a1": "Choose an agent for this check",
+ "f1c9e3a6d4": "Choose agent to fix check"
+ },
+ "check": {
+ "run": {
+ "details": {
+ "fix": {
+ "with": {
+ "ai": {
+ "1a8c4e2b90": "Select a workspace before launching an AI action.",
+ "4f2d9a8c17": "Select a repository before launching an AI action.",
+ "7c3e1b5d42": "Open a PR or MR before launching an AI fix.",
+ "9b2f6d4a81": "This check is not failing.",
+ "2ef90c9819": "Started an AI agent for this check."
+ }
+ }
+ }
+ }
+ }
}
},
"diff": {
diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json
index 86dab5929..0acfc6a1c 100644
--- a/src/renderer/src/i18n/locales/es.json
+++ b/src/renderer/src/i18n/locales/es.json
@@ -8505,7 +8505,8 @@
"d91f2a6c39": "Enviar {{value0}} comentarios en cola",
"a6de3e5a20": "Borrar comentarios en cola",
"49ea0937e4": "Agregar comentario a la lista de resolución",
- "9fecebb29d": "Agregar"
+ "9fecebb29d": "Agregar",
+ "b8c4e2a1f7": "View full logs"
},
"empty": {
"state": {
@@ -10438,7 +10439,30 @@
"49731703ea": "Jobs",
"ee07b33924": "unknown",
"07eccfa397": "No details are available for this check.",
- "a916648574": "Open details"
+ "a916648574": "Open details",
+ "834cb3f23d": "Fix with AI",
+ "c8f1a2d4e7": "Choose the agent and edit the full command input before launch.",
+ "b3e7f9a1c2": "Check fix context unavailable",
+ "d5a8c2f1b9": "Start the default AI agent to fix this check",
+ "e2b4d7c8a1": "Choose an agent for this check",
+ "f1c9e3a6d4": "Choose agent to fix check"
+ },
+ "check": {
+ "run": {
+ "details": {
+ "fix": {
+ "with": {
+ "ai": {
+ "1a8c4e2b90": "Select a workspace before launching an AI action.",
+ "4f2d9a8c17": "Select a repository before launching an AI action.",
+ "7c3e1b5d42": "Open a PR or MR before launching an AI fix.",
+ "9b2f6d4a81": "This check is not failing.",
+ "2ef90c9819": "Started an AI agent for this check."
+ }
+ }
+ }
+ }
+ }
}
},
"diff": {
diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json
index 3e5995b78..0d4c246ac 100644
--- a/src/renderer/src/i18n/locales/ja.json
+++ b/src/renderer/src/i18n/locales/ja.json
@@ -8505,7 +8505,8 @@
"d91f2a6c39": "キュー内の {{value0}} 件のコメントを送信",
"a6de3e5a20": "キュー内のコメントをクリア",
"49ea0937e4": "コメントを解決リストに追加",
- "9fecebb29d": "追加"
+ "9fecebb29d": "追加",
+ "b8c4e2a1f7": "View full logs"
},
"empty": {
"state": {
@@ -10438,7 +10439,30 @@
"49731703ea": "Jobs",
"ee07b33924": "unknown",
"07eccfa397": "No details are available for this check.",
- "a916648574": "Open details"
+ "a916648574": "Open details",
+ "834cb3f23d": "Fix with AI",
+ "c8f1a2d4e7": "Choose the agent and edit the full command input before launch.",
+ "b3e7f9a1c2": "Check fix context unavailable",
+ "d5a8c2f1b9": "Start the default AI agent to fix this check",
+ "e2b4d7c8a1": "Choose an agent for this check",
+ "f1c9e3a6d4": "Choose agent to fix check"
+ },
+ "check": {
+ "run": {
+ "details": {
+ "fix": {
+ "with": {
+ "ai": {
+ "1a8c4e2b90": "Select a workspace before launching an AI action.",
+ "4f2d9a8c17": "Select a repository before launching an AI action.",
+ "7c3e1b5d42": "Open a PR or MR before launching an AI fix.",
+ "9b2f6d4a81": "This check is not failing.",
+ "2ef90c9819": "Started an AI agent for this check."
+ }
+ }
+ }
+ }
+ }
}
},
"diff": {
diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json
index fc08403d0..a43873824 100644
--- a/src/renderer/src/i18n/locales/ko.json
+++ b/src/renderer/src/i18n/locales/ko.json
@@ -8505,7 +8505,8 @@
"d91f2a6c39": "대기 중인 댓글 {{value0}}개 보내기",
"a6de3e5a20": "대기 중인 댓글 지우기",
"49ea0937e4": "댓글을 해결 목록에 추가",
- "9fecebb29d": "추가"
+ "9fecebb29d": "추가",
+ "b8c4e2a1f7": "View full logs"
},
"empty": {
"state": {
@@ -10438,7 +10439,30 @@
"49731703ea": "Jobs",
"ee07b33924": "unknown",
"07eccfa397": "No details are available for this check.",
- "a916648574": "Open details"
+ "a916648574": "Open details",
+ "834cb3f23d": "Fix with AI",
+ "c8f1a2d4e7": "Choose the agent and edit the full command input before launch.",
+ "b3e7f9a1c2": "Check fix context unavailable",
+ "d5a8c2f1b9": "Start the default AI agent to fix this check",
+ "e2b4d7c8a1": "Choose an agent for this check",
+ "f1c9e3a6d4": "Choose agent to fix check"
+ },
+ "check": {
+ "run": {
+ "details": {
+ "fix": {
+ "with": {
+ "ai": {
+ "1a8c4e2b90": "Select a workspace before launching an AI action.",
+ "4f2d9a8c17": "Select a repository before launching an AI action.",
+ "7c3e1b5d42": "Open a PR or MR before launching an AI fix.",
+ "9b2f6d4a81": "This check is not failing.",
+ "2ef90c9819": "Started an AI agent for this check."
+ }
+ }
+ }
+ }
+ }
}
},
"diff": {
diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json
index 9aeb0c421..194233d18 100644
--- a/src/renderer/src/i18n/locales/zh.json
+++ b/src/renderer/src/i18n/locales/zh.json
@@ -8505,7 +8505,8 @@
"d91f2a6c39": "发送 {{value0}} 条已排队评论",
"a6de3e5a20": "清除已排队评论",
"49ea0937e4": "将评论添加到解决列表",
- "9fecebb29d": "添加"
+ "9fecebb29d": "添加",
+ "b8c4e2a1f7": "View full logs"
},
"empty": {
"state": {
@@ -10438,7 +10439,30 @@
"49731703ea": "Jobs",
"ee07b33924": "unknown",
"07eccfa397": "No details are available for this check.",
- "a916648574": "Open details"
+ "a916648574": "Open details",
+ "834cb3f23d": "Fix with AI",
+ "c8f1a2d4e7": "Choose the agent and edit the full command input before launch.",
+ "b3e7f9a1c2": "Check fix context unavailable",
+ "d5a8c2f1b9": "Start the default AI agent to fix this check",
+ "e2b4d7c8a1": "Choose an agent for this check",
+ "f1c9e3a6d4": "Choose agent to fix check"
+ },
+ "check": {
+ "run": {
+ "details": {
+ "fix": {
+ "with": {
+ "ai": {
+ "1a8c4e2b90": "Select a workspace before launching an AI action.",
+ "4f2d9a8c17": "Select a repository before launching an AI action.",
+ "7c3e1b5d42": "Open a PR or MR before launching an AI fix.",
+ "9b2f6d4a81": "This check is not failing.",
+ "2ef90c9819": "Started an AI agent for this check."
+ }
+ }
+ }
+ }
+ }
}
},
"diff": {