feat(ui): start worktree sessions from GitLab issues and merge requests

This commit is contained in:
2026-08-16 15:42:26 +00:00
parent a42eec5c9c
commit a05056a871
29 changed files with 1706 additions and 53 deletions
@@ -85,6 +85,22 @@ const PROMPT_PAGE_MAP: Record<string, PromptPageConfig> = {
{ id: 'github.pr.comment.single.instructions', titleKey: 'settings.magicPrompts.page.block.instructions' }, { id: 'github.pr.comment.single.instructions', titleKey: 'settings.magicPrompts.page.block.instructions' },
], ],
}, },
'gitlab.pr.review': {
titleKey: 'settings.magicPrompts.page.group.gitlabPrReview.title',
descriptionKey: 'settings.magicPrompts.page.group.gitlabPrReview.description',
blocks: [
{ id: 'gitlab.pr.review.visible', titleKey: 'settings.magicPrompts.page.block.visiblePrompt' },
{ id: 'gitlab.pr.review.instructions', titleKey: 'settings.magicPrompts.page.block.instructions' },
],
},
'gitlab.issue.review': {
titleKey: 'settings.magicPrompts.page.group.gitlabIssueReview.title',
descriptionKey: 'settings.magicPrompts.page.group.gitlabIssueReview.description',
blocks: [
{ id: 'gitlab.issue.review.visible', titleKey: 'settings.magicPrompts.page.block.visiblePrompt' },
{ id: 'gitlab.issue.review.instructions', titleKey: 'settings.magicPrompts.page.block.instructions' },
],
},
'git.conflict.resolve': { 'git.conflict.resolve': {
titleKey: 'settings.magicPrompts.page.group.gitConflictResolve.title', titleKey: 'settings.magicPrompts.page.group.gitConflictResolve.title',
descriptionKey: 'settings.magicPrompts.page.group.gitConflictResolve.description', descriptionKey: 'settings.magicPrompts.page.group.gitConflictResolve.description',
@@ -35,6 +35,13 @@ export const MagicPromptsSidebar: React.FC<MagicPromptsSidebarProps> = ({ onItem
{ id: 'github.pr.comment.single', titleKey: 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview' }, { id: 'github.pr.comment.single', titleKey: 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview' },
], ],
}, },
{
groupKey: 'settings.magicPrompts.sidebar.group.gitlab',
items: [
{ id: 'gitlab.pr.review', titleKey: 'settings.magicPrompts.sidebar.item.gitlabPrReview' },
{ id: 'gitlab.issue.review', titleKey: 'settings.magicPrompts.sidebar.item.gitlabIssueReview' },
],
},
{ {
groupKey: 'settings.magicPrompts.sidebar.group.planning', groupKey: 'settings.magicPrompts.sidebar.group.planning',
items: [ items: [
@@ -0,0 +1,684 @@
import * as React from 'react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { cn } from '@/lib/utils';
import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';
import { useProjectsStore } from '@/stores/useProjectsStore';
import { useUIStore } from '@/stores/useUIStore';
import { useGitLabAuthStore } from '@/stores/useGitLabAuthStore';
import { validateWorktreeCreate } from '@/lib/worktrees/worktreeManager';
import { SortableTabsStrip } from '@/components/ui/sortable-tabs-strip';
import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
import { Icon } from "@/components/icon/Icon";
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import type {
GitLabIssueSummary,
GitLabMergeRequestSummary,
} from '@/lib/api/types';
import type { ProjectRef } from '@/lib/worktrees/worktreeManager';
import { useI18n } from '@/lib/i18n';
type GitLabTab = 'issues' | 'mrs';
interface GitLabIntegrationDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onSelect: (result: {
type: 'issue';
number: number;
title: string;
url: string;
} | {
type: 'mr';
number: number;
title: string;
url: string;
sourceBranch: string;
includeDiff: boolean;
} | null) => void;
}
interface ValidationResult {
isValid: boolean;
error: string | null;
}
export function GitLabIntegrationDialog({
open,
onOpenChange,
onSelect,
}: GitLabIntegrationDialogProps) {
const { t } = useI18n();
const isMobile = useUIStore((state) => state.isMobile);
const gitlab = getRegisteredRuntimeAPIs()?.gitlab;
const gitlabAuthStatus = useGitLabAuthStore((state) => state.status);
const gitlabAuthChecked = useGitLabAuthStore((state) => state.hasChecked);
const setSettingsDialogOpen = useUIStore((state) => state.setSettingsDialogOpen);
const setSettingsPage = useUIStore((state) => state.setSettingsPage);
const activeProject = useProjectsStore((state) => state.getActiveProject());
const projectDirectory = activeProject?.path ?? null;
const projectRef: ProjectRef | null = React.useMemo(() => {
if (projectDirectory && activeProject) {
return { id: activeProject.id, path: projectDirectory };
}
return null;
}, [activeProject, projectDirectory]);
// State
const [activeTab, setActiveTab] = React.useState<GitLabTab>('issues');
const [searchQuery, setSearchQuery] = React.useState('');
const [issues, setIssues] = React.useState<GitLabIssueSummary[]>([]);
const [mrs, setMrs] = React.useState<GitLabMergeRequestSummary[]>([]);
const [loading, setLoading] = React.useState(false);
const [loadingMore, setLoadingMore] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
const [selectedIssue, setSelectedIssue] = React.useState<GitLabIssueSummary | null>(null);
const [selectedMr, setSelectedMr] = React.useState<GitLabMergeRequestSummary | null>(null);
const [includeDiff, setIncludeDiff] = React.useState(false);
const [validations, setValidations] = React.useState<Map<string, ValidationResult>>(new Map());
const [page, setPage] = React.useState(1);
const [hasMore, setHasMore] = React.useState(false);
const debouncedSearchQuery = useDebouncedValue(searchQuery, 350);
const loadData = React.useCallback(async (query?: string) => {
if (!projectDirectory || !gitlab) return;
if (gitlabAuthChecked && gitlabAuthStatus?.connected === false) return;
setLoading(true);
setError(null);
setPage(1);
setHasMore(false);
try {
if (activeTab === 'issues' && gitlab.issuesList) {
const result = await gitlab.issuesList(projectDirectory, { page: 1, query });
if (result.connected === false) {
setError(t('session.gitlabIntegration.error.notConnected'));
setIssues([]);
} else {
setIssues(result.issues ?? []);
setPage(result.page ?? 1);
setHasMore(Boolean(result.hasMore));
}
} else if (activeTab === 'mrs' && gitlab.mrsList) {
const result = await gitlab.mrsList(projectDirectory, { page: 1, query });
if (result.connected === false) {
setError(t('session.gitlabIntegration.error.notConnected'));
setMrs([]);
} else {
setMrs(result.mrs ?? []);
setPage(result.page ?? 1);
setHasMore(Boolean(result.hasMore));
}
}
} catch (err) {
setError(err instanceof Error ? err.message : t('session.gitlabIntegration.error.loadDataFailed'));
} finally {
setLoading(false);
}
}, [projectDirectory, gitlab, gitlabAuthChecked, gitlabAuthStatus, activeTab, t]);
React.useEffect(() => {
if (!open || !projectDirectory) return;
if (gitlabAuthChecked && gitlabAuthStatus?.connected === false) return;
if (!gitlab) return;
if (!debouncedSearchQuery.trim()) {
void loadData();
return;
}
const controller = new AbortController();
setLoading(true);
setError(null);
setPage(1);
setHasMore(false);
const apiCall = activeTab === 'issues' && gitlab.issuesList
? gitlab.issuesList(projectDirectory, { page: 1, query: debouncedSearchQuery.trim() })
: activeTab === 'mrs' && gitlab.mrsList
? gitlab.mrsList(projectDirectory, { page: 1, query: debouncedSearchQuery.trim() })
: null;
if (!apiCall) {
setLoading(false);
return;
}
apiCall
.then((result) => {
if (controller.signal.aborted) return;
if ('issues' in result) {
if (result.connected === false) {
setError(t('session.gitlabIntegration.error.notConnected'));
setIssues([]);
} else {
setIssues(result.issues ?? []);
setPage(result.page ?? 1);
setHasMore(Boolean(result.hasMore));
}
} else if ('mrs' in result) {
if (result.connected === false) {
setError(t('session.gitlabIntegration.error.notConnected'));
setMrs([]);
} else {
setMrs(result.mrs ?? []);
setPage(result.page ?? 1);
setHasMore(Boolean(result.hasMore));
}
}
})
.catch((err) => {
if (controller.signal.aborted) return;
setError(err instanceof Error ? err.message : t('session.gitlabIntegration.error.loadDataFailed'));
})
.finally(() => {
if (!controller.signal.aborted) setLoading(false);
});
return () => controller.abort();
}, [open, projectDirectory, gitlab, gitlabAuthChecked, gitlabAuthStatus, activeTab, debouncedSearchQuery, loadData, t]);
const loadMore = React.useCallback(async () => {
if (!projectDirectory || !gitlab) return;
if (loading || loadingMore) return;
if (!hasMore) return;
setLoadingMore(true);
try {
const nextPage = page + 1;
if (activeTab === 'issues' && gitlab.issuesList) {
const result = debouncedSearchQuery.trim()
? await gitlab.issuesList(projectDirectory, { page: nextPage, query: debouncedSearchQuery.trim() })
: await gitlab.issuesList(projectDirectory, { page: nextPage });
if (result.connected !== false) {
setIssues(prev => [...prev, ...(result.issues ?? [])]);
setPage(result.page ?? nextPage);
setHasMore(Boolean(result.hasMore));
}
} else if (activeTab === 'mrs' && gitlab.mrsList) {
const result = debouncedSearchQuery.trim()
? await gitlab.mrsList(projectDirectory, { page: nextPage, query: debouncedSearchQuery.trim() })
: await gitlab.mrsList(projectDirectory, { page: nextPage });
if (result.connected !== false) {
setMrs(prev => [...prev, ...(result.mrs ?? [])]);
setPage(result.page ?? nextPage);
setHasMore(Boolean(result.hasMore));
}
}
} catch {
// Silently fail on load more errors
} finally {
setLoadingMore(false);
}
}, [projectDirectory, gitlab, activeTab, page, hasMore, loading, loadingMore, debouncedSearchQuery]);
// Reset state when dialog opens/closes
React.useEffect(() => {
if (!open) {
setActiveTab('issues');
setSearchQuery('');
setIssues([]);
setMrs([]);
setSelectedIssue(null);
setSelectedMr(null);
setIncludeDiff(false);
setError(null);
setValidations(new Map());
setPage(1);
setHasMore(false);
return;
}
void loadData();
}, [open, loadData]);
// Validate branches for worktree creation
const validateBranch = React.useCallback(async (branchName: string) => {
if (!projectRef || !branchName) return;
// Check cache first
if (validations.has(branchName)) return;
try {
const result = await validateWorktreeCreate(projectRef, {
mode: 'new',
branchName,
worktreeName: branchName,
});
const blockingError = result.errors.find((entry) => entry.code === 'branch_in_use');
setValidations(prev => new Map(prev).set(branchName, {
isValid: !blockingError,
error: blockingError
? t(blockingError.code === 'branch_exists'
? 'session.gitlabIntegration.validation.branchAlreadyExists'
: 'session.gitlabIntegration.validation.branchAlreadyCheckedOut')
: null,
}));
} catch {
setValidations(prev => new Map(prev).set(branchName, {
isValid: false,
error: t('session.gitlabIntegration.validation.failed'),
}));
}
}, [projectRef, validations, t]);
// Validate MR branches when loaded
React.useEffect(() => {
if (!open || activeTab !== 'mrs') return;
mrs.forEach(mr => {
if (mr.sourceBranch) {
void validateBranch(mr.sourceBranch);
}
});
}, [open, activeTab, mrs, validateBranch]);
// GitLab connection check
const isGitLabConnected = gitlabAuthChecked && gitlabAuthStatus?.connected === true;
const openGitLabSettings = () => {
setSettingsPage('git');
setSettingsDialogOpen(true);
};
// Handle selection
const handleSelectIssue = (issue: GitLabIssueSummary) => {
setSelectedIssue(issue);
setSelectedMr(null);
};
const handleSelectMr = (mr: GitLabMergeRequestSummary) => {
setSelectedMr(mr);
setSelectedIssue(null);
};
const handleConfirm = () => {
if (selectedIssue) {
onSelect({
type: 'issue',
number: selectedIssue.number,
title: selectedIssue.title,
url: selectedIssue.url,
});
} else if (selectedMr) {
onSelect({
type: 'mr',
number: selectedMr.number,
title: selectedMr.title,
url: selectedMr.url,
sourceBranch: selectedMr.sourceBranch,
includeDiff,
});
}
onOpenChange(false);
};
const handleClear = () => {
setSelectedIssue(null);
setSelectedMr(null);
setIncludeDiff(false);
};
// Check if selection is valid
const canConfirm = selectedIssue || (selectedMr && validations.get(selectedMr.sourceBranch)?.isValid !== false);
// Check if MR is blocked
const isMrBlocked = (mr: GitLabMergeRequestSummary): boolean => {
if (!mr.sourceBranch) return true;
const validation = validations.get(mr.sourceBranch);
return validation?.isValid === false;
};
// Content for the dialog (shared between mobile and desktop)
const dialogContent = (
<>
{!isGitLabConnected ? (
<div className="flex-1 flex flex-col items-center justify-center p-8 gap-4">
<Icon name="git-branch" className="h-12 w-12 text-muted-foreground" />
<div className="text-center">
<p className="typography-ui-label text-foreground">{t('session.gitlabIntegration.connect.title')}</p>
<p className="typography-small text-muted-foreground mt-1">
{t('session.gitlabIntegration.connect.description')}
</p>
</div>
<Button onClick={openGitLabSettings} size="sm">{t('session.gitlabIntegration.connect.action')}</Button>
</div>
) : (
<>
{/* Search */}
<div className="relative mt-2">
<Icon name="search" className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder={activeTab === 'issues'
? t('session.gitlabIntegration.search.issuesPlaceholder')
: t('session.gitlabIntegration.search.mrsPlaceholder')}
className="h-8 pl-9"
/>
</div>
{/* List Content */}
<div className="mt-2 h-[300px] overflow-hidden">
<div className="h-full overflow-y-auto">
{/* Loading */}
{loading && (
<div className="flex items-center justify-center h-full">
<Icon name="loader-4" className="h-5 w-5 animate-spin text-muted-foreground" />
</div>
)}
{/* Error */}
{error && (
<div className="flex items-center justify-center h-full">
<div className="flex items-center gap-2 p-2 rounded-md bg-destructive/10 text-destructive">
<Icon name="error-warning" className="h-4 w-4" />
<span className="typography-small">{error}</span>
</div>
</div>
)}
{/* Issues List */}
{!loading && !error && activeTab === 'issues' && (
<div className="space-y-0.5 min-h-full">
{issues.length > 0 ? (
issues.map(issue => (
<button
key={issue.number}
onClick={() => handleSelectIssue(issue)}
className={cn(
'w-full text-left px-2 py-1.5 rounded transition-colors',
selectedIssue?.number === issue.number
? 'bg-interactive-selection text-interactive-selection-foreground'
: 'hover:bg-interactive-hover'
)}
>
<div className="flex items-start gap-2">
<span className="text-muted-foreground shrink-0 typography-micro">#{issue.number}</span>
<div className="min-w-0 flex-1">
<span className="typography-small line-clamp-2">{issue.title}</span>
</div>
</div>
</button>
))
) : (
<div className="flex items-center justify-center h-[300px] text-center typography-small text-muted-foreground">
{t('session.gitlabIntegration.empty.noIssuesFound')}
</div>
)}
{hasMore && !loadingMore && (
<div className="flex justify-center pt-2">
<Button
variant="ghost"
size="sm"
onClick={() => void loadMore()}
className="h-7 text-xs"
>
{t('session.gitlabIntegration.actions.loadMore')}
</Button>
</div>
)}
{loadingMore && (
<div className="flex items-center justify-center py-2">
<Icon name="loader-4" className="h-4 w-4 animate-spin text-muted-foreground" />
</div>
)}
</div>
)}
{/* MRs List */}
{!loading && !error && activeTab === 'mrs' && (
<div className="space-y-0.5 min-h-full">
{mrs.length > 0 ? (
mrs.map(mr => {
const blocked = isMrBlocked(mr);
const validation = mr.sourceBranch ? validations.get(mr.sourceBranch) : undefined;
return (
<button
key={mr.number}
onClick={() => !blocked && handleSelectMr(mr)}
disabled={blocked}
className={cn(
'w-full text-left px-2 py-1.5 rounded transition-colors',
selectedMr?.number === mr.number
? 'bg-interactive-selection text-interactive-selection-foreground'
: blocked
? 'opacity-50 cursor-not-allowed'
: 'hover:bg-interactive-hover'
)}
>
<div className="flex items-start gap-2">
<span className="text-muted-foreground shrink-0 typography-micro">!{mr.number}</span>
<div className="min-w-0 flex-1">
<span className="typography-small line-clamp-1">{mr.title}</span>
<div className="flex items-center gap-2 mt-0.5">
<span className="typography-micro text-muted-foreground">
{mr.sourceBranch} {mr.targetBranch}
</span>
{mr.draft && (
<span className="typography-micro px-1 py-0.5 rounded bg-status-info/10 text-status-info">
{t('session.gitlabIntegration.draftBadge')}
</span>
)}
{blocked && validation?.error && (
<span className="typography-micro text-destructive">
{validation.error}
</span>
)}
</div>
</div>
</div>
</button>
);
})
) : (
<div className="flex items-center justify-center h-[300px] text-center typography-small text-muted-foreground">
{t('session.gitlabIntegration.empty.noMergeRequestsFound')}
</div>
)}
{hasMore && !loadingMore && (
<div className="flex justify-center pt-2">
<Button
variant="ghost"
size="sm"
onClick={() => void loadMore()}
className="h-7 text-xs"
>
{t('session.gitlabIntegration.actions.loadMore')}
</Button>
</div>
)}
{loadingMore && (
<div className="flex items-center justify-center py-2">
<Icon name="loader-4" className="h-4 w-4 animate-spin text-muted-foreground" />
</div>
)}
</div>
)}
</div>
</div>
</>
)}
</>
);
// Footer content
const footerContent = (
<div className={cn(
'w-full',
isMobile ? 'flex flex-col gap-2' : 'flex flex-row items-center'
)}>
{/* Left side: Selected Item / Checkbox */}
<div className={cn(
'flex items-center gap-4',
isMobile ? 'w-full justify-center order-1' : 'flex-1'
)}>
{/* Selected Issue/MR display - hidden on mobile (shown in header instead) */}
{!isMobile && (selectedIssue || selectedMr) && (
<div className="flex items-center gap-2 px-2 h-8 rounded-md bg-muted/50 border border-border/50">
<Icon name="check" className="h-3.5 w-3.5 text-status-success shrink-0" />
<span className="typography-small truncate max-w-[150px]">
{selectedIssue
? t('session.gitlabIntegration.selected.issueNumber', { number: selectedIssue.number })
: t('session.gitlabIntegration.selected.mrNumber', { number: selectedMr?.number ?? '' })}
</span>
<button
onClick={handleClear}
className="text-muted-foreground hover:text-foreground shrink-0 p-0.5 rounded hover:bg-muted transition-colors"
>
<Icon name="close" className="h-3.5 w-3.5" />
</button>
</div>
)}
{/* Include Diff Checkbox - only show when MR tab is active and MR is selected */}
{activeTab === 'mrs' && selectedMr && (
<label className="flex items-center gap-2 cursor-pointer h-8">
<Checkbox
checked={includeDiff}
onChange={(checked) => setIncludeDiff(checked)}
ariaLabel={t('session.gitlabIntegration.includeDiffAria')}
/>
<span className="typography-small text-foreground">
{t('session.gitlabIntegration.includeDiff')}
</span>
</label>
)}
</div>
{/* Right side: Buttons */}
<div className={cn(
'flex gap-2',
isMobile ? 'w-full order-2' : 'justify-end'
)}>
<Button
variant="outline"
size="sm"
onClick={() => onOpenChange(false)}
className={cn(isMobile && 'flex-1')}
>
{t('session.gitlabIntegration.actions.cancel')}
</Button>
<Button
size="sm"
onClick={handleConfirm}
disabled={!canConfirm}
className={cn(isMobile && 'flex-1')}
>
{t('session.gitlabIntegration.actions.select')}
</Button>
</div>
</div>
);
return (
<>
{isMobile ? (
<MobileOverlayPanel
open={open}
title={t('session.gitlabIntegration.title')}
onClose={() => onOpenChange(false)}
footer={!isGitLabConnected ? undefined : footerContent}
renderHeader={(closeButton) => (
<div className="flex flex-col gap-2 px-3 py-2 border-b border-border/40">
<div className="flex items-center justify-between">
<h2 className="typography-ui-label font-semibold text-foreground">{t('session.gitlabIntegration.title')}</h2>
{closeButton}
</div>
{/* Tabs - using SortableTabsStrip */}
<div className="w-full">
<SortableTabsStrip
items={[
{ id: 'issues', label: t('session.gitlabIntegration.tabs.issues'), icon: <Icon name="git-branch" className="h-3.5 w-3.5" /> },
{ id: 'mrs', label: t('session.gitlabIntegration.tabs.mergeRequests'), icon: <Icon name="git-merge" className="h-3.5 w-3.5" /> },
]}
activeId={activeTab}
onSelect={(id) => {
setActiveTab(id as GitLabTab);
setSearchQuery('');
}}
variant="active-pill"
layoutMode="fit"
/>
</div>
{/* Selected Item Inline Display */}
{(selectedIssue || selectedMr) && (
<div className="flex items-center gap-2 px-2 py-1 rounded-md bg-muted/50 border border-border/50">
<Icon name="check" className="h-3.5 w-3.5 text-status-success shrink-0" />
<span className="typography-small truncate flex-1">
{selectedIssue
? t('session.gitlabIntegration.selected.issueNumber', { number: selectedIssue.number })
: t('session.gitlabIntegration.selected.mrNumber', { number: selectedMr?.number ?? '' })}
</span>
<button
onClick={handleClear}
className="text-muted-foreground hover:text-foreground shrink-0 p-0.5 rounded hover:bg-muted transition-colors"
>
<Icon name="close" className="h-3.5 w-3.5" />
</button>
</div>
)}
</div>
)}
>
{dialogContent}
</MobileOverlayPanel>
) : (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl max-h-[70vh] flex flex-col">
<DialogHeader className="flex flex-row items-center justify-between">
<div className="flex items-center gap-3">
<DialogTitle className="flex items-center gap-2 shrink-0">
<Icon name="git-branch" className="h-5 w-5" />
{t('session.gitlabIntegration.title')}
</DialogTitle>
{/* Tabs - using SortableTabsStrip */}
<div className="w-[220px]">
<SortableTabsStrip
items={[
{ id: 'issues', label: t('session.gitlabIntegration.tabs.issues'), icon: <Icon name="git-branch" className="h-3.5 w-3.5" /> },
{ id: 'mrs', label: t('session.gitlabIntegration.tabs.mergeRequests'), icon: <Icon name="git-merge" className="h-3.5 w-3.5" /> },
]}
activeId={activeTab}
onSelect={(id) => {
setActiveTab(id as GitLabTab);
setSearchQuery('');
}}
variant="active-pill"
layoutMode="fit"
/>
</div>
</div>
</DialogHeader>
{dialogContent}
{/* Footer */}
<DialogFooter className="mt-1">
{footerContent}
</DialogFooter>
</DialogContent>
</Dialog>
)}
</>
);
}
@@ -27,6 +27,7 @@ import { cn } from '@/lib/utils';
import { dropdownTriggerVariants } from '@/components/ui/dropdown-trigger'; import { dropdownTriggerVariants } from '@/components/ui/dropdown-trigger';
import { useProjectsStore } from '@/stores/useProjectsStore'; import { useProjectsStore } from '@/stores/useProjectsStore';
import { useGitHubAuthStore } from '@/stores/useGitHubAuthStore'; import { useGitHubAuthStore } from '@/stores/useGitHubAuthStore';
import { useGitLabAuthStore } from '@/stores/useGitLabAuthStore';
import { useUIStore } from '@/stores/useUIStore'; import { useUIStore } from '@/stores/useUIStore';
import { useSessionUIStore } from '@/sync/session-ui-store'; import { useSessionUIStore } from '@/sync/session-ui-store';
import { useSelectionStore } from '@/sync/selection-store'; import { useSelectionStore } from '@/sync/selection-store';
@@ -50,6 +51,7 @@ import {
import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs'; import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs';
import { useGitBranches, useGitStore, useGitLoadingBranches } from '@/stores/useGitStore'; import { useGitBranches, useGitStore, useGitLoadingBranches } from '@/stores/useGitStore';
import { GitHubIntegrationDialog } from './GitHubIntegrationDialog'; import { GitHubIntegrationDialog } from './GitHubIntegrationDialog';
import { GitLabIntegrationDialog } from './GitLabIntegrationDialog';
import { SortableTabsStrip } from '@/components/ui/sortable-tabs-strip'; import { SortableTabsStrip } from '@/components/ui/sortable-tabs-strip';
import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel'; import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
import { Icon } from "@/components/icon/Icon"; import { Icon } from "@/components/icon/Icon";
@@ -59,6 +61,10 @@ import type {
GitHubIssuesListResult, GitHubIssuesListResult,
GitHubPullRequestContextResult, GitHubPullRequestContextResult,
GitHubPullRequestSummary, GitHubPullRequestSummary,
GitLabIssue,
GitLabIssueComment,
GitLabIssuesListResult,
GitLabMergeRequestContextResult,
} from '@/lib/api/types'; } from '@/lib/api/types';
import type { ProjectRef } from '@/lib/worktrees/worktreeManager'; import type { ProjectRef } from '@/lib/worktrees/worktreeManager';
import { useI18n } from '@/lib/i18n'; import { useI18n } from '@/lib/i18n';
@@ -81,6 +87,9 @@ interface NewBranchState {
linkedIssue: GitHubIssue | null; linkedIssue: GitHubIssue | null;
linkedPr: GitHubPullRequestSummary | null; linkedPr: GitHubPullRequestSummary | null;
includePrDiff: boolean; includePrDiff: boolean;
linkedGitLabIssue: { number: number; title: string; url: string } | null;
linkedGitLabMr: { number: number; title: string; url: string; sourceBranch: string } | null;
includeGitLabMrDiff: boolean;
} }
// State for Existing Branch mode // State for Existing Branch mode
@@ -205,16 +214,35 @@ const buildPullRequestContextText = (payload: GitHubPullRequestContextResult) =>
return `GitHub pull request context (JSON)\n${JSON.stringify(payload, null, 2)}`; return `GitHub pull request context (JSON)\n${JSON.stringify(payload, null, 2)}`;
}; };
const buildGitLabIssueContextText = (args: {
repo: GitLabIssuesListResult['repo'] | undefined;
issue: GitLabIssue;
comments: GitLabIssueComment[];
}) => {
const payload = {
repo: args.repo ?? null,
issue: args.issue,
comments: args.comments,
};
return `GitLab issue context (JSON)\n${JSON.stringify(payload, null, 2)}`;
};
const buildGitLabMrContextText = (payload: GitLabMergeRequestContextResult) => {
return `GitLab merge request context (JSON)\n${JSON.stringify(payload, null, 2)}`;
};
export function NewWorktreeDialog({ export function NewWorktreeDialog({
open, open,
onOpenChange, onOpenChange,
onWorktreeCreated, onWorktreeCreated,
}: NewWorktreeDialogProps) { }: NewWorktreeDialogProps) {
const { t } = useI18n(); const { t } = useI18n();
const { github, git } = useRuntimeAPIs(); const { github, git, gitlab } = useRuntimeAPIs();
const isMobile = useUIStore((state) => state.isMobile); const isMobile = useUIStore((state) => state.isMobile);
const githubAuthStatus = useGitHubAuthStore((state) => state.status); const githubAuthStatus = useGitHubAuthStore((state) => state.status);
const githubAuthChecked = useGitHubAuthStore((state) => state.hasChecked); const githubAuthChecked = useGitHubAuthStore((state) => state.hasChecked);
const gitlabAuthStatus = useGitLabAuthStore((state) => state.status);
const gitlabAuthChecked = useGitLabAuthStore((state) => state.hasChecked);
const activeProject = useProjectsStore((state) => state.getActiveProject()); const activeProject = useProjectsStore((state) => state.getActiveProject());
const projectDirectory = activeProject?.path ?? null; const projectDirectory = activeProject?.path ?? null;
@@ -237,6 +265,9 @@ export function NewWorktreeDialog({
linkedIssue: null, linkedIssue: null,
linkedPr: null, linkedPr: null,
includePrDiff: false, includePrDiff: false,
linkedGitLabIssue: null,
linkedGitLabMr: null,
includeGitLabMrDiff: false,
}); });
const [existingBranchState, setExistingBranchState] = React.useState<ExistingBranchState>({ const [existingBranchState, setExistingBranchState] = React.useState<ExistingBranchState>({
@@ -286,6 +317,7 @@ export function NewWorktreeDialog({
}, [existingWorktreeNames]); }, [existingWorktreeNames]);
const [githubDialogOpen, setGithubDialogOpen] = React.useState(false); const [githubDialogOpen, setGithubDialogOpen] = React.useState(false);
const [gitlabDialogOpen, setGitlabDialogOpen] = React.useState(false);
// Desktop branch picker states // Desktop branch picker states
const [existingBranchDropdownOpen, setExistingBranchDropdownOpen] = React.useState(false); const [existingBranchDropdownOpen, setExistingBranchDropdownOpen] = React.useState(false);
@@ -477,8 +509,11 @@ export function NewWorktreeDialog({
issue: GitHubIssue | null; issue: GitHubIssue | null;
pr: GitHubPullRequestSummary | null; pr: GitHubPullRequestSummary | null;
includeDiff: boolean; includeDiff: boolean;
gitLabIssue: { number: number; title: string; url: string } | null;
gitLabMr: { number: number; title: string; url: string; sourceBranch: string } | null;
includeGitLabMrDiff: boolean;
}) => { }) => {
if (!projectDirectory || !github) { if (!projectDirectory) {
return; return;
} }
@@ -497,7 +532,7 @@ export function NewWorktreeDialog({
const variant = resolveDefaultVariant(providerID, modelID); const variant = resolveDefaultVariant(providerID, modelID);
if (args.issue) { if (args.issue) {
if (!github.issueGet || !github.issueComments) { if (!github || !github.issueGet || !github.issueComments) {
return; return;
} }
@@ -558,7 +593,7 @@ export function NewWorktreeDialog({
} }
if (args.pr) { if (args.pr) {
if (!github.prContext) { if (!github || !github.prContext) {
return; return;
} }
@@ -609,8 +644,125 @@ export function NewWorktreeDialog({
toast.success(t('session.newWorktree.toast.sessionFromPr')); toast.success(t('session.newWorktree.toast.sessionFromPr'));
} }
if (args.gitLabIssue) {
if (!gitlab || !gitlab.issueGet || !gitlab.issueComments) {
return;
}
const issueRes = await gitlab.issueGet(projectDirectory, args.gitLabIssue.number);
if (issueRes.connected === false || !issueRes.issue) {
throw new Error('Failed to load issue context');
}
const commentsRes = await gitlab.issueComments(projectDirectory, args.gitLabIssue.number);
if (commentsRes.connected === false) {
throw new Error('Failed to load issue comments');
}
const visiblePromptText = await renderMagicPrompt('gitlab.issue.review.visible', {
issue_number: String(args.gitLabIssue.number),
});
const instructionsText = await renderMagicPrompt('gitlab.issue.review.instructions');
const contextText = buildGitLabIssueContextText({
repo: issueRes.repo,
issue: issueRes.issue,
comments: commentsRes.comments ?? [],
});
await useSessionUIStore.getState().sendMessage(
visiblePromptText,
providerID,
modelID,
agentName,
undefined,
undefined,
[
{ text: instructionsText, synthetic: true },
{ text: contextText, synthetic: true },
],
variant,
undefined,
{ sessionId: args.sessionId },
);
// Record the thread this worktree session was created for, so it stays
// visible as a context source after the opening message scrolls away.
void sessionActions.setLinkedIssue(
args.sessionId,
args.directory,
buildLinkedIssue({
url: issueRes.issue.url,
number: issueRes.issue.number,
title: issueRes.issue.title,
kind: 'issue',
author: issueRes.issue.author
? { login: issueRes.issue.author.username, avatarUrl: issueRes.issue.author.avatarUrl }
: null,
linkedAt: Date.now(),
}),
true,
).catch(() => undefined);
toast.success(t('session.newWorktree.toast.sessionFromIssue'));
return;
}
if (args.gitLabMr) {
if (!gitlab || !gitlab.mrContext) {
return;
}
const mrContext = await gitlab.mrContext(projectDirectory, args.gitLabMr.number, {
includeDiff: args.includeGitLabMrDiff,
});
if (mrContext.connected === false || !mrContext.mr) {
throw new Error('Failed to load MR context');
}
const visiblePromptText = await renderMagicPrompt('gitlab.pr.review.visible', {
mr_number: String(args.gitLabMr.number),
});
const instructionsText = await renderMagicPrompt('gitlab.pr.review.instructions');
const contextText = buildGitLabMrContextText(mrContext);
await useSessionUIStore.getState().sendMessage(
visiblePromptText,
providerID,
modelID,
agentName,
undefined,
undefined,
[
{ text: instructionsText, synthetic: true },
{ text: contextText, synthetic: true },
],
variant,
undefined,
{ sessionId: args.sessionId },
);
void sessionActions.setLinkedIssue(
args.sessionId,
args.directory,
buildLinkedIssue({
url: mrContext.mr.url,
number: mrContext.mr.number,
title: mrContext.mr.title,
kind: 'pull',
author: mrContext.mr.author
? { login: mrContext.mr.author.username, avatarUrl: mrContext.mr.author.avatarUrl }
: null,
linkedAt: Date.now(),
}),
true,
).catch(() => undefined);
toast.success(t('session.newWorktree.toast.sessionFromMr'));
}
}, [ }, [
github, github,
gitlab,
projectDirectory, projectDirectory,
resolveDefaultAgentName, resolveDefaultAgentName,
resolveDefaultModelSelection, resolveDefaultModelSelection,
@@ -699,6 +851,9 @@ export function NewWorktreeDialog({
linkedIssue: null, linkedIssue: null,
linkedPr: null, linkedPr: null,
includePrDiff: false, includePrDiff: false,
linkedGitLabIssue: null,
linkedGitLabMr: null,
includeGitLabMrDiff: false,
}); });
}, [open, generateUniqueSlug]); }, [open, generateUniqueSlug]);
@@ -746,11 +901,13 @@ export function NewWorktreeDialog({
if (normalizedBranch && normalizedWorktree) { if (normalizedBranch && normalizedWorktree) {
const linkedPr = mode === 'new-branch' ? newBranchState.linkedPr : null; const linkedPr = mode === 'new-branch' ? newBranchState.linkedPr : null;
const prConfig = linkedPr ? resolvePrWorktreeConfig(linkedPr, localBranches, remoteBranches) : null; const prConfig = linkedPr ? resolvePrWorktreeConfig(linkedPr, localBranches, remoteBranches) : null;
const linkedGitLabMr = mode === 'new-branch' ? newBranchState.linkedGitLabMr : null;
const gitLabMrBranch = linkedGitLabMr ? normalizeBranchName(linkedGitLabMr.sourceBranch || '') : '';
const result = await validateWorktreeCreate(projectRef, { const result = await validateWorktreeCreate(projectRef, {
mode: mode === 'existing-branch' || prConfig ? 'existing' : 'new', mode: mode === 'existing-branch' || prConfig || gitLabMrBranch ? 'existing' : 'new',
branchName: normalizedBranch, branchName: normalizedBranch,
worktreeName: normalizedWorktree, worktreeName: normalizedWorktree,
existingBranch: prConfig?.existingBranch ?? (mode === 'existing-branch' ? normalizedBranch : undefined), existingBranch: prConfig?.existingBranch ?? (gitLabMrBranch || (mode === 'existing-branch' ? normalizedBranch : undefined)),
...(prConfig?.ensureRemoteName ? { ensureRemoteName: prConfig.ensureRemoteName } : {}), ...(prConfig?.ensureRemoteName ? { ensureRemoteName: prConfig.ensureRemoteName } : {}),
...(prConfig?.ensureRemoteUrl ? { ensureRemoteUrl: prConfig.ensureRemoteUrl } : {}), ...(prConfig?.ensureRemoteUrl ? { ensureRemoteUrl: prConfig.ensureRemoteUrl } : {}),
}); });
@@ -792,6 +949,7 @@ export function NewWorktreeDialog({
mode, mode,
newBranchState.branchName, newBranchState.branchName,
newBranchState.linkedPr, newBranchState.linkedPr,
newBranchState.linkedGitLabMr,
existingBranchState.selectedBranch, existingBranchState.selectedBranch,
currentState.worktreeName, currentState.worktreeName,
localBranches, localBranches,
@@ -860,7 +1018,10 @@ export function NewWorktreeDialog({
const linkedIssue = mode === 'new-branch' ? newBranchState.linkedIssue : null; const linkedIssue = mode === 'new-branch' ? newBranchState.linkedIssue : null;
const linkedPrState = mode === 'new-branch' ? newBranchState.linkedPr : null; const linkedPrState = mode === 'new-branch' ? newBranchState.linkedPr : null;
const includePrDiff = mode === 'new-branch' ? newBranchState.includePrDiff : false; const includePrDiff = mode === 'new-branch' ? newBranchState.includePrDiff : false;
const shouldCreateSession = Boolean(linkedIssue || linkedPrState); const linkedGitLabIssue = mode === 'new-branch' ? newBranchState.linkedGitLabIssue : null;
const linkedGitLabMr = mode === 'new-branch' ? newBranchState.linkedGitLabMr : null;
const includeGitLabMrDiff = mode === 'new-branch' ? newBranchState.includeGitLabMrDiff : false;
const shouldCreateSession = Boolean(linkedIssue || linkedPrState || linkedGitLabIssue || linkedGitLabMr);
const setupCommands = await getWorktreeSetupCommands(projectRef); const setupCommands = await getWorktreeSetupCommands(projectRef);
const sourceBranch = newBranchState.sourceBranch; const sourceBranch = newBranchState.sourceBranch;
@@ -886,6 +1047,23 @@ export function NewWorktreeDialog({
}; };
} }
if (linkedGitLabMr) {
const mrBranch = normalizeBranchName(linkedGitLabMr.sourceBranch || '');
if (!mrBranch) {
throw new Error('MR source branch is missing');
}
sourceLabel = mrBranch;
return {
preferredName: normalizedBranch || normalizedWorktree,
mode: 'existing' as const,
branchName: normalizedBranch,
worktreeName: normalizedWorktree,
existingBranch: mrBranch,
setupCommands,
returnAfterDirectoryCreated: true,
};
}
sourceLabel = mode === 'new-branch' ? sourceBranch : ''; sourceLabel = mode === 'new-branch' ? sourceBranch : '';
return { return {
preferredName: normalizedBranch || normalizedWorktree, preferredName: normalizedBranch || normalizedWorktree,
@@ -914,7 +1092,11 @@ export function NewWorktreeDialog({
? `#${linkedIssue.number} ${linkedIssue.title}`.trim() ? `#${linkedIssue.number} ${linkedIssue.title}`.trim()
: linkedPrState : linkedPrState
? `#${linkedPrState.number} ${linkedPrState.title}`.trim() ? `#${linkedPrState.number} ${linkedPrState.title}`.trim()
: t('session.newWorktree.newSessionTitle'); : linkedGitLabIssue
? `#${linkedGitLabIssue.number} ${linkedGitLabIssue.title}`.trim()
: linkedGitLabMr
? `!${linkedGitLabMr.number} ${linkedGitLabMr.title}`.trim()
: t('session.newWorktree.newSessionTitle');
const session = await sessionActions.createSession(sessionTitle, metadata.path, null); const session = await sessionActions.createSession(sessionTitle, metadata.path, null);
if (!session?.id) { if (!session?.id) {
@@ -963,9 +1145,16 @@ export function NewWorktreeDialog({
issue: linkedIssue, issue: linkedIssue,
pr: linkedPrState, pr: linkedPrState,
includeDiff: includePrDiff, includeDiff: includePrDiff,
gitLabIssue: linkedGitLabIssue,
gitLabMr: linkedGitLabMr,
includeGitLabMrDiff: includeGitLabMrDiff,
}).catch((error) => { }).catch((error) => {
const message = error instanceof Error ? error.message : t('session.newWorktree.error.sendGitHubContextFailed'); const isGitLabLink = Boolean(linkedGitLabIssue || linkedGitLabMr);
toast.error(t('session.newWorktree.error.sendGitHubContextFailed'), { description: message }); const errorKey = isGitLabLink
? 'session.newWorktree.error.sendGitLabContextFailed'
: 'session.newWorktree.error.sendGitHubContextFailed';
const message = error instanceof Error ? error.message : t(errorKey);
toast.error(t(errorKey), { description: message });
}); });
} else { } else {
onWorktreeCreated?.(metadata.path); onWorktreeCreated?.(metadata.path);
@@ -996,6 +1185,9 @@ export function NewWorktreeDialog({
linkedIssue: null, linkedIssue: null,
linkedPr: null, linkedPr: null,
includePrDiff: false, includePrDiff: false,
linkedGitLabIssue: null,
linkedGitLabMr: null,
includeGitLabMrDiff: false,
branchName: '', branchName: '',
})); }));
return; return;
@@ -1009,6 +1201,9 @@ export function NewWorktreeDialog({
linkedIssue: issue, linkedIssue: issue,
linkedPr: null, linkedPr: null,
includePrDiff: false, includePrDiff: false,
linkedGitLabIssue: null,
linkedGitLabMr: null,
includeGitLabMrDiff: false,
branchName: newBranchName, branchName: newBranchName,
worktreeName: slugifyWorktreeName(newBranchName), worktreeName: slugifyWorktreeName(newBranchName),
isSyncingWorktreeName: true, isSyncingWorktreeName: true,
@@ -1020,6 +1215,9 @@ export function NewWorktreeDialog({
linkedPr: pr, linkedPr: pr,
linkedIssue: null, linkedIssue: null,
includePrDiff: result.includeDiff ?? false, includePrDiff: result.includeDiff ?? false,
linkedGitLabIssue: null,
linkedGitLabMr: null,
includeGitLabMrDiff: false,
branchName: pr.head, branchName: pr.head,
worktreeName: slugifyWorktreeName(pr.head), worktreeName: slugifyWorktreeName(pr.head),
isSyncingWorktreeName: true, isSyncingWorktreeName: true,
@@ -1027,8 +1225,77 @@ export function NewWorktreeDialog({
} }
}; };
// Handle GitLab selection
const handleGitLabSelect = (result: {
type: 'issue';
number: number;
title: string;
url: string;
} | {
type: 'mr';
number: number;
title: string;
url: string;
sourceBranch: string;
includeDiff: boolean;
} | null) => {
if (!result) {
setNewBranchState(prev => ({
...prev,
linkedGitLabIssue: null,
linkedGitLabMr: null,
includeGitLabMrDiff: false,
linkedIssue: null,
linkedPr: null,
includePrDiff: false,
branchName: '',
}));
return;
}
if (result.type === 'issue') {
const newBranchName = `issue-${result.number}-${generateBranchSlug()}`;
setNewBranchState(prev => ({
...prev,
linkedGitLabIssue: {
number: result.number,
title: result.title,
url: result.url,
},
linkedGitLabMr: null,
includeGitLabMrDiff: false,
linkedIssue: null,
linkedPr: null,
includePrDiff: false,
branchName: newBranchName,
worktreeName: slugifyWorktreeName(newBranchName),
isSyncingWorktreeName: true,
}));
} else if (result.type === 'mr') {
setNewBranchState(prev => ({
...prev,
linkedGitLabMr: {
number: result.number,
title: result.title,
url: result.url,
sourceBranch: result.sourceBranch,
},
linkedGitLabIssue: null,
includeGitLabMrDiff: result.includeDiff,
linkedIssue: null,
linkedPr: null,
includePrDiff: false,
branchName: result.sourceBranch,
worktreeName: slugifyWorktreeName(result.sourceBranch),
isSyncingWorktreeName: true,
}));
}
};
// GitHub connection check // GitHub connection check
const isGitHubConnected = githubAuthChecked && githubAuthStatus?.connected === true; const isGitHubConnected = githubAuthChecked && githubAuthStatus?.connected === true;
// GitLab connection check
const isGitLabConnected = gitlabAuthChecked && gitlabAuthStatus?.connected === true;
// Check if form is valid for submission // Check if form is valid for submission
const isFormValid = mode === 'existing-branch' const isFormValid = mode === 'existing-branch'
@@ -1042,8 +1309,11 @@ export function NewWorktreeDialog({
...prev, ...prev,
linkedIssue: null, linkedIssue: null,
linkedPr: null, linkedPr: null,
linkedGitLabIssue: null,
linkedGitLabMr: null,
branchName: '', branchName: '',
includePrDiff: false, includePrDiff: false,
includeGitLabMrDiff: false,
isSyncingWorktreeName: true, isSyncingWorktreeName: true,
})); }));
}; };
@@ -1277,16 +1547,31 @@ export function NewWorktreeDialog({
<label className="typography-ui-label text-foreground block font-semibold"> <label className="typography-ui-label text-foreground block font-semibold">
{t('session.newWorktree.branchName')} {t('session.newWorktree.branchName')}
</label> </label>
{mode === 'new-branch' && isGitHubConnected && ( {mode === 'new-branch' && (isGitHubConnected || isGitLabConnected) && (
<Button <div className="flex items-center gap-2 flex-wrap">
variant="outline" {isGitHubConnected && (
size="sm" <Button
onClick={() => setGithubDialogOpen(true)} variant="outline"
className="gap-1.5 h-7" size="sm"
> onClick={() => setGithubDialogOpen(true)}
<Icon name="github" className="size-4 text-status-success" /> className="gap-1.5 h-7"
{newBranchState.linkedIssue || newBranchState.linkedPr ? t('session.newWorktree.actions.change') : t('session.newWorktree.actions.startFromGitHubIssuePr')} >
</Button> <Icon name="github" className="size-4 text-status-success" />
{newBranchState.linkedIssue || newBranchState.linkedPr ? t('session.newWorktree.actions.change') : t('session.newWorktree.actions.startFromGitHubIssuePr')}
</Button>
)}
{isGitLabConnected && (
<Button
variant="outline"
size="sm"
onClick={() => setGitlabDialogOpen(true)}
className="gap-1.5 h-7"
>
<Icon name="git-merge" className="size-4 text-status-success" />
{newBranchState.linkedGitLabIssue || newBranchState.linkedGitLabMr ? t('session.newWorktree.actions.change') : t('session.newWorktree.actions.startFromGitLabIssueMr')}
</Button>
)}
</div>
)} )}
</div> </div>
<Input <Input
@@ -1298,15 +1583,17 @@ export function NewWorktreeDialog({
isSyncingWorktreeName: true, isSyncingWorktreeName: true,
linkedIssue: null, linkedIssue: null,
linkedPr: null, linkedPr: null,
linkedGitLabIssue: null,
linkedGitLabMr: null,
})); }));
}} }}
onBlur={() => setValidation(prev => ({ ...prev, touched: true }))} onBlur={() => setValidation(prev => ({ ...prev, touched: true }))}
placeholder={t('session.newWorktree.branchNamePlaceholder')} placeholder={t('session.newWorktree.branchNamePlaceholder')}
disabled={!!newBranchState.linkedPr} disabled={!!newBranchState.linkedPr || !!newBranchState.linkedGitLabMr}
className={cn( className={cn(
'h-8', 'h-8',
validation.touched && validation.branchError && 'border-destructive', validation.touched && validation.branchError && 'border-destructive',
newBranchState.linkedPr && 'bg-muted text-muted-foreground' (newBranchState.linkedPr || newBranchState.linkedGitLabMr) && 'bg-muted text-muted-foreground'
)} )}
/> />
{newBranchState.linkedPr && ( {newBranchState.linkedPr && (
@@ -1317,6 +1604,14 @@ export function NewWorktreeDialog({
</span> </span>
</div> </div>
)} )}
{newBranchState.linkedGitLabMr && (
<div className="flex items-center gap-1.5 text-muted-foreground">
<Icon name="check" className="h-3.5 w-3.5 text-status-success" />
<span className="typography-micro">
{t('session.newWorktree.usingMrBranch', { branch: newBranchState.linkedGitLabMr.sourceBranch })}
</span>
</div>
)}
{newBranchState.linkedIssue && !newBranchState.linkedPr && ( {newBranchState.linkedIssue && !newBranchState.linkedPr && (
<div className="flex items-center gap-1.5 text-muted-foreground"> <div className="flex items-center gap-1.5 text-muted-foreground">
<Icon name="check" className="h-3.5 w-3.5 text-status-success" /> <Icon name="check" className="h-3.5 w-3.5 text-status-success" />
@@ -1325,6 +1620,14 @@ export function NewWorktreeDialog({
</span> </span>
</div> </div>
)} )}
{newBranchState.linkedGitLabIssue && !newBranchState.linkedGitLabMr && (
<div className="flex items-center gap-1.5 text-muted-foreground">
<Icon name="check" className="h-3.5 w-3.5 text-status-success" />
<span className="typography-micro">
{t('session.newWorktree.fromIssue', { number: newBranchState.linkedGitLabIssue.number, title: newBranchState.linkedGitLabIssue.title })}
</span>
</div>
)}
</div> </div>
)} )}
@@ -1383,8 +1686,8 @@ export function NewWorktreeDialog({
/> />
</div> </div>
{/* Source Branch - Only for New Branch mode, hide when PR is selected */} {/* Source Branch - Only for New Branch mode, hide when a linked PR/MR is selected */}
{mode === 'new-branch' && !newBranchState.linkedPr && ( {mode === 'new-branch' && !newBranchState.linkedPr && !newBranchState.linkedGitLabMr && (
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="typography-ui-label text-foreground block font-semibold"> <label className="typography-ui-label text-foreground block font-semibold">
{t('session.newWorktree.sourceBranch')} {t('session.newWorktree.sourceBranch')}
@@ -1523,11 +1826,15 @@ export function NewWorktreeDialog({
)} )}
{/* Linked Item Preview - Two row minimal display */} {/* Linked Item Preview - Two row minimal display */}
{(newBranchState.linkedIssue || newBranchState.linkedPr) && mode === 'new-branch' && ( {(newBranchState.linkedIssue || newBranchState.linkedPr || newBranchState.linkedGitLabIssue || newBranchState.linkedGitLabMr) && mode === 'new-branch' && (
<div className="mt-2 px-2 py-1.5 rounded bg-muted/30"> <div className="mt-2 px-2 py-1.5 rounded bg-muted/30">
{/* Row 1: Type, number, title, actions */} {/* Row 1: Type, number, title, actions */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Icon name="github" className="h-3.5 w-3.5 text-status-success shrink-0" /> {newBranchState.linkedIssue || newBranchState.linkedPr ? (
<Icon name="github" className="h-3.5 w-3.5 text-status-success shrink-0" />
) : (
<Icon name="git-merge" className="h-3.5 w-3.5 text-status-success shrink-0" />
)}
{newBranchState.linkedIssue && ( {newBranchState.linkedIssue && (
<span className="typography-micro text-muted-foreground shrink-0"> <span className="typography-micro text-muted-foreground shrink-0">
@@ -1539,13 +1846,23 @@ export function NewWorktreeDialog({
{t('session.newWorktree.prNumber', { number: newBranchState.linkedPr.number })} {t('session.newWorktree.prNumber', { number: newBranchState.linkedPr.number })}
</span> </span>
)} )}
{newBranchState.linkedGitLabIssue && (
<span className="typography-micro text-muted-foreground shrink-0">
{t('session.newWorktree.issueNumber', { number: newBranchState.linkedGitLabIssue.number })}
</span>
)}
{newBranchState.linkedGitLabMr && (
<span className="typography-micro text-muted-foreground shrink-0">
{t('session.newWorktree.mrNumber', { number: newBranchState.linkedGitLabMr.number })}
</span>
)}
<span className="typography-micro text-foreground truncate flex-1"> <span className="typography-micro text-foreground truncate flex-1">
{newBranchState.linkedIssue?.title || newBranchState.linkedPr?.title} {newBranchState.linkedIssue?.title || newBranchState.linkedPr?.title || newBranchState.linkedGitLabIssue?.title || newBranchState.linkedGitLabMr?.title}
</span> </span>
<a <a
href={newBranchState.linkedIssue?.url || newBranchState.linkedPr?.url} href={newBranchState.linkedIssue?.url || newBranchState.linkedPr?.url || newBranchState.linkedGitLabIssue?.url || newBranchState.linkedGitLabMr?.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-muted-foreground hover:text-foreground shrink-0" className="text-muted-foreground hover:text-foreground shrink-0"
@@ -1562,7 +1879,7 @@ export function NewWorktreeDialog({
</button> </button>
</div> </div>
{/* Row 2: PR branch info + diff indicator */} {/* Row 2: PR/MR branch info + diff indicator */}
{newBranchState.linkedPr && ( {newBranchState.linkedPr && (
<div className="flex items-center gap-2 mt-0.5 pl-5"> <div className="flex items-center gap-2 mt-0.5 pl-5">
<span className="typography-micro text-muted-foreground"> <span className="typography-micro text-muted-foreground">
@@ -1575,6 +1892,18 @@ export function NewWorktreeDialog({
)} )}
</div> </div>
)} )}
{newBranchState.linkedGitLabMr && (
<div className="flex items-center gap-2 mt-0.5 pl-5">
<span className="typography-micro text-muted-foreground">
{newBranchState.linkedGitLabMr.sourceBranch}
</span>
{newBranchState.includeGitLabMrDiff && (
<span className="typography-micro px-1 py-0.5 rounded bg-status-success/10 text-status-success">
{t('session.newWorktree.includeDiffBadge')}
</span>
)}
</div>
)}
</div> </div>
)} )}
</div> </div>
@@ -1746,16 +2075,31 @@ export function NewWorktreeDialog({
<label className="typography-ui-label text-foreground block font-semibold"> <label className="typography-ui-label text-foreground block font-semibold">
{t('session.newWorktree.branchName')} {t('session.newWorktree.branchName')}
</label> </label>
{mode === 'new-branch' && isGitHubConnected && ( {mode === 'new-branch' && (isGitHubConnected || isGitLabConnected) && (
<Button <div className="flex items-center gap-2 flex-wrap">
variant="outline" {isGitHubConnected && (
size="sm" <Button
onClick={() => setGithubDialogOpen(true)} variant="outline"
className="gap-1.5 h-7" size="sm"
> onClick={() => setGithubDialogOpen(true)}
<Icon name="github" className="size-4 text-status-success" /> className="gap-1.5 h-7"
{newBranchState.linkedIssue || newBranchState.linkedPr ? t('session.newWorktree.actions.change') : t('session.newWorktree.actions.startFromGitHubIssuePr')} >
</Button> <Icon name="github" className="size-4 text-status-success" />
{newBranchState.linkedIssue || newBranchState.linkedPr ? t('session.newWorktree.actions.change') : t('session.newWorktree.actions.startFromGitHubIssuePr')}
</Button>
)}
{isGitLabConnected && (
<Button
variant="outline"
size="sm"
onClick={() => setGitlabDialogOpen(true)}
className="gap-1.5 h-7"
>
<Icon name="git-merge" className="size-4 text-status-success" />
{newBranchState.linkedGitLabIssue || newBranchState.linkedGitLabMr ? t('session.newWorktree.actions.change') : t('session.newWorktree.actions.startFromGitLabIssueMr')}
</Button>
)}
</div>
)} )}
</div> </div>
<Input <Input
@@ -1767,15 +2111,17 @@ export function NewWorktreeDialog({
isSyncingWorktreeName: true, isSyncingWorktreeName: true,
linkedIssue: null, linkedIssue: null,
linkedPr: null, linkedPr: null,
linkedGitLabIssue: null,
linkedGitLabMr: null,
})); }));
}} }}
onBlur={() => setValidation(prev => ({ ...prev, touched: true }))} onBlur={() => setValidation(prev => ({ ...prev, touched: true }))}
placeholder={t('session.newWorktree.branchNamePlaceholder')} placeholder={t('session.newWorktree.branchNamePlaceholder')}
disabled={!!newBranchState.linkedPr} disabled={!!newBranchState.linkedPr || !!newBranchState.linkedGitLabMr}
className={cn( className={cn(
'h-8', 'h-8',
validation.touched && validation.branchError && 'border-destructive', validation.touched && validation.branchError && 'border-destructive',
newBranchState.linkedPr && 'bg-muted text-muted-foreground' (newBranchState.linkedPr || newBranchState.linkedGitLabMr) && 'bg-muted text-muted-foreground'
)} )}
/> />
{newBranchState.linkedPr && ( {newBranchState.linkedPr && (
@@ -1786,6 +2132,14 @@ export function NewWorktreeDialog({
</span> </span>
</div> </div>
)} )}
{newBranchState.linkedGitLabMr && (
<div className="flex items-center gap-1.5 text-muted-foreground">
<Icon name="check" className="h-3.5 w-3.5 text-status-success" />
<span className="typography-micro">
{t('session.newWorktree.usingMrBranch', { branch: newBranchState.linkedGitLabMr.sourceBranch })}
</span>
</div>
)}
{newBranchState.linkedIssue && !newBranchState.linkedPr && ( {newBranchState.linkedIssue && !newBranchState.linkedPr && (
<div className="flex items-center gap-1.5 text-muted-foreground"> <div className="flex items-center gap-1.5 text-muted-foreground">
<Icon name="check" className="h-3.5 w-3.5 text-status-success" /> <Icon name="check" className="h-3.5 w-3.5 text-status-success" />
@@ -1794,6 +2148,14 @@ export function NewWorktreeDialog({
</span> </span>
</div> </div>
)} )}
{newBranchState.linkedGitLabIssue && !newBranchState.linkedGitLabMr && (
<div className="flex items-center gap-1.5 text-muted-foreground">
<Icon name="check" className="h-3.5 w-3.5 text-status-success" />
<span className="typography-micro">
{t('session.newWorktree.fromIssue', { number: newBranchState.linkedGitLabIssue.number, title: newBranchState.linkedGitLabIssue.title })}
</span>
</div>
)}
</div> </div>
)} )}
@@ -1852,8 +2214,8 @@ export function NewWorktreeDialog({
/> />
</div> </div>
{/* Source Branch - Only for New Branch mode, hide when PR is selected */} {/* Source Branch - Only for New Branch mode, hide when a linked PR/MR is selected */}
{mode === 'new-branch' && !newBranchState.linkedPr && ( {mode === 'new-branch' && !newBranchState.linkedPr && !newBranchState.linkedGitLabMr && (
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="typography-ui-label text-foreground block font-semibold"> <label className="typography-ui-label text-foreground block font-semibold">
{t('session.newWorktree.sourceBranch')} {t('session.newWorktree.sourceBranch')}
@@ -1966,11 +2328,15 @@ export function NewWorktreeDialog({
)} )}
{/* Linked Item Preview - Two row minimal display */} {/* Linked Item Preview - Two row minimal display */}
{(newBranchState.linkedIssue || newBranchState.linkedPr) && mode === 'new-branch' && ( {(newBranchState.linkedIssue || newBranchState.linkedPr || newBranchState.linkedGitLabIssue || newBranchState.linkedGitLabMr) && mode === 'new-branch' && (
<div className="mt-2 px-2 py-1.5 rounded bg-muted/30"> <div className="mt-2 px-2 py-1.5 rounded bg-muted/30">
{/* Row 1: Type, number, title, actions */} {/* Row 1: Type, number, title, actions */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Icon name="github" className="h-3.5 w-3.5 text-status-success shrink-0" /> {newBranchState.linkedIssue || newBranchState.linkedPr ? (
<Icon name="github" className="h-3.5 w-3.5 text-status-success shrink-0" />
) : (
<Icon name="git-merge" className="h-3.5 w-3.5 text-status-success shrink-0" />
)}
{newBranchState.linkedIssue && ( {newBranchState.linkedIssue && (
<span className="typography-micro text-muted-foreground shrink-0"> <span className="typography-micro text-muted-foreground shrink-0">
@@ -1982,13 +2348,23 @@ export function NewWorktreeDialog({
{t('session.newWorktree.prNumber', { number: newBranchState.linkedPr.number })} {t('session.newWorktree.prNumber', { number: newBranchState.linkedPr.number })}
</span> </span>
)} )}
{newBranchState.linkedGitLabIssue && (
<span className="typography-micro text-muted-foreground shrink-0">
{t('session.newWorktree.issueNumber', { number: newBranchState.linkedGitLabIssue.number })}
</span>
)}
{newBranchState.linkedGitLabMr && (
<span className="typography-micro text-muted-foreground shrink-0">
{t('session.newWorktree.mrNumber', { number: newBranchState.linkedGitLabMr.number })}
</span>
)}
<span className="typography-micro text-foreground truncate flex-1"> <span className="typography-micro text-foreground truncate flex-1">
{newBranchState.linkedIssue?.title || newBranchState.linkedPr?.title} {newBranchState.linkedIssue?.title || newBranchState.linkedPr?.title || newBranchState.linkedGitLabIssue?.title || newBranchState.linkedGitLabMr?.title}
</span> </span>
<a <a
href={newBranchState.linkedIssue?.url || newBranchState.linkedPr?.url} href={newBranchState.linkedIssue?.url || newBranchState.linkedPr?.url || newBranchState.linkedGitLabIssue?.url || newBranchState.linkedGitLabMr?.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-muted-foreground hover:text-foreground shrink-0" className="text-muted-foreground hover:text-foreground shrink-0"
@@ -2005,7 +2381,7 @@ export function NewWorktreeDialog({
</button> </button>
</div> </div>
{/* Row 2: PR branch info + diff indicator */} {/* Row 2: PR/MR branch info + diff indicator */}
{newBranchState.linkedPr && ( {newBranchState.linkedPr && (
<div className="flex items-center gap-2 mt-0.5 pl-5"> <div className="flex items-center gap-2 mt-0.5 pl-5">
<span className="typography-micro text-muted-foreground"> <span className="typography-micro text-muted-foreground">
@@ -2018,6 +2394,18 @@ export function NewWorktreeDialog({
)} )}
</div> </div>
)} )}
{newBranchState.linkedGitLabMr && (
<div className="flex items-center gap-2 mt-0.5 pl-5">
<span className="typography-micro text-muted-foreground">
{newBranchState.linkedGitLabMr.sourceBranch}
</span>
{newBranchState.includeGitLabMrDiff && (
<span className="typography-micro px-1 py-0.5 rounded bg-status-success/10 text-status-success">
{t('session.newWorktree.includeDiffBadge')}
</span>
)}
</div>
)}
</div> </div>
)} )}
</div> </div>
@@ -2065,6 +2453,12 @@ export function NewWorktreeDialog({
onOpenChange={setGithubDialogOpen} onOpenChange={setGithubDialogOpen}
onSelect={handleGitHubSelect} onSelect={handleGitHubSelect}
/> />
<GitLabIntegrationDialog
open={gitlabDialogOpen}
onOpenChange={setGitlabDialogOpen}
onSelect={handleGitLabSelect}
/>
</> </>
); );
} }
@@ -242,6 +242,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': 'Eine Prompt-Vorlage zum Bearbeiten auswählen.', 'settings.magicPrompts.sidebar.description': 'Eine Prompt-Vorlage zum Bearbeiten auswählen.',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': 'Planung', 'settings.magicPrompts.sidebar.group.planning': 'Planung',
'settings.magicPrompts.sidebar.group.session': 'Sitzung', 'settings.magicPrompts.sidebar.group.session': 'Sitzung',
'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit-Generierung', 'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit-Generierung',
@@ -253,6 +254,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR-Review fehlgeschlagener Prüfungen', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR-Review fehlgeschlagener Prüfungen',
'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR-Kommentar-Review', 'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR-Kommentar-Review',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Einzelner PR-Kommentar-Review', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Einzelner PR-Kommentar-Review',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'MR-Review',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': 'Issue-Review',
'settings.magicPrompts.sidebar.item.planTodo': 'Aufgabenplanung', 'settings.magicPrompts.sidebar.item.planTodo': 'Aufgabenplanung',
'settings.magicPrompts.sidebar.item.planImprove': 'Plan verbessern', 'settings.magicPrompts.sidebar.item.planImprove': 'Plan verbessern',
'settings.magicPrompts.sidebar.item.planImplement': 'Plan umsetzen', 'settings.magicPrompts.sidebar.item.planImplement': 'Plan umsetzen',
@@ -2012,6 +2015,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'Eingabeaufforderungen zur Analyse von PR-Kommentaren.', 'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'Eingabeaufforderungen zur Analyse von PR-Kommentaren.',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Einzelner PR-Kommentar-Überprüfung', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Einzelner PR-Kommentar-Überprüfung',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Eingabeaufforderungen zur Analyse eines einzelnen PR-Kommentars.', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Eingabeaufforderungen zur Analyse eines einzelnen PR-Kommentars.',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'MR-Überprüfung',
'settings.magicPrompts.page.group.gitlabPrReview.description': 'Eingabeaufforderungen für den GitLab-MR-Überprüfungsprozess: Sichtbare Benutzernachricht + versteckte Anweisungspayload.',
'settings.magicPrompts.page.group.gitlabIssueReview.title': 'Problem-Überprüfung',
'settings.magicPrompts.page.group.gitlabIssueReview.description': 'Eingabeaufforderungen für den GitLab-Problem-Überprüfungsprozess: Sichtbare Benutzernachricht + versteckte Anweisungspayload.',
'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase Konfliktlösung', 'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase Konfliktlösung',
'settings.magicPrompts.page.group.gitConflictResolve.description': 'Eingabeaufforderungen beim Auflösen von Merge-/Rebase-Konflikten mit KI.', 'settings.magicPrompts.page.group.gitConflictResolve.description': 'Eingabeaufforderungen beim Auflösen von Merge-/Rebase-Konflikten mit KI.',
'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick-Konfliktlösung', 'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick-Konfliktlösung',
+28
View File
@@ -1726,7 +1726,9 @@ export const dict = {
'session.newWorktree.branchNamePlaceholder': 'feature/mein-geil-feature', 'session.newWorktree.branchNamePlaceholder': 'feature/mein-geil-feature',
'session.newWorktree.actions.change': 'Ändern', 'session.newWorktree.actions.change': 'Ändern',
'session.newWorktree.actions.startFromGitHubIssuePr': 'Starte von GitHub Issue/PR', 'session.newWorktree.actions.startFromGitHubIssuePr': 'Starte von GitHub Issue/PR',
'session.newWorktree.actions.startFromGitLabIssueMr': 'Starte von GitLab Issue/MR',
'session.newWorktree.usingPrBranch': 'Verwende PR-Branch: {branch}', 'session.newWorktree.usingPrBranch': 'Verwende PR-Branch: {branch}',
'session.newWorktree.usingMrBranch': 'Verwende MR-Branch: {branch}',
'session.newWorktree.fromIssue': 'Von Issue #{number}: {title}', 'session.newWorktree.fromIssue': 'Von Issue #{number}: {title}',
'session.newWorktree.worktreeDirectory': 'Worktree-Verzeichnis', 'session.newWorktree.worktreeDirectory': 'Worktree-Verzeichnis',
'session.newWorktree.worktreeDirectoryPlaceholder': 'mein-worktree-verzeichnis', 'session.newWorktree.worktreeDirectoryPlaceholder': 'mein-worktree-verzeichnis',
@@ -1737,6 +1739,7 @@ export const dict = {
'session.newWorktree.newBranchFromSource': 'Neuer Branch wird erstellt von {source}', 'session.newWorktree.newBranchFromSource': 'Neuer Branch wird erstellt von {source}',
'session.newWorktree.issueNumber': 'Issue #{number}', 'session.newWorktree.issueNumber': 'Issue #{number}',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.includeDiffBadge': '+diff', 'session.newWorktree.includeDiffBadge': '+diff',
'session.newWorktree.newSessionTitle': 'Neue Sitzung', 'session.newWorktree.newSessionTitle': 'Neue Sitzung',
'session.newWorktree.fromSource': 'von {source}', 'session.newWorktree.fromSource': 'von {source}',
@@ -1749,9 +1752,11 @@ export const dict = {
'session.newWorktree.error.branchNameRequired': 'Branch-Name ist erforderlich', 'session.newWorktree.error.branchNameRequired': 'Branch-Name ist erforderlich',
'session.newWorktree.error.worktreeDirectoryRequired': 'Worktree-Verzeichnis ist erforderlich', 'session.newWorktree.error.worktreeDirectoryRequired': 'Worktree-Verzeichnis ist erforderlich',
'session.newWorktree.error.sendGitHubContextFailed': 'Fehler beim Senden des GitHub-Kontexts', 'session.newWorktree.error.sendGitHubContextFailed': 'Fehler beim Senden des GitHub-Kontexts',
'session.newWorktree.error.sendGitLabContextFailed': 'Fehler beim Senden des GitLab-Kontexts',
'session.newWorktree.error.createWorktreeFailed': 'Fehler beim Erstellen des Worktrees', 'session.newWorktree.error.createWorktreeFailed': 'Fehler beim Erstellen des Worktrees',
'session.newWorktree.toast.sessionFromIssue': 'Sitzung aus Problem erstellt', 'session.newWorktree.toast.sessionFromIssue': 'Sitzung aus Problem erstellt',
'session.newWorktree.toast.sessionFromPr': 'Sitzung aus Pull Request erstellt', 'session.newWorktree.toast.sessionFromPr': 'Sitzung aus Pull Request erstellt',
'session.newWorktree.toast.sessionFromMr': 'Sitzung aus Merge Request erstellt',
'session.newWorktree.toast.worktreeCreated': 'Worktree erstellt', 'session.newWorktree.toast.worktreeCreated': 'Worktree erstellt',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} - im Hintergrund initialisiert', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} - im Hintergrund initialisiert',
'session.githubIntegration.title': 'Aus GitHub auswählen', 'session.githubIntegration.title': 'Aus GitHub auswählen',
@@ -1776,6 +1781,29 @@ export const dict = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': 'Branch ist bereits in einem Worktree ausgecheckt', 'session.githubIntegration.validation.branchAlreadyCheckedOut': 'Branch ist bereits in einem Worktree ausgecheckt',
'session.githubIntegration.validation.branchAlreadyExists': 'Branch existiert bereits lokal', 'session.githubIntegration.validation.branchAlreadyExists': 'Branch existiert bereits lokal',
'session.githubIntegration.validation.failed': 'Validierung fehlgeschlagen', 'session.githubIntegration.validation.failed': 'Validierung fehlgeschlagen',
'session.gitlabIntegration.title': 'Aus GitLab auswählen',
'session.gitlabIntegration.tabs.issues': 'Probleme',
'session.gitlabIntegration.tabs.mergeRequests': 'Merge Requests',
'session.gitlabIntegration.connect.title': 'Mit GitLab verbinden',
'session.gitlabIntegration.connect.description': 'Verknüpfen Sie Probleme oder Merge Requests, um Worktree-Details automatisch auszufüllen',
'session.gitlabIntegration.connect.action': 'GitLab verbinden',
'session.gitlabIntegration.search.issuesPlaceholder': 'GitLab-Probleme durchsuchen',
'session.gitlabIntegration.search.mrsPlaceholder': 'GitLab-Merge-Requests durchsuchen',
'session.gitlabIntegration.empty.noIssuesFound': 'Keine Probleme gefunden',
'session.gitlabIntegration.empty.noMergeRequestsFound': 'Keine Merge Requests gefunden',
'session.gitlabIntegration.actions.loadMore': 'Mehr laden',
'session.gitlabIntegration.actions.cancel': 'Abbrechen',
'session.gitlabIntegration.actions.select': 'Auswählen',
'session.gitlabIntegration.selected.issueNumber': 'Problem #{number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': 'MR-Diff in Sitzungskontext einbeziehen',
'session.gitlabIntegration.includeDiff': 'MR-Diff einbeziehen',
'session.gitlabIntegration.error.notConnected': 'GitLab nicht verbunden',
'session.gitlabIntegration.error.loadDataFailed': 'Fehler beim Laden der Daten',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': 'Branch ist bereits in einem Worktree ausgecheckt',
'session.gitlabIntegration.validation.branchAlreadyExists': 'Branch existiert bereits lokal',
'session.gitlabIntegration.validation.failed': 'Validierung fehlgeschlagen',
'session.gitlabIntegration.draftBadge': 'Entwurf',
'chat.fileAttachment.toast.attachFailed': 'Fehler beim Anhängen der Datei', 'chat.fileAttachment.toast.attachFailed': 'Fehler beim Anhängen der Datei',
'chat.fileAttachment.toast.someFilesSkipped': 'Einige Dateien wurden übersprungen:\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': 'Einige Dateien wurden übersprungen:\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': 'Fehler beim Auswählen von Dateien in VS Code', 'chat.fileAttachment.toast.vscodePickFailed': 'Fehler beim Auswählen von Dateien in VS Code',
@@ -258,6 +258,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': 'Select a prompt template to edit.', 'settings.magicPrompts.sidebar.description': 'Select a prompt template to edit.',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': 'Planning', 'settings.magicPrompts.sidebar.group.planning': 'Planning',
'settings.magicPrompts.sidebar.group.session': 'Session', 'settings.magicPrompts.sidebar.group.session': 'Session',
'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit Generation', 'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit Generation',
@@ -269,6 +270,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR Failed Checks Review', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR Failed Checks Review',
'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR Comments Review', 'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR Comments Review',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Single PR Comment Review', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Single PR Comment Review',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'MR Review',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': 'Issue Review',
'settings.magicPrompts.sidebar.item.planTodo': 'Todo Planning', 'settings.magicPrompts.sidebar.item.planTodo': 'Todo Planning',
'settings.magicPrompts.sidebar.item.planImprove': 'Improve Plan', 'settings.magicPrompts.sidebar.item.planImprove': 'Improve Plan',
'settings.magicPrompts.sidebar.item.planImplement': 'Implement Plan', 'settings.magicPrompts.sidebar.item.planImplement': 'Implement Plan',
@@ -2099,6 +2102,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'Prompts used for PR comments analysis.', 'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'Prompts used for PR comments analysis.',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Single PR Comment Review', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Single PR Comment Review',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Prompts used for single PR comment analysis.', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Prompts used for single PR comment analysis.',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'MR Review',
'settings.magicPrompts.page.group.gitlabPrReview.description': 'Prompts used for GitLab merge request review flow: visible user message + hidden instruction payload.',
'settings.magicPrompts.page.group.gitlabIssueReview.title': 'Issue Review',
'settings.magicPrompts.page.group.gitlabIssueReview.description': 'Prompts used for GitLab issue review flow: visible user message + hidden instruction payload.',
'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase Conflict Resolution', 'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase Conflict Resolution',
'settings.magicPrompts.page.group.gitConflictResolve.description': 'Prompts used when resolving merge/rebase conflicts with AI.', 'settings.magicPrompts.page.group.gitConflictResolve.description': 'Prompts used when resolving merge/rebase conflicts with AI.',
'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick Conflict Resolution', 'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick Conflict Resolution',
+28
View File
@@ -1883,7 +1883,9 @@ export const dict = {
'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature', 'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature',
'session.newWorktree.actions.change': 'Change', 'session.newWorktree.actions.change': 'Change',
'session.newWorktree.actions.startFromGitHubIssuePr': 'Start from GitHub Issue/PR', 'session.newWorktree.actions.startFromGitHubIssuePr': 'Start from GitHub Issue/PR',
'session.newWorktree.actions.startFromGitLabIssueMr': 'Start from GitLab Issue/MR',
'session.newWorktree.usingPrBranch': 'Using PR branch: {branch}', 'session.newWorktree.usingPrBranch': 'Using PR branch: {branch}',
'session.newWorktree.usingMrBranch': 'Using MR branch: {branch}',
'session.newWorktree.fromIssue': 'From issue #{number}: {title}', 'session.newWorktree.fromIssue': 'From issue #{number}: {title}',
'session.newWorktree.worktreeDirectory': 'Worktree Directory', 'session.newWorktree.worktreeDirectory': 'Worktree Directory',
'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory', 'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory',
@@ -1894,6 +1896,7 @@ export const dict = {
'session.newWorktree.newBranchFromSource': 'New branch will be created from {source}', 'session.newWorktree.newBranchFromSource': 'New branch will be created from {source}',
'session.newWorktree.issueNumber': 'Issue #{number}', 'session.newWorktree.issueNumber': 'Issue #{number}',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.includeDiffBadge': '+diff', 'session.newWorktree.includeDiffBadge': '+diff',
'session.newWorktree.newSessionTitle': 'New session', 'session.newWorktree.newSessionTitle': 'New session',
'session.newWorktree.fromSource': 'from {source}', 'session.newWorktree.fromSource': 'from {source}',
@@ -1906,9 +1909,11 @@ export const dict = {
'session.newWorktree.error.branchNameRequired': 'Branch name is required', 'session.newWorktree.error.branchNameRequired': 'Branch name is required',
'session.newWorktree.error.worktreeDirectoryRequired': 'Worktree directory is required', 'session.newWorktree.error.worktreeDirectoryRequired': 'Worktree directory is required',
'session.newWorktree.error.sendGitHubContextFailed': 'Failed to send GitHub context', 'session.newWorktree.error.sendGitHubContextFailed': 'Failed to send GitHub context',
'session.newWorktree.error.sendGitLabContextFailed': 'Failed to send GitLab context',
'session.newWorktree.error.createWorktreeFailed': 'Failed to create worktree', 'session.newWorktree.error.createWorktreeFailed': 'Failed to create worktree',
'session.newWorktree.toast.sessionFromIssue': 'Session created from issue', 'session.newWorktree.toast.sessionFromIssue': 'Session created from issue',
'session.newWorktree.toast.sessionFromPr': 'Session created from PR', 'session.newWorktree.toast.sessionFromPr': 'Session created from PR',
'session.newWorktree.toast.sessionFromMr': 'Session created from merge request',
'session.newWorktree.toast.worktreeCreated': 'Worktree created', 'session.newWorktree.toast.worktreeCreated': 'Worktree created',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} - bootstrapping in background', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} - bootstrapping in background',
'session.githubIntegration.title': 'Select from GitHub', 'session.githubIntegration.title': 'Select from GitHub',
@@ -1933,6 +1938,29 @@ export const dict = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': 'Branch is already checked out in a worktree', 'session.githubIntegration.validation.branchAlreadyCheckedOut': 'Branch is already checked out in a worktree',
'session.githubIntegration.validation.branchAlreadyExists': 'Branch already exists locally', 'session.githubIntegration.validation.branchAlreadyExists': 'Branch already exists locally',
'session.githubIntegration.validation.failed': 'Validation failed', 'session.githubIntegration.validation.failed': 'Validation failed',
'session.gitlabIntegration.title': 'Select from GitLab',
'session.gitlabIntegration.tabs.issues': 'Issues',
'session.gitlabIntegration.tabs.mergeRequests': 'Merge Requests',
'session.gitlabIntegration.connect.title': 'Connect to GitLab',
'session.gitlabIntegration.connect.description': 'Link issues or merge requests to auto-fill worktree details',
'session.gitlabIntegration.connect.action': 'Connect GitLab',
'session.gitlabIntegration.search.issuesPlaceholder': 'Search GitLab issues',
'session.gitlabIntegration.search.mrsPlaceholder': 'Search GitLab merge requests',
'session.gitlabIntegration.empty.noIssuesFound': 'No issues found',
'session.gitlabIntegration.empty.noMergeRequestsFound': 'No merge requests found',
'session.gitlabIntegration.actions.loadMore': 'Load more',
'session.gitlabIntegration.actions.cancel': 'Cancel',
'session.gitlabIntegration.actions.select': 'Select',
'session.gitlabIntegration.selected.issueNumber': 'Issue #{number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': 'Include MR diff in session context',
'session.gitlabIntegration.includeDiff': 'Include MR diff',
'session.gitlabIntegration.error.notConnected': 'GitLab not connected',
'session.gitlabIntegration.error.loadDataFailed': 'Failed to load data',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': 'Branch is already checked out in a worktree',
'session.gitlabIntegration.validation.branchAlreadyExists': 'Branch already exists locally',
'session.gitlabIntegration.validation.failed': 'Validation failed',
'session.gitlabIntegration.draftBadge': 'Draft',
'chat.fileAttachment.toast.attachFailed': 'Failed to attach file', 'chat.fileAttachment.toast.attachFailed': 'Failed to attach file',
'chat.fileAttachment.toast.someFilesSkipped': 'Some files were skipped:\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': 'Some files were skipped:\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': 'Failed to pick files in VS Code', 'chat.fileAttachment.toast.vscodePickFailed': 'Failed to pick files in VS Code',
@@ -226,6 +226,7 @@ export const settingsDict = {
"settings.magicPrompts.sidebar.description": "Selecciona una plantilla de prompt para editar.", "settings.magicPrompts.sidebar.description": "Selecciona una plantilla de prompt para editar.",
"settings.magicPrompts.sidebar.group.git": "Git", "settings.magicPrompts.sidebar.group.git": "Git",
"settings.magicPrompts.sidebar.group.github": "GitHub", "settings.magicPrompts.sidebar.group.github": "GitHub",
"settings.magicPrompts.sidebar.group.gitlab": "GitLab",
"settings.magicPrompts.sidebar.group.planning": "Planificación", "settings.magicPrompts.sidebar.group.planning": "Planificación",
"settings.magicPrompts.sidebar.group.session": "Sesión", "settings.magicPrompts.sidebar.group.session": "Sesión",
"settings.magicPrompts.sidebar.item.gitCommitGenerate": "Generación de commit", "settings.magicPrompts.sidebar.item.gitCommitGenerate": "Generación de commit",
@@ -237,6 +238,8 @@ export const settingsDict = {
"settings.magicPrompts.sidebar.item.githubPrFailedChecksReview": "Revisión de PR con comprobaciones fallidas", "settings.magicPrompts.sidebar.item.githubPrFailedChecksReview": "Revisión de PR con comprobaciones fallidas",
"settings.magicPrompts.sidebar.item.githubPrCommentsReview": "Revisión de comentarios de PR", "settings.magicPrompts.sidebar.item.githubPrCommentsReview": "Revisión de comentarios de PR",
"settings.magicPrompts.sidebar.item.githubSinglePrCommentReview": "Revisión de comentario único de PR", "settings.magicPrompts.sidebar.item.githubSinglePrCommentReview": "Revisión de comentario único de PR",
"settings.magicPrompts.sidebar.item.gitlabPrReview": "Revisión de MR",
"settings.magicPrompts.sidebar.item.gitlabIssueReview": "Revisión de issue",
"settings.magicPrompts.sidebar.item.planTodo": "Planificar Todo", "settings.magicPrompts.sidebar.item.planTodo": "Planificar Todo",
"settings.magicPrompts.sidebar.item.planImprove": "Mejorar plan", "settings.magicPrompts.sidebar.item.planImprove": "Mejorar plan",
"settings.magicPrompts.sidebar.item.planImplement": "Implementar plan", "settings.magicPrompts.sidebar.item.planImplement": "Implementar plan",
@@ -2076,6 +2079,10 @@ export const settingsDict = {
"settings.magicPrompts.page.group.githubPrCommentsReview.description": "Prompts usados para el análisis de comentarios de un PR.", "settings.magicPrompts.page.group.githubPrCommentsReview.description": "Prompts usados para el análisis de comentarios de un PR.",
"settings.magicPrompts.page.group.githubSinglePrCommentReview.title": "Revisión de comentario único de PR", "settings.magicPrompts.page.group.githubSinglePrCommentReview.title": "Revisión de comentario único de PR",
"settings.magicPrompts.page.group.githubSinglePrCommentReview.description": "Prompts usados para el análisis de un comentario único de un PR.", "settings.magicPrompts.page.group.githubSinglePrCommentReview.description": "Prompts usados para el análisis de un comentario único de un PR.",
"settings.magicPrompts.page.group.gitlabPrReview.title": "Revisión de MR",
"settings.magicPrompts.page.group.gitlabPrReview.description": "Prompts usados para el flujo de revisión de MR de GitLab: mensaje visible del usuario + carga de instrucciones ocultas.",
"settings.magicPrompts.page.group.gitlabIssueReview.title": "Revisión de issue",
"settings.magicPrompts.page.group.gitlabIssueReview.description": "Prompts usados para el flujo de revisión de issue de GitLab: mensaje visible del usuario + carga de instrucciones ocultas.",
"settings.magicPrompts.page.group.gitConflictResolve.title": "Resolución de conflictos de merge/rebase", "settings.magicPrompts.page.group.gitConflictResolve.title": "Resolución de conflictos de merge/rebase",
"settings.magicPrompts.page.group.gitConflictResolve.description": "Prompts usados al resolver conflictos de merge/rebase con IA.", "settings.magicPrompts.page.group.gitConflictResolve.description": "Prompts usados al resolver conflictos de merge/rebase con IA.",
"settings.magicPrompts.page.group.gitCherrypickConflictResolve.title": "Resolución de conflictos de cherry-pick", "settings.magicPrompts.page.group.gitCherrypickConflictResolve.title": "Resolución de conflictos de cherry-pick",
+28
View File
@@ -1861,7 +1861,9 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.branchNamePlaceholder": "feature/my-awesome-feature", "session.newWorktree.branchNamePlaceholder": "feature/my-awesome-feature",
"session.newWorktree.actions.change": "Cambiar", "session.newWorktree.actions.change": "Cambiar",
"session.newWorktree.actions.startFromGitHubIssuePr": "Iniciar desde Issue/PR de GitHub", "session.newWorktree.actions.startFromGitHubIssuePr": "Iniciar desde Issue/PR de GitHub",
"session.newWorktree.actions.startFromGitLabIssueMr": "Iniciar desde Issue/MR de GitLab",
"session.newWorktree.usingPrBranch": "Usando rama de la PR: {branch}", "session.newWorktree.usingPrBranch": "Usando rama de la PR: {branch}",
"session.newWorktree.usingMrBranch": "Usando rama del MR: {branch}",
"session.newWorktree.fromIssue": "De issue #{number}: {title}", "session.newWorktree.fromIssue": "De issue #{number}: {title}",
"session.newWorktree.worktreeDirectory": "Directorio del worktree", "session.newWorktree.worktreeDirectory": "Directorio del worktree",
"session.newWorktree.worktreeDirectoryPlaceholder": "my-worktree-directory", "session.newWorktree.worktreeDirectoryPlaceholder": "my-worktree-directory",
@@ -1872,6 +1874,7 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.newBranchFromSource": "Se creará una nueva rama desde {source}", "session.newWorktree.newBranchFromSource": "Se creará una nueva rama desde {source}",
"session.newWorktree.issueNumber": "Issue #{number}", "session.newWorktree.issueNumber": "Issue #{number}",
"session.newWorktree.prNumber": "PR #{number}", "session.newWorktree.prNumber": "PR #{number}",
"session.newWorktree.mrNumber": "MR #{number}",
"session.newWorktree.includeDiffBadge": "+diff", "session.newWorktree.includeDiffBadge": "+diff",
"session.newWorktree.newSessionTitle": "Nueva sesión", "session.newWorktree.newSessionTitle": "Nueva sesión",
"session.newWorktree.fromSource": "desde {source}", "session.newWorktree.fromSource": "desde {source}",
@@ -1884,9 +1887,11 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.error.branchNameRequired": "Se requiere el nombre de la rama", "session.newWorktree.error.branchNameRequired": "Se requiere el nombre de la rama",
"session.newWorktree.error.worktreeDirectoryRequired": "Se requiere el directorio del worktree", "session.newWorktree.error.worktreeDirectoryRequired": "Se requiere el directorio del worktree",
"session.newWorktree.error.sendGitHubContextFailed": "No se pudo enviar el contexto de GitHub", "session.newWorktree.error.sendGitHubContextFailed": "No se pudo enviar el contexto de GitHub",
"session.newWorktree.error.sendGitLabContextFailed": "No se pudo enviar el contexto de GitLab",
"session.newWorktree.error.createWorktreeFailed": "No se pudo crear el worktree", "session.newWorktree.error.createWorktreeFailed": "No se pudo crear el worktree",
"session.newWorktree.toast.sessionFromIssue": "Sesión creada desde issue", "session.newWorktree.toast.sessionFromIssue": "Sesión creada desde issue",
"session.newWorktree.toast.sessionFromPr": "Sesión creada desde PR", "session.newWorktree.toast.sessionFromPr": "Sesión creada desde PR",
"session.newWorktree.toast.sessionFromMr": "Sesión creada desde merge request",
"session.newWorktree.toast.worktreeCreated": "Worktree creado", "session.newWorktree.toast.worktreeCreated": "Worktree creado",
"session.newWorktree.toast.worktreeCreatedDescription": "{target} - configurando en segundo plano", "session.newWorktree.toast.worktreeCreatedDescription": "{target} - configurando en segundo plano",
"session.githubIntegration.title": "Seleccionar desde GitHub", "session.githubIntegration.title": "Seleccionar desde GitHub",
@@ -1911,6 +1916,29 @@ export const dict: Record<I18nKey, string> = {
"session.githubIntegration.validation.branchAlreadyCheckedOut": "La rama ya está en uso en un worktree", "session.githubIntegration.validation.branchAlreadyCheckedOut": "La rama ya está en uso en un worktree",
"session.githubIntegration.validation.branchAlreadyExists": "La rama ya existe localmente", "session.githubIntegration.validation.branchAlreadyExists": "La rama ya existe localmente",
"session.githubIntegration.validation.failed": "No se pudo validar", "session.githubIntegration.validation.failed": "No se pudo validar",
"session.gitlabIntegration.title": "Seleccionar desde GitLab",
"session.gitlabIntegration.tabs.issues": "Issues",
"session.gitlabIntegration.tabs.mergeRequests": "Merge Requests",
"session.gitlabIntegration.connect.title": "Conectar a GitLab",
"session.gitlabIntegration.connect.description": "Vincula issues o merge requests para rellenar automáticamente los detalles del worktree",
"session.gitlabIntegration.connect.action": "Conectar a GitLab",
"session.gitlabIntegration.search.issuesPlaceholder": "Buscar issues de GitLab",
"session.gitlabIntegration.search.mrsPlaceholder": "Buscar merge requests de GitLab",
"session.gitlabIntegration.empty.noIssuesFound": "No se encontraron issues",
"session.gitlabIntegration.empty.noMergeRequestsFound": "No se encontraron merge requests",
"session.gitlabIntegration.actions.loadMore": "Cargar más",
"session.gitlabIntegration.actions.cancel": "Cancelar",
"session.gitlabIntegration.actions.select": "Seleccionar",
"session.gitlabIntegration.selected.issueNumber": "Issue #{number}",
"session.gitlabIntegration.selected.mrNumber": "MR #{number}",
"session.gitlabIntegration.includeDiffAria": "Incluir diff del MR en el contexto de la sesión",
"session.gitlabIntegration.includeDiff": "Incluir diff del MR",
"session.gitlabIntegration.error.notConnected": "GitLab no está conectado",
"session.gitlabIntegration.error.loadDataFailed": "No se pudieron cargar los datos",
"session.gitlabIntegration.validation.branchAlreadyCheckedOut": "La rama ya está en uso en un worktree",
"session.gitlabIntegration.validation.branchAlreadyExists": "La rama ya existe localmente",
"session.gitlabIntegration.validation.failed": "No se pudo validar",
"session.gitlabIntegration.draftBadge": "Borrador",
"chat.fileAttachment.toast.attachFailed": "No se pudo adjuntar el archivo", "chat.fileAttachment.toast.attachFailed": "No se pudo adjuntar el archivo",
"chat.fileAttachment.toast.someFilesSkipped": "Algunos archivos se omitieron:\n{summary}", "chat.fileAttachment.toast.someFilesSkipped": "Algunos archivos se omitieron:\n{summary}",
"chat.fileAttachment.toast.vscodePickFailed": "No se pudieron seleccionar archivos en VS Code", "chat.fileAttachment.toast.vscodePickFailed": "No se pudieron seleccionar archivos en VS Code",
@@ -249,6 +249,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': 'Sélectionnez un modèle de prompt à modifier.', 'settings.magicPrompts.sidebar.description': 'Sélectionnez un modèle de prompt à modifier.',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': 'Planification', 'settings.magicPrompts.sidebar.group.planning': 'Planification',
'settings.magicPrompts.sidebar.group.session': 'Session', 'settings.magicPrompts.sidebar.group.session': 'Session',
'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Génération de commit', 'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Génération de commit',
@@ -260,6 +261,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'Examen des checks PR en échec', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'Examen des checks PR en échec',
'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'Examen des commentaires PR', 'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'Examen des commentaires PR',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Examen des commentaires PR uniques', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Examen des commentaires PR uniques',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'Revue de MR',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': 'Examen du problème',
'settings.magicPrompts.sidebar.item.planTodo': 'Planification des tâches', 'settings.magicPrompts.sidebar.item.planTodo': 'Planification des tâches',
'settings.magicPrompts.sidebar.item.planImprove': 'Améliorer le plan', 'settings.magicPrompts.sidebar.item.planImprove': 'Améliorer le plan',
'settings.magicPrompts.sidebar.item.planImplement': 'Plan de mise en œuvre', 'settings.magicPrompts.sidebar.item.planImplement': 'Plan de mise en œuvre',
@@ -1978,6 +1981,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'Prompts utilisés pour lanalyse des commentaires PR.', 'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'Prompts utilisés pour lanalyse des commentaires PR.',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Examen des commentaires PR uniques', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Examen des commentaires PR uniques',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Prompts utilisés pour lanalyse dun seul commentaire PR.', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Prompts utilisés pour lanalyse dun seul commentaire PR.',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'Revue de MR',
'settings.magicPrompts.page.group.gitlabPrReview.description': 'Prompts utilisés pour le flux de revue des MR GitLab : message utilisateur visible + charge utile d\'instruction cachée.',
'settings.magicPrompts.page.group.gitlabIssueReview.title': 'Examen du problème',
'settings.magicPrompts.page.group.gitlabIssueReview.description': 'Prompts utilisés pour le flux d\'examen des issues GitLab : message utilisateur visible + charge utile d\'instruction masquée.',
'settings.magicPrompts.page.group.gitConflictResolve.title': 'Résolution des conflits de fusion/rebase', 'settings.magicPrompts.page.group.gitConflictResolve.title': 'Résolution des conflits de fusion/rebase',
'settings.magicPrompts.page.group.gitConflictResolve.description': 'Prompts utilisés lors de la résolution des conflits de fusion/rebase avec l\'IA.', 'settings.magicPrompts.page.group.gitConflictResolve.description': 'Prompts utilisés lors de la résolution des conflits de fusion/rebase avec l\'IA.',
'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Résolution des conflits par sélection', 'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Résolution des conflits par sélection',
+28
View File
@@ -1641,7 +1641,9 @@ export const dict = {
'session.newWorktree.branchNamePlaceholder': 'fonctionnalité/ma-fonctionnalité-géniale', 'session.newWorktree.branchNamePlaceholder': 'fonctionnalité/ma-fonctionnalité-géniale',
'session.newWorktree.actions.change': 'Changement', 'session.newWorktree.actions.change': 'Changement',
'session.newWorktree.actions.startFromGitHubIssuePr': 'À partir de GitHub Issue/PR', 'session.newWorktree.actions.startFromGitHubIssuePr': 'À partir de GitHub Issue/PR',
'session.newWorktree.actions.startFromGitLabIssueMr': 'À partir de GitLab Issue/MR',
'session.newWorktree.usingPrBranch': 'Utilisation de la branche PR : {branch}', 'session.newWorktree.usingPrBranch': 'Utilisation de la branche PR : {branch}',
'session.newWorktree.usingMrBranch': 'Utilisation de la branche MR : {branch}',
'session.newWorktree.fromIssue': 'Extrait du numéro {number} : {title}', 'session.newWorktree.fromIssue': 'Extrait du numéro {number} : {title}',
'session.newWorktree.worktreeDirectory': 'Répertoire du worktree', 'session.newWorktree.worktreeDirectory': 'Répertoire du worktree',
'session.newWorktree.worktreeDirectoryPlaceholder': 'mon-répertoire-worktree', 'session.newWorktree.worktreeDirectoryPlaceholder': 'mon-répertoire-worktree',
@@ -1652,6 +1654,7 @@ export const dict = {
'session.newWorktree.newBranchFromSource': 'Une nouvelle branche sera créée à partir de {source}', 'session.newWorktree.newBranchFromSource': 'Une nouvelle branche sera créée à partir de {source}',
'session.newWorktree.issueNumber': 'Numéro {number}', 'session.newWorktree.issueNumber': 'Numéro {number}',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.includeDiffBadge': '+diff', 'session.newWorktree.includeDiffBadge': '+diff',
'session.newWorktree.newSessionTitle': 'Nouvelle session', 'session.newWorktree.newSessionTitle': 'Nouvelle session',
'session.newWorktree.fromSource': 'de {source}', 'session.newWorktree.fromSource': 'de {source}',
@@ -1664,9 +1667,11 @@ export const dict = {
'session.newWorktree.error.branchNameRequired': 'Le nom de la branche est requis', 'session.newWorktree.error.branchNameRequired': 'Le nom de la branche est requis',
'session.newWorktree.error.worktreeDirectoryRequired': 'Le répertoire du worktree est requis', 'session.newWorktree.error.worktreeDirectoryRequired': 'Le répertoire du worktree est requis',
'session.newWorktree.error.sendGitHubContextFailed': 'Échec de l\'envoi du contexte GitHub', 'session.newWorktree.error.sendGitHubContextFailed': 'Échec de l\'envoi du contexte GitHub',
'session.newWorktree.error.sendGitLabContextFailed': 'Échec de l\'envoi du contexte GitLab',
'session.newWorktree.error.createWorktreeFailed': 'Échec de la création du worktree', 'session.newWorktree.error.createWorktreeFailed': 'Échec de la création du worktree',
'session.newWorktree.toast.sessionFromIssue': 'Session créée à partir du problème', 'session.newWorktree.toast.sessionFromIssue': 'Session créée à partir du problème',
'session.newWorktree.toast.sessionFromPr': 'Session créée à partir de PR', 'session.newWorktree.toast.sessionFromPr': 'Session créée à partir de PR',
'session.newWorktree.toast.sessionFromMr': 'Session créée à partir de la merge request',
'session.newWorktree.toast.worktreeCreated': 'Worktree créé', 'session.newWorktree.toast.worktreeCreated': 'Worktree créé',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} - démarrage en arrière-plan', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} - démarrage en arrière-plan',
'session.githubIntegration.title': 'Sélectionnez parmi GitHub', 'session.githubIntegration.title': 'Sélectionnez parmi GitHub',
@@ -1691,6 +1696,29 @@ export const dict = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': 'La branche est déjà checkout dans un worktree', 'session.githubIntegration.validation.branchAlreadyCheckedOut': 'La branche est déjà checkout dans un worktree',
'session.githubIntegration.validation.branchAlreadyExists': 'Une branche existe déjà localement', 'session.githubIntegration.validation.branchAlreadyExists': 'Une branche existe déjà localement',
'session.githubIntegration.validation.failed': 'Échec de la validation', 'session.githubIntegration.validation.failed': 'Échec de la validation',
'session.gitlabIntegration.title': 'Sélectionnez parmi GitLab',
'session.gitlabIntegration.tabs.issues': 'Problèmes',
'session.gitlabIntegration.tabs.mergeRequests': 'Merge Requests',
'session.gitlabIntegration.connect.title': 'Connectez-vous à GitLab',
'session.gitlabIntegration.connect.description': 'Lier des issues ou des merge requests pour remplir automatiquement les détails du worktree',
'session.gitlabIntegration.connect.action': 'Connectez GitLab',
'session.gitlabIntegration.search.issuesPlaceholder': 'Recherchez des problèmes GitLab',
'session.gitlabIntegration.search.mrsPlaceholder': 'Recherchez les merge requests GitLab',
'session.gitlabIntegration.empty.noIssuesFound': 'Aucun problème trouvé',
'session.gitlabIntegration.empty.noMergeRequestsFound': 'Aucune merge request trouvée',
'session.gitlabIntegration.actions.loadMore': 'Charger plus',
'session.gitlabIntegration.actions.cancel': 'Annuler',
'session.gitlabIntegration.actions.select': 'Sélectionner',
'session.gitlabIntegration.selected.issueNumber': 'Numéro {number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': 'Inclure la différence MR dans le contexte de la session',
'session.gitlabIntegration.includeDiff': 'Inclure la différence MR',
'session.gitlabIntegration.error.notConnected': 'GitLab non connecté',
'session.gitlabIntegration.error.loadDataFailed': 'Échec du chargement des données',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': 'La branche est déjà checkout dans un worktree',
'session.gitlabIntegration.validation.branchAlreadyExists': 'Une branche existe déjà localement',
'session.gitlabIntegration.validation.failed': 'Échec de la validation',
'session.gitlabIntegration.draftBadge': 'Brouillon',
'chat.fileAttachment.toast.attachFailed': 'Impossible de joindre le fichier', 'chat.fileAttachment.toast.attachFailed': 'Impossible de joindre le fichier',
'chat.fileAttachment.toast.someFilesSkipped': 'Certains fichiers ont été ignorés :\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': 'Certains fichiers ont été ignorés :\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': 'Échec de la sélection des fichiers dans VS Code', 'chat.fileAttachment.toast.vscodePickFailed': 'Échec de la sélection des fichiers dans VS Code',
@@ -259,6 +259,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': '編集する Prompt Template を選択してください。', 'settings.magicPrompts.sidebar.description': '編集する Prompt Template を選択してください。',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': '計画', 'settings.magicPrompts.sidebar.group.planning': '計画',
'settings.magicPrompts.sidebar.group.session': 'セッション', 'settings.magicPrompts.sidebar.group.session': 'セッション',
'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit 生成', 'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit 生成',
@@ -270,6 +271,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 失敗チェックレビュー', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 失敗チェックレビュー',
'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR コメントレビュー', 'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR コメントレビュー',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '単一 PR コメントレビュー', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '単一 PR コメントレビュー',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'MR レビュー',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': 'Issue レビュー',
'settings.magicPrompts.sidebar.item.planTodo': 'Todo 計画', 'settings.magicPrompts.sidebar.item.planTodo': 'Todo 計画',
'settings.magicPrompts.sidebar.item.planImprove': '計画の改善', 'settings.magicPrompts.sidebar.item.planImprove': '計画の改善',
'settings.magicPrompts.sidebar.item.planImplement': '計画の実装', 'settings.magicPrompts.sidebar.item.planImplement': '計画の実装',
@@ -2109,6 +2112,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'PR コメント分析に使用するプロンプト。', 'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'PR コメント分析に使用するプロンプト。',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '単一 PR コメントレビュー', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '単一 PR コメントレビュー',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '単一 PR コメント分析に使用するプロンプト。', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '単一 PR コメント分析に使用するプロンプト。',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'MR レビュー',
'settings.magicPrompts.page.group.gitlabPrReview.description': 'GitLab MR レビューフローに使用するプロンプト: 表示ユーザーメッセージ + 非表示指示ペイロード。',
'settings.magicPrompts.page.group.gitlabIssueReview.title': 'Issue レビュー',
'settings.magicPrompts.page.group.gitlabIssueReview.description': 'GitLab Issue レビューフローに使用するプロンプト: 表示ユーザーメッセージ + 非表示指示ペイロード。',
'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase 競合解決', 'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase 競合解決',
'settings.magicPrompts.page.group.gitConflictResolve.description': 'AI で Merge/Rebase 競合を解決する際に使用するプロンプト。', 'settings.magicPrompts.page.group.gitConflictResolve.description': 'AI で Merge/Rebase 競合を解決する際に使用するプロンプト。',
'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 競合解決', 'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 競合解決',
+28
View File
@@ -1879,7 +1879,9 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature', 'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature',
'session.newWorktree.actions.change': '変更', 'session.newWorktree.actions.change': '変更',
'session.newWorktree.actions.startFromGitHubIssuePr': 'GitHub Issue/PRから開始', 'session.newWorktree.actions.startFromGitHubIssuePr': 'GitHub Issue/PRから開始',
'session.newWorktree.actions.startFromGitLabIssueMr': 'GitLab Issue/MRから開始',
'session.newWorktree.usingPrBranch': 'PRブランチを使用: {branch}', 'session.newWorktree.usingPrBranch': 'PRブランチを使用: {branch}',
'session.newWorktree.usingMrBranch': 'MRブランチを使用: {branch}',
'session.newWorktree.fromIssue': 'Issue #{number}: {title}から', 'session.newWorktree.fromIssue': 'Issue #{number}: {title}から',
'session.newWorktree.worktreeDirectory': 'ワークツリーディレクトリ', 'session.newWorktree.worktreeDirectory': 'ワークツリーディレクトリ',
'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory', 'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory',
@@ -1890,6 +1892,7 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.newBranchFromSource': '{source}から新しいブランチが作成されます', 'session.newWorktree.newBranchFromSource': '{source}から新しいブランチが作成されます',
'session.newWorktree.issueNumber': 'Issue #{number}', 'session.newWorktree.issueNumber': 'Issue #{number}',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.includeDiffBadge': '+diff', 'session.newWorktree.includeDiffBadge': '+diff',
'session.newWorktree.newSessionTitle': '新しいセッション', 'session.newWorktree.newSessionTitle': '新しいセッション',
'session.newWorktree.fromSource': 'from {source}', 'session.newWorktree.fromSource': 'from {source}',
@@ -1902,9 +1905,11 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.error.branchNameRequired': 'ブランチ名が必要です', 'session.newWorktree.error.branchNameRequired': 'ブランチ名が必要です',
'session.newWorktree.error.worktreeDirectoryRequired': 'ワークツリーディレクトリが必要です', 'session.newWorktree.error.worktreeDirectoryRequired': 'ワークツリーディレクトリが必要です',
'session.newWorktree.error.sendGitHubContextFailed': 'GitHubコンテキストの送信に失敗しました', 'session.newWorktree.error.sendGitHubContextFailed': 'GitHubコンテキストの送信に失敗しました',
'session.newWorktree.error.sendGitLabContextFailed': 'GitLabコンテキストの送信に失敗しました',
'session.newWorktree.error.createWorktreeFailed': 'ワークツリーの作成に失敗しました', 'session.newWorktree.error.createWorktreeFailed': 'ワークツリーの作成に失敗しました',
'session.newWorktree.toast.sessionFromIssue': 'Issueからセッションを作成しました', 'session.newWorktree.toast.sessionFromIssue': 'Issueからセッションを作成しました',
'session.newWorktree.toast.sessionFromPr': 'PRからセッションを作成しました', 'session.newWorktree.toast.sessionFromPr': 'PRからセッションを作成しました',
'session.newWorktree.toast.sessionFromMr': 'マージリクエストからセッションを作成しました',
'session.newWorktree.toast.worktreeCreated': 'ワークツリーを作成しました', 'session.newWorktree.toast.worktreeCreated': 'ワークツリーを作成しました',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} - バックグラウンドでブートストラップ中', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} - バックグラウンドでブートストラップ中',
'session.githubIntegration.title': 'GitHubから選択', 'session.githubIntegration.title': 'GitHubから選択',
@@ -1929,6 +1934,29 @@ export const dict: Record<I18nKey, string> = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': 'ブランチはすでにワークツリーでチェックアウトされています', 'session.githubIntegration.validation.branchAlreadyCheckedOut': 'ブランチはすでにワークツリーでチェックアウトされています',
'session.githubIntegration.validation.branchAlreadyExists': 'ブランチはすでにローカルに存在します', 'session.githubIntegration.validation.branchAlreadyExists': 'ブランチはすでにローカルに存在します',
'session.githubIntegration.validation.failed': '検証に失敗しました', 'session.githubIntegration.validation.failed': '検証に失敗しました',
'session.gitlabIntegration.title': 'GitLabから選択',
'session.gitlabIntegration.tabs.issues': 'Issue',
'session.gitlabIntegration.tabs.mergeRequests': 'マージリクエスト',
'session.gitlabIntegration.connect.title': 'GitLabに接続',
'session.gitlabIntegration.connect.description': 'Issueまたはマージリクエストをリンクしてワークツリー詳細を自動入力',
'session.gitlabIntegration.connect.action': 'GitLabに接続',
'session.gitlabIntegration.search.issuesPlaceholder': 'GitLabのIssueを検索',
'session.gitlabIntegration.search.mrsPlaceholder': 'GitLabのマージリクエストを検索',
'session.gitlabIntegration.empty.noIssuesFound': 'Issueが見つかりません',
'session.gitlabIntegration.empty.noMergeRequestsFound': 'マージリクエストが見つかりません',
'session.gitlabIntegration.actions.loadMore': 'さらに読み込む',
'session.gitlabIntegration.actions.cancel': 'キャンセル',
'session.gitlabIntegration.actions.select': '選択',
'session.gitlabIntegration.selected.issueNumber': 'Issue #{number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': 'セッションコンテキストにMR差分を含める',
'session.gitlabIntegration.includeDiff': 'MR差分を含める',
'session.gitlabIntegration.error.notConnected': 'GitLabに接続されていません',
'session.gitlabIntegration.error.loadDataFailed': 'データの読み込みに失敗しました',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': 'ブランチはすでにワークツリーでチェックアウトされています',
'session.gitlabIntegration.validation.branchAlreadyExists': 'ブランチはすでにローカルに存在します',
'session.gitlabIntegration.validation.failed': '検証に失敗しました',
'session.gitlabIntegration.draftBadge': '下書き',
'chat.fileAttachment.toast.attachFailed': 'ファイルの添付に失敗しました', 'chat.fileAttachment.toast.attachFailed': 'ファイルの添付に失敗しました',
'chat.fileAttachment.toast.someFilesSkipped': '一部のファイルがスキップされました:\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': '一部のファイルがスキップされました:\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': 'VS Codeでのファイル選択に失敗しました', 'chat.fileAttachment.toast.vscodePickFailed': 'VS Codeでのファイル選択に失敗しました',
@@ -226,6 +226,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': '편집할 프롬프트 템플릿을 선택하세요.', 'settings.magicPrompts.sidebar.description': '편집할 프롬프트 템플릿을 선택하세요.',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': '계획', 'settings.magicPrompts.sidebar.group.planning': '계획',
'settings.magicPrompts.sidebar.group.session': '세션', 'settings.magicPrompts.sidebar.group.session': '세션',
'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit 생성', 'settings.magicPrompts.sidebar.item.gitCommitGenerate': 'Commit 생성',
@@ -237,6 +238,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 실패 체크 리뷰', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 실패 체크 리뷰',
'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR 댓글 리뷰', 'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR 댓글 리뷰',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '단일 PR 댓글 리뷰', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '단일 PR 댓글 리뷰',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'MR 리뷰',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': '이슈 리뷰',
'settings.magicPrompts.sidebar.item.planTodo': '할 일 계획', 'settings.magicPrompts.sidebar.item.planTodo': '할 일 계획',
'settings.magicPrompts.sidebar.item.planImprove': '계획 개선', 'settings.magicPrompts.sidebar.item.planImprove': '계획 개선',
'settings.magicPrompts.sidebar.item.planImplement': '계획 구현', 'settings.magicPrompts.sidebar.item.planImplement': '계획 구현',
@@ -2076,6 +2079,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'PR 댓글 분석에 사용되는 프롬프트입니다.', 'settings.magicPrompts.page.group.githubPrCommentsReview.description': 'PR 댓글 분석에 사용되는 프롬프트입니다.',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '단일 PR 댓글 리뷰', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '단일 PR 댓글 리뷰',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '단일 PR 댓글 분석에 사용되는 프롬프트입니다.', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '단일 PR 댓글 분석에 사용되는 프롬프트입니다.',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'MR 리뷰',
'settings.magicPrompts.page.group.gitlabPrReview.description': 'GitLab MR 리뷰 flow에 사용하는 프롬프트입니다: 표시 사용자 메시지 + 숨겨진 지침 payload.',
'settings.magicPrompts.page.group.gitlabIssueReview.title': '이슈 리뷰',
'settings.magicPrompts.page.group.gitlabIssueReview.description': 'GitLab issue 리뷰 flow에 사용하는 프롬프트입니다: 표시 사용자 메시지 + 숨겨진 지침 payload.',
'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase 충돌 해결', 'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase 충돌 해결',
'settings.magicPrompts.page.group.gitConflictResolve.description': 'AI로 merge/rebase 충돌을 해결할 때 사용하는 프롬프트입니다.', 'settings.magicPrompts.page.group.gitConflictResolve.description': 'AI로 merge/rebase 충돌을 해결할 때 사용하는 프롬프트입니다.',
'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 충돌 해결', 'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 충돌 해결',
+28
View File
@@ -1885,7 +1885,9 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature', 'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature',
'session.newWorktree.actions.change': '변경', 'session.newWorktree.actions.change': '변경',
'session.newWorktree.actions.startFromGitHubIssuePr': 'GitHub 이슈/PR에서 시작', 'session.newWorktree.actions.startFromGitHubIssuePr': 'GitHub 이슈/PR에서 시작',
'session.newWorktree.actions.startFromGitLabIssueMr': 'GitLab 이슈/MR에서 시작',
'session.newWorktree.usingPrBranch': 'PR 브랜치 사용 중: {branch}', 'session.newWorktree.usingPrBranch': 'PR 브랜치 사용 중: {branch}',
'session.newWorktree.usingMrBranch': 'MR 브랜치 사용 중: {branch}',
'session.newWorktree.fromIssue': '이슈 #{number}에서: {title}', 'session.newWorktree.fromIssue': '이슈 #{number}에서: {title}',
'session.newWorktree.worktreeDirectory': '워크트리 디렉터리', 'session.newWorktree.worktreeDirectory': '워크트리 디렉터리',
'session.newWorktree.worktreeDirectoryPlaceholder': 'my-워크트리-디렉터리', 'session.newWorktree.worktreeDirectoryPlaceholder': 'my-워크트리-디렉터리',
@@ -1896,6 +1898,7 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.newBranchFromSource': '{source}에서 새 브랜치가 생성됩니다', 'session.newWorktree.newBranchFromSource': '{source}에서 새 브랜치가 생성됩니다',
'session.newWorktree.issueNumber': '이슈 #{number}', 'session.newWorktree.issueNumber': '이슈 #{number}',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.includeDiffBadge': '+diff', 'session.newWorktree.includeDiffBadge': '+diff',
'session.newWorktree.newSessionTitle': '새 세션', 'session.newWorktree.newSessionTitle': '새 세션',
'session.newWorktree.fromSource': '{source}에서', 'session.newWorktree.fromSource': '{source}에서',
@@ -1908,9 +1911,11 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.error.branchNameRequired': '브랜치 이름은 필수입니다', 'session.newWorktree.error.branchNameRequired': '브랜치 이름은 필수입니다',
'session.newWorktree.error.worktreeDirectoryRequired': '워크트리 디렉터리 필수', 'session.newWorktree.error.worktreeDirectoryRequired': '워크트리 디렉터리 필수',
'session.newWorktree.error.sendGitHubContextFailed': 'GitHub 컨텍스트 전송에 실패했습니다', 'session.newWorktree.error.sendGitHubContextFailed': 'GitHub 컨텍스트 전송에 실패했습니다',
'session.newWorktree.error.sendGitLabContextFailed': 'GitLab 컨텍스트 전송에 실패했습니다',
'session.newWorktree.error.createWorktreeFailed': '워크트리 생성에 실패했습니다', 'session.newWorktree.error.createWorktreeFailed': '워크트리 생성에 실패했습니다',
'session.newWorktree.toast.sessionFromIssue': '이슈에서 세션을 생성했습니다', 'session.newWorktree.toast.sessionFromIssue': '이슈에서 세션을 생성했습니다',
'session.newWorktree.toast.sessionFromPr': 'PR에서 세션을 생성했습니다', 'session.newWorktree.toast.sessionFromPr': 'PR에서 세션을 생성했습니다',
'session.newWorktree.toast.sessionFromMr': '머지 리퀘스트에서 세션을 생성했습니다',
'session.newWorktree.toast.worktreeCreated': '워크트리를 생성했습니다', 'session.newWorktree.toast.worktreeCreated': '워크트리를 생성했습니다',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} - 백그라운드에서 초기 설정 중', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} - 백그라운드에서 초기 설정 중',
'session.githubIntegration.title': 'GitHub에서 선택', 'session.githubIntegration.title': 'GitHub에서 선택',
@@ -1935,6 +1940,29 @@ export const dict: Record<I18nKey, string> = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': '브랜치가 이미 워크트리에 체크아웃되어 있습니다', 'session.githubIntegration.validation.branchAlreadyCheckedOut': '브랜치가 이미 워크트리에 체크아웃되어 있습니다',
'session.githubIntegration.validation.branchAlreadyExists': '브랜치가 이미 로컬에 있습니다', 'session.githubIntegration.validation.branchAlreadyExists': '브랜치가 이미 로컬에 있습니다',
'session.githubIntegration.validation.failed': '유효성 검사에 실패했습니다', 'session.githubIntegration.validation.failed': '유효성 검사에 실패했습니다',
'session.gitlabIntegration.title': 'GitLab에서 선택',
'session.gitlabIntegration.tabs.issues': '이슈',
'session.gitlabIntegration.tabs.mergeRequests': '머지 리퀘스트',
'session.gitlabIntegration.connect.title': 'GitLab에 연결',
'session.gitlabIntegration.connect.description': '이슈 또는 머지 리퀘스트를 연결해 워크트리 정보를 자동으로 채웁니다',
'session.gitlabIntegration.connect.action': 'GitLab 연결',
'session.gitlabIntegration.search.issuesPlaceholder': 'GitLab 이슈 검색',
'session.gitlabIntegration.search.mrsPlaceholder': 'GitLab 머지 리퀘스트 검색',
'session.gitlabIntegration.empty.noIssuesFound': '이슈 없음',
'session.gitlabIntegration.empty.noMergeRequestsFound': '머지 리퀘스트가 없습니다',
'session.gitlabIntegration.actions.loadMore': '더 불러오기',
'session.gitlabIntegration.actions.cancel': '취소',
'session.gitlabIntegration.actions.select': '선택',
'session.gitlabIntegration.selected.issueNumber': '이슈 #{number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': 'MR 변경사항을 세션 컨텍스트에 포함',
'session.gitlabIntegration.includeDiff': 'MR 변경사항 포함',
'session.gitlabIntegration.error.notConnected': 'GitLab에 연결되어 있지 않습니다',
'session.gitlabIntegration.error.loadDataFailed': '데이터를 불러오지 못했습니다',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': '브랜치가 이미 워크트리에 체크아웃되어 있습니다',
'session.gitlabIntegration.validation.branchAlreadyExists': '브랜치가 이미 로컬에 있습니다',
'session.gitlabIntegration.validation.failed': '유효성 검사에 실패했습니다',
'session.gitlabIntegration.draftBadge': '초안',
'chat.fileAttachment.toast.attachFailed': '첨부 파일 실패', 'chat.fileAttachment.toast.attachFailed': '첨부 파일 실패',
'chat.fileAttachment.toast.someFilesSkipped': '일부 파일을 건너뛰었습니다:\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': '일부 파일을 건너뛰었습니다:\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': 'VS Code에서 파일 선택에 실패했습니다', 'chat.fileAttachment.toast.vscodePickFailed': 'VS Code에서 파일 선택에 실패했습니다',
@@ -372,6 +372,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrReview.description': 'Prompty używane w przepływie przeglądu PR: widoczna wiadomość użytkownika + ukryty ładunek instrukcji.', 'settings.magicPrompts.page.group.githubPrReview.description': 'Prompty używane w przepływie przeglądu PR: widoczna wiadomość użytkownika + ukryty ładunek instrukcji.',
'settings.magicPrompts.page.group.githubPrReview.title': 'Przegląd PR', 'settings.magicPrompts.page.group.githubPrReview.title': 'Przegląd PR',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Prompty używane do analizy pojedynczego komentarza w PR.', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': 'Prompty używane do analizy pojedynczego komentarza w PR.',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'Przegląd MR',
'settings.magicPrompts.page.group.gitlabPrReview.description': 'Prompty używane w przepływie przeglądu MR GitLab: widoczna wiadomość użytkownika + ukryty ładunek instrukcji.',
'settings.magicPrompts.page.group.gitlabIssueReview.title': 'Przegląd Issue',
'settings.magicPrompts.page.group.gitlabIssueReview.description': 'Prompty używane w przepływie przeglądu Issue GitLab: widoczna wiadomość użytkownika + ukryty ładunek instrukcji.',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Przegląd pojedynczego komentarza PR', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': 'Przegląd pojedynczego komentarza PR',
'settings.magicPrompts.page.group.planImplement.description': 'Ukryty prompt używany podczas przesyłania zapisanego planu do przepływu implementacji.', 'settings.magicPrompts.page.group.planImplement.description': 'Ukryty prompt używany podczas przesyłania zapisanego planu do przepływu implementacji.',
'settings.magicPrompts.page.group.planImplement.title': 'Implementuj Plan', 'settings.magicPrompts.page.group.planImplement.title': 'Implementuj Plan',
@@ -413,6 +417,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': 'Wybierz szablon promptu, aby go edytować.', 'settings.magicPrompts.sidebar.description': 'Wybierz szablon promptu, aby go edytować.',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': 'Planowanie', 'settings.magicPrompts.sidebar.group.planning': 'Planowanie',
'settings.magicPrompts.sidebar.group.session': 'Sesja', 'settings.magicPrompts.sidebar.group.session': 'Sesja',
'settings.magicPrompts.sidebar.item.gitCherrypickConflictResolve': 'Rozwiązywanie konfliktów Cherry-pick', 'settings.magicPrompts.sidebar.item.gitCherrypickConflictResolve': 'Rozwiązywanie konfliktów Cherry-pick',
@@ -424,6 +429,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'Przegląd nieudanych sprawdzeń PR', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'Przegląd nieudanych sprawdzeń PR',
'settings.magicPrompts.sidebar.item.githubPrReview': 'Przegląd PR', 'settings.magicPrompts.sidebar.item.githubPrReview': 'Przegląd PR',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Przegląd pojedynczego komentarza PR', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': 'Przegląd pojedynczego komentarza PR',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'Przegląd MR',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': 'Przegląd Issue',
'settings.magicPrompts.sidebar.item.planImplement': 'Implementuj Plan', 'settings.magicPrompts.sidebar.item.planImplement': 'Implementuj Plan',
'settings.magicPrompts.sidebar.item.planImprove': 'Ulepsz Plan', 'settings.magicPrompts.sidebar.item.planImprove': 'Ulepsz Plan',
'settings.magicPrompts.sidebar.item.planTodo': 'Planowanie Todo', 'settings.magicPrompts.sidebar.item.planTodo': 'Planowanie Todo',
+28
View File
@@ -682,6 +682,29 @@ export const dict: Record<I18nKey, string> = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': 'Gałąź jest już wyewidencjonowana w drzewie pracy', 'session.githubIntegration.validation.branchAlreadyCheckedOut': 'Gałąź jest już wyewidencjonowana w drzewie pracy',
'session.githubIntegration.validation.branchAlreadyExists': 'Gałąź już istnieje lokalnie', 'session.githubIntegration.validation.branchAlreadyExists': 'Gałąź już istnieje lokalnie',
'session.githubIntegration.validation.failed': 'Walidacja nie powiodła się', 'session.githubIntegration.validation.failed': 'Walidacja nie powiodła się',
'session.gitlabIntegration.title': 'Wybierz z GitLab',
'session.gitlabIntegration.tabs.issues': 'Zagadnienia',
'session.gitlabIntegration.tabs.mergeRequests': 'Merge requesty',
'session.gitlabIntegration.connect.title': 'Połącz z GitLab',
'session.gitlabIntegration.connect.description': 'Połącz zagadnienia lub merge requesty aby auto-wypełnić szczegóły drzewa pracy',
'session.gitlabIntegration.connect.action': 'Połącz GitLab',
'session.gitlabIntegration.search.issuesPlaceholder': 'Szukaj zagadnień GitLab',
'session.gitlabIntegration.search.mrsPlaceholder': 'Szukaj merge requestów GitLab',
'session.gitlabIntegration.empty.noIssuesFound': 'Nie znaleziono zagadnień',
'session.gitlabIntegration.empty.noMergeRequestsFound': 'Nie znaleziono merge requestów',
'session.gitlabIntegration.actions.loadMore': 'Załaduj więcej',
'session.gitlabIntegration.actions.cancel': 'Anuluj',
'session.gitlabIntegration.actions.select': 'Wybierz',
'session.gitlabIntegration.selected.issueNumber': 'Zagadnienie #{number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': 'Dołącz diff MR do kontekstu sesji',
'session.gitlabIntegration.includeDiff': 'Dołącz diff MR',
'session.gitlabIntegration.error.notConnected': 'GitLab nie jest połączony',
'session.gitlabIntegration.error.loadDataFailed': 'Nie udało się załadować danych',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': 'Gałąź jest już wyewidencjonowana w drzewie pracy',
'session.gitlabIntegration.validation.branchAlreadyExists': 'Gałąź już istnieje lokalnie',
'session.gitlabIntegration.validation.failed': 'Walidacja nie powiodła się',
'session.gitlabIntegration.draftBadge': 'Szkic',
'chat.fileAttachment.toast.attachFailed': 'Nie udało się dołączyć pliku', 'chat.fileAttachment.toast.attachFailed': 'Nie udało się dołączyć pliku',
'chat.fileAttachment.toast.someFilesSkipped': 'Niektóre pliki zostały pominięte:\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': 'Niektóre pliki zostały pominięte:\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': 'Nie udało się wybrać plików w VS Code', 'chat.fileAttachment.toast.vscodePickFailed': 'Nie udało się wybrać plików w VS Code',
@@ -2701,6 +2724,7 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.actions.creating': 'Tworzenie...', 'session.newWorktree.actions.creating': 'Tworzenie...',
'session.newWorktree.actions.reset': 'Resetuj', 'session.newWorktree.actions.reset': 'Resetuj',
'session.newWorktree.actions.startFromGitHubIssuePr': 'Rozpocznij ze zgłoszenia/PR GitHub', 'session.newWorktree.actions.startFromGitHubIssuePr': 'Rozpocznij ze zgłoszenia/PR GitHub',
'session.newWorktree.actions.startFromGitLabIssueMr': 'Rozpocznij z GitLab zagadnienia/MR',
'session.newWorktree.branchName': 'Nazwa gałęzi', 'session.newWorktree.branchName': 'Nazwa gałęzi',
'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature', 'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature',
'session.newWorktree.chooseBranch': 'Wybierz gałąź...', 'session.newWorktree.chooseBranch': 'Wybierz gałąź...',
@@ -2709,6 +2733,7 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.error.noActiveProject': 'Brak aktywnego projektu', 'session.newWorktree.error.noActiveProject': 'Brak aktywnego projektu',
'session.newWorktree.error.noModelSelected': 'Nie wybrano modelu', 'session.newWorktree.error.noModelSelected': 'Nie wybrano modelu',
'session.newWorktree.error.sendGitHubContextFailed': 'Nie udało się wysłać kontekstu GitHub', 'session.newWorktree.error.sendGitHubContextFailed': 'Nie udało się wysłać kontekstu GitHub',
'session.newWorktree.error.sendGitLabContextFailed': 'Nie udało się wysłać kontekstu GitLab',
'session.newWorktree.error.worktreeDirectoryRequired': 'Katalog drzewa pracy jest wymagany', 'session.newWorktree.error.worktreeDirectoryRequired': 'Katalog drzewa pracy jest wymagany',
'session.newWorktree.fetchBranches': 'Pobierz gałęzie', 'session.newWorktree.fetchBranches': 'Pobierz gałęzie',
'session.newWorktree.fromIssue': 'Ze zgłoszenia #{number}: {title}', 'session.newWorktree.fromIssue': 'Ze zgłoszenia #{number}: {title}',
@@ -2727,6 +2752,7 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.otherLocalBranches': 'Pozostałe lokalne gałęzie', 'session.newWorktree.otherLocalBranches': 'Pozostałe lokalne gałęzie',
'session.newWorktree.otherRemoteBranches': 'Pozostałe zdalne gałęzie', 'session.newWorktree.otherRemoteBranches': 'Pozostałe zdalne gałęzie',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.remoteBranches': 'Zdalne gałęzie', 'session.newWorktree.remoteBranches': 'Zdalne gałęzie',
'session.newWorktree.resetToMatchBranchName': 'Zresetuj do nazwy zgodnej z gałęzią', 'session.newWorktree.resetToMatchBranchName': 'Zresetuj do nazwy zgodnej z gałęzią',
'session.newWorktree.searchBranches': 'Szukaj gałęzi...', 'session.newWorktree.searchBranches': 'Szukaj gałęzi...',
@@ -2737,9 +2763,11 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.title': 'Nowe drzewo pracy', 'session.newWorktree.title': 'Nowe drzewo pracy',
'session.newWorktree.toast.sessionFromIssue': 'Sesja utworzona ze zgłoszenia', 'session.newWorktree.toast.sessionFromIssue': 'Sesja utworzona ze zgłoszenia',
'session.newWorktree.toast.sessionFromPr': 'Sesja utworzona z PR', 'session.newWorktree.toast.sessionFromPr': 'Sesja utworzona z PR',
'session.newWorktree.toast.sessionFromMr': 'Sesja utworzona z merge requesta',
'session.newWorktree.toast.worktreeCreated': 'Drzewo pracy utworzone', 'session.newWorktree.toast.worktreeCreated': 'Drzewo pracy utworzone',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} — inicjalizacja w tle', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} — inicjalizacja w tle',
'session.newWorktree.usingPrBranch': 'Używana gałąź PR: {branch}', 'session.newWorktree.usingPrBranch': 'Używana gałąź PR: {branch}',
'session.newWorktree.usingMrBranch': 'Używana gałąź MR: {branch}',
'session.newWorktree.worktreeDirectory': 'Katalog drzewa pracy', 'session.newWorktree.worktreeDirectory': 'Katalog drzewa pracy',
'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory', 'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory',
'sessionAuth.actions.addPasskey': 'Add passkey', 'sessionAuth.actions.addPasskey': 'Add passkey',
@@ -226,6 +226,7 @@ export const settingsDict = {
"settings.magicPrompts.sidebar.description": "Selecione um modelo de prompt para editar.", "settings.magicPrompts.sidebar.description": "Selecione um modelo de prompt para editar.",
"settings.magicPrompts.sidebar.group.git": "Git", "settings.magicPrompts.sidebar.group.git": "Git",
"settings.magicPrompts.sidebar.group.github": "GitHub", "settings.magicPrompts.sidebar.group.github": "GitHub",
"settings.magicPrompts.sidebar.group.gitlab": "GitLab",
"settings.magicPrompts.sidebar.group.planning": "Planejamento", "settings.magicPrompts.sidebar.group.planning": "Planejamento",
"settings.magicPrompts.sidebar.group.session": "Sessão", "settings.magicPrompts.sidebar.group.session": "Sessão",
"settings.magicPrompts.sidebar.item.gitCommitGenerate": "Geração de commit", "settings.magicPrompts.sidebar.item.gitCommitGenerate": "Geração de commit",
@@ -237,6 +238,8 @@ export const settingsDict = {
"settings.magicPrompts.sidebar.item.githubPrFailedChecksReview": "Revisão de PR com verificações com falha", "settings.magicPrompts.sidebar.item.githubPrFailedChecksReview": "Revisão de PR com verificações com falha",
"settings.magicPrompts.sidebar.item.githubPrCommentsReview": "Revisão de comentários de PR", "settings.magicPrompts.sidebar.item.githubPrCommentsReview": "Revisão de comentários de PR",
"settings.magicPrompts.sidebar.item.githubSinglePrCommentReview": "Revisão de comentário único de PR", "settings.magicPrompts.sidebar.item.githubSinglePrCommentReview": "Revisão de comentário único de PR",
"settings.magicPrompts.sidebar.item.gitlabPrReview": "Revisão de MR",
"settings.magicPrompts.sidebar.item.gitlabIssueReview": "Revisão de issue",
"settings.magicPrompts.sidebar.item.planTodo": "Planejar Todo", "settings.magicPrompts.sidebar.item.planTodo": "Planejar Todo",
"settings.magicPrompts.sidebar.item.planImprove": "Melhorar plano", "settings.magicPrompts.sidebar.item.planImprove": "Melhorar plano",
"settings.magicPrompts.sidebar.item.planImplement": "Implementar plano", "settings.magicPrompts.sidebar.item.planImplement": "Implementar plano",
@@ -2076,6 +2079,10 @@ export const settingsDict = {
"settings.magicPrompts.page.group.githubPrCommentsReview.description": "Prompts usados para a análise de comentários de um PR.", "settings.magicPrompts.page.group.githubPrCommentsReview.description": "Prompts usados para a análise de comentários de um PR.",
"settings.magicPrompts.page.group.githubSinglePrCommentReview.title": "Revisão de comentário único de PR", "settings.magicPrompts.page.group.githubSinglePrCommentReview.title": "Revisão de comentário único de PR",
"settings.magicPrompts.page.group.githubSinglePrCommentReview.description": "Prompts usados para a análise de um único comentário em um PR.", "settings.magicPrompts.page.group.githubSinglePrCommentReview.description": "Prompts usados para a análise de um único comentário em um PR.",
"settings.magicPrompts.page.group.gitlabPrReview.title": "Revisão de MR",
"settings.magicPrompts.page.group.gitlabPrReview.description": "Prompts usados para o fluxo de revisão de MR do GitLab: mensagem visível do usuário + carga de instruções ocultas.",
"settings.magicPrompts.page.group.gitlabIssueReview.title": "Revisão de issue",
"settings.magicPrompts.page.group.gitlabIssueReview.description": "Prompts usados para o fluxo de revisão de issue do GitLab: mensagem visível do usuário + carga de instruções ocultas.",
"settings.magicPrompts.page.group.gitConflictResolve.title": "Resolução de conflitos de merge/rebase", "settings.magicPrompts.page.group.gitConflictResolve.title": "Resolução de conflitos de merge/rebase",
"settings.magicPrompts.page.group.gitConflictResolve.description": "Prompts usados ao resolver conflitos de merge/rebase com IA.", "settings.magicPrompts.page.group.gitConflictResolve.description": "Prompts usados ao resolver conflitos de merge/rebase com IA.",
"settings.magicPrompts.page.group.gitCherrypickConflictResolve.title": "Resolução de conflitos de cherry-pick", "settings.magicPrompts.page.group.gitCherrypickConflictResolve.title": "Resolução de conflitos de cherry-pick",
@@ -1861,7 +1861,9 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.branchNamePlaceholder": "feature/my-awesome-feature", "session.newWorktree.branchNamePlaceholder": "feature/my-awesome-feature",
"session.newWorktree.actions.change": "Alterar", "session.newWorktree.actions.change": "Alterar",
"session.newWorktree.actions.startFromGitHubIssuePr": "Iniciar de Issue/PR de GitHub", "session.newWorktree.actions.startFromGitHubIssuePr": "Iniciar de Issue/PR de GitHub",
"session.newWorktree.actions.startFromGitLabIssueMr": "Iniciar de Issue/MR de GitLab",
"session.newWorktree.usingPrBranch": "Usando branch da PR: {branch}", "session.newWorktree.usingPrBranch": "Usando branch da PR: {branch}",
"session.newWorktree.usingMrBranch": "Usando branch do MR: {branch}",
"session.newWorktree.fromIssue": "Da issue #{number}: {title}", "session.newWorktree.fromIssue": "Da issue #{number}: {title}",
"session.newWorktree.worktreeDirectory": "Diretório do worktree", "session.newWorktree.worktreeDirectory": "Diretório do worktree",
"session.newWorktree.worktreeDirectoryPlaceholder": "my-worktree-directory", "session.newWorktree.worktreeDirectoryPlaceholder": "my-worktree-directory",
@@ -1872,6 +1874,7 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.newBranchFromSource": "Uma nova branch será criada a partir de {source}", "session.newWorktree.newBranchFromSource": "Uma nova branch será criada a partir de {source}",
"session.newWorktree.issueNumber": "Issue #{number}", "session.newWorktree.issueNumber": "Issue #{number}",
"session.newWorktree.prNumber": "PR #{number}", "session.newWorktree.prNumber": "PR #{number}",
"session.newWorktree.mrNumber": "MR #{number}",
"session.newWorktree.includeDiffBadge": "+diff", "session.newWorktree.includeDiffBadge": "+diff",
"session.newWorktree.newSessionTitle": "Nova sessão", "session.newWorktree.newSessionTitle": "Nova sessão",
"session.newWorktree.fromSource": "de {source}", "session.newWorktree.fromSource": "de {source}",
@@ -1884,9 +1887,11 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.error.branchNameRequired": "É necessário informar o nome da branch", "session.newWorktree.error.branchNameRequired": "É necessário informar o nome da branch",
"session.newWorktree.error.worktreeDirectoryRequired": "É necessário o diretório do worktree", "session.newWorktree.error.worktreeDirectoryRequired": "É necessário o diretório do worktree",
"session.newWorktree.error.sendGitHubContextFailed": "Não foi possível enviar o contexto de GitHub", "session.newWorktree.error.sendGitHubContextFailed": "Não foi possível enviar o contexto de GitHub",
"session.newWorktree.error.sendGitLabContextFailed": "Não foi possível enviar o contexto de GitLab",
"session.newWorktree.error.createWorktreeFailed": "Não foi possível criar o worktree", "session.newWorktree.error.createWorktreeFailed": "Não foi possível criar o worktree",
"session.newWorktree.toast.sessionFromIssue": "Sessão criada a partir da issue", "session.newWorktree.toast.sessionFromIssue": "Sessão criada a partir da issue",
"session.newWorktree.toast.sessionFromPr": "Sessão criada a partir da PR", "session.newWorktree.toast.sessionFromPr": "Sessão criada a partir da PR",
"session.newWorktree.toast.sessionFromMr": "Sessão criada a partir do merge request",
"session.newWorktree.toast.worktreeCreated": "Worktree criado", "session.newWorktree.toast.worktreeCreated": "Worktree criado",
"session.newWorktree.toast.worktreeCreatedDescription": "{target} - configurando em segundo plano", "session.newWorktree.toast.worktreeCreatedDescription": "{target} - configurando em segundo plano",
"session.githubIntegration.title": "Selecionar de GitHub", "session.githubIntegration.title": "Selecionar de GitHub",
@@ -1911,6 +1916,29 @@ export const dict: Record<I18nKey, string> = {
"session.githubIntegration.validation.branchAlreadyCheckedOut": "A branch já está em uso em um worktree", "session.githubIntegration.validation.branchAlreadyCheckedOut": "A branch já está em uso em um worktree",
"session.githubIntegration.validation.branchAlreadyExists": "A branch já existe localmente", "session.githubIntegration.validation.branchAlreadyExists": "A branch já existe localmente",
"session.githubIntegration.validation.failed": "Não foi possível validar", "session.githubIntegration.validation.failed": "Não foi possível validar",
"session.gitlabIntegration.title": "Selecionar de GitLab",
"session.gitlabIntegration.tabs.issues": "Issues",
"session.gitlabIntegration.tabs.mergeRequests": "Merge Requests",
"session.gitlabIntegration.connect.title": "Conectar a GitLab",
"session.gitlabIntegration.connect.description": "Vincule issues ou merge requests para preencher automaticamente os detalhes do worktree",
"session.gitlabIntegration.connect.action": "Conectar a GitLab",
"session.gitlabIntegration.search.issuesPlaceholder": "Pesquisar issues do GitLab",
"session.gitlabIntegration.search.mrsPlaceholder": "Pesquisar merge requests do GitLab",
"session.gitlabIntegration.empty.noIssuesFound": "Nenhuma issue encontrada",
"session.gitlabIntegration.empty.noMergeRequestsFound": "Nenhum merge request encontrado",
"session.gitlabIntegration.actions.loadMore": "Carregar mais",
"session.gitlabIntegration.actions.cancel": "Cancelar",
"session.gitlabIntegration.actions.select": "Selecionar",
"session.gitlabIntegration.selected.issueNumber": "Issue #{number}",
"session.gitlabIntegration.selected.mrNumber": "MR #{number}",
"session.gitlabIntegration.includeDiffAria": "Incluir diff do MR no contexto da sessão",
"session.gitlabIntegration.includeDiff": "Incluir diff do MR",
"session.gitlabIntegration.error.notConnected": "GitLab não está conectado",
"session.gitlabIntegration.error.loadDataFailed": "Não foi possível carregar os dados",
"session.gitlabIntegration.validation.branchAlreadyCheckedOut": "A branch já está em uso em um worktree",
"session.gitlabIntegration.validation.branchAlreadyExists": "A branch já existe localmente",
"session.gitlabIntegration.validation.failed": "Não foi possível validar",
"session.gitlabIntegration.draftBadge": "Rascunho",
"chat.fileAttachment.toast.attachFailed": "Não foi possível anexar o arquivo", "chat.fileAttachment.toast.attachFailed": "Não foi possível anexar o arquivo",
"chat.fileAttachment.toast.someFilesSkipped": "Alguns arquivos foram omitidos:\n{summary}", "chat.fileAttachment.toast.someFilesSkipped": "Alguns arquivos foram omitidos:\n{summary}",
"chat.fileAttachment.toast.vscodePickFailed": "Não foi possível selecionar arquivos em VS Code", "chat.fileAttachment.toast.vscodePickFailed": "Não foi possível selecionar arquivos em VS Code",
@@ -226,6 +226,7 @@ export const settingsDict = {
"settings.magicPrompts.sidebar.description": "Виберіть шаблон промпта для редагування.", "settings.magicPrompts.sidebar.description": "Виберіть шаблон промпта для редагування.",
"settings.magicPrompts.sidebar.group.git": "Git", "settings.magicPrompts.sidebar.group.git": "Git",
"settings.magicPrompts.sidebar.group.github": "GitHub", "settings.magicPrompts.sidebar.group.github": "GitHub",
"settings.magicPrompts.sidebar.group.gitlab": "GitLab",
"settings.magicPrompts.sidebar.group.planning": "Планування", "settings.magicPrompts.sidebar.group.planning": "Планування",
"settings.magicPrompts.sidebar.group.session": "Сесія", "settings.magicPrompts.sidebar.group.session": "Сесія",
"settings.magicPrompts.sidebar.item.gitCommitGenerate": "Генерація комітів", "settings.magicPrompts.sidebar.item.gitCommitGenerate": "Генерація комітів",
@@ -237,6 +238,8 @@ export const settingsDict = {
"settings.magicPrompts.sidebar.item.githubPrFailedChecksReview": "Перевірка перевірок PR", "settings.magicPrompts.sidebar.item.githubPrFailedChecksReview": "Перевірка перевірок PR",
"settings.magicPrompts.sidebar.item.githubPrCommentsReview": "Огляд коментарів PR", "settings.magicPrompts.sidebar.item.githubPrCommentsReview": "Огляд коментарів PR",
"settings.magicPrompts.sidebar.item.githubSinglePrCommentReview": "Огляд єдиного PR коментаря", "settings.magicPrompts.sidebar.item.githubSinglePrCommentReview": "Огляд єдиного PR коментаря",
"settings.magicPrompts.sidebar.item.gitlabPrReview": "MR огляд",
"settings.magicPrompts.sidebar.item.gitlabIssueReview": "Огляд issue",
"settings.magicPrompts.sidebar.item.planTodo": "Планування Todo", "settings.magicPrompts.sidebar.item.planTodo": "Планування Todo",
"settings.magicPrompts.sidebar.item.planImprove": "Поліпшити план", "settings.magicPrompts.sidebar.item.planImprove": "Поліпшити план",
"settings.magicPrompts.sidebar.item.planImplement": "Реалізувати план", "settings.magicPrompts.sidebar.item.planImplement": "Реалізувати план",
@@ -2076,6 +2079,10 @@ export const settingsDict = {
"settings.magicPrompts.page.group.githubPrCommentsReview.description": "Промпти, які використовуються для аналізу PR коментарів.", "settings.magicPrompts.page.group.githubPrCommentsReview.description": "Промпти, які використовуються для аналізу PR коментарів.",
"settings.magicPrompts.page.group.githubSinglePrCommentReview.title": "Огляд окремого коментаря PR", "settings.magicPrompts.page.group.githubSinglePrCommentReview.title": "Огляд окремого коментаря PR",
"settings.magicPrompts.page.group.githubSinglePrCommentReview.description": "Промпти, які використовуються для аналізу окремих коментарів PR.", "settings.magicPrompts.page.group.githubSinglePrCommentReview.description": "Промпти, які використовуються для аналізу окремих коментарів PR.",
"settings.magicPrompts.page.group.gitlabPrReview.title": "Огляд MR",
"settings.magicPrompts.page.group.gitlabPrReview.description": "Промпти, які використовуються для GitLab MR-огляду: видиме повідомлення користувача + приховані інструкції.",
"settings.magicPrompts.page.group.gitlabIssueReview.title": "Огляд issue",
"settings.magicPrompts.page.group.gitlabIssueReview.description": "Промпти, які використовуються для GitLab issue-огляду: видиме повідомлення користувача + приховані інструкції.",
"settings.magicPrompts.page.group.gitConflictResolve.title": "Вирішення конфліктів злиття/перебазування", "settings.magicPrompts.page.group.gitConflictResolve.title": "Вирішення конфліктів злиття/перебазування",
"settings.magicPrompts.page.group.gitConflictResolve.description": "Промпти, які використовуються під час вирішення конфліктів злиття/перебазування з AI.", "settings.magicPrompts.page.group.gitConflictResolve.description": "Промпти, які використовуються під час вирішення конфліктів злиття/перебазування з AI.",
"settings.magicPrompts.page.group.gitCherrypickConflictResolve.title": "Вирішення конфліктів", "settings.magicPrompts.page.group.gitCherrypickConflictResolve.title": "Вирішення конфліктів",
+28
View File
@@ -1861,7 +1861,9 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.branchNamePlaceholder": "feature/my-awesome-feature", "session.newWorktree.branchNamePlaceholder": "feature/my-awesome-feature",
"session.newWorktree.actions.change": "Змінити", "session.newWorktree.actions.change": "Змінити",
"session.newWorktree.actions.startFromGitHubIssuePr": "Почати з GitHub issue/PR", "session.newWorktree.actions.startFromGitHubIssuePr": "Почати з GitHub issue/PR",
"session.newWorktree.actions.startFromGitLabIssueMr": "Почати з GitLab issue/MR",
"session.newWorktree.usingPrBranch": "Використовується PR-гілка: {branch}", "session.newWorktree.usingPrBranch": "Використовується PR-гілка: {branch}",
"session.newWorktree.usingMrBranch": "Використовується MR-гілка: {branch}",
"session.newWorktree.fromIssue": "З issue №{number}: {title}", "session.newWorktree.fromIssue": "З issue №{number}: {title}",
"session.newWorktree.worktreeDirectory": "Каталог worktree", "session.newWorktree.worktreeDirectory": "Каталог worktree",
"session.newWorktree.worktreeDirectoryPlaceholder": "my-worktree-directory", "session.newWorktree.worktreeDirectoryPlaceholder": "my-worktree-directory",
@@ -1872,6 +1874,7 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.newBranchFromSource": "Нову гілку буде створено з {source}", "session.newWorktree.newBranchFromSource": "Нову гілку буде створено з {source}",
"session.newWorktree.issueNumber": "issue №{number}", "session.newWorktree.issueNumber": "issue №{number}",
"session.newWorktree.prNumber": "PR #{number}", "session.newWorktree.prNumber": "PR #{number}",
"session.newWorktree.mrNumber": "MR #{number}",
"session.newWorktree.includeDiffBadge": "+diff", "session.newWorktree.includeDiffBadge": "+diff",
"session.newWorktree.newSessionTitle": "Нова сесія", "session.newWorktree.newSessionTitle": "Нова сесія",
"session.newWorktree.fromSource": "з {source}", "session.newWorktree.fromSource": "з {source}",
@@ -1884,9 +1887,11 @@ export const dict: Record<I18nKey, string> = {
"session.newWorktree.error.branchNameRequired": "Необхідно вказати назву гілки", "session.newWorktree.error.branchNameRequired": "Необхідно вказати назву гілки",
"session.newWorktree.error.worktreeDirectoryRequired": "Потрібен каталог worktree", "session.newWorktree.error.worktreeDirectoryRequired": "Потрібен каталог worktree",
"session.newWorktree.error.sendGitHubContextFailed": "Не вдалося надіслати контекст GitHub", "session.newWorktree.error.sendGitHubContextFailed": "Не вдалося надіслати контекст GitHub",
"session.newWorktree.error.sendGitLabContextFailed": "Не вдалося надіслати контекст GitLab",
"session.newWorktree.error.createWorktreeFailed": "Не вдалося створити worktree", "session.newWorktree.error.createWorktreeFailed": "Не вдалося створити worktree",
"session.newWorktree.toast.sessionFromIssue": "Сесію створено з issue", "session.newWorktree.toast.sessionFromIssue": "Сесію створено з issue",
"session.newWorktree.toast.sessionFromPr": "Сесію створено з PR", "session.newWorktree.toast.sessionFromPr": "Сесію створено з PR",
"session.newWorktree.toast.sessionFromMr": "Сесію створено з merge request",
"session.newWorktree.toast.worktreeCreated": "Створено worktree", "session.newWorktree.toast.worktreeCreated": "Створено worktree",
"session.newWorktree.toast.worktreeCreatedDescription": "{target} - завантаження у фоні", "session.newWorktree.toast.worktreeCreatedDescription": "{target} - завантаження у фоні",
"session.githubIntegration.title": "Виберіть із GitHub", "session.githubIntegration.title": "Виберіть із GitHub",
@@ -1911,6 +1916,29 @@ export const dict: Record<I18nKey, string> = {
"session.githubIntegration.validation.branchAlreadyCheckedOut": "Гілку вже відкрито в worktree", "session.githubIntegration.validation.branchAlreadyCheckedOut": "Гілку вже відкрито в worktree",
"session.githubIntegration.validation.branchAlreadyExists": "Гілка вже існує локально", "session.githubIntegration.validation.branchAlreadyExists": "Гілка вже існує локально",
"session.githubIntegration.validation.failed": "Помилка перевірки", "session.githubIntegration.validation.failed": "Помилка перевірки",
"session.gitlabIntegration.title": "Виберіть із GitLab",
"session.gitlabIntegration.tabs.issues": "Issue",
"session.gitlabIntegration.tabs.mergeRequests": "Merge Request",
"session.gitlabIntegration.connect.title": "Підключитися до GitLab",
"session.gitlabIntegration.connect.description": "Пов’яжіть issue або merge request, щоб автоматично заповнити деталі worktree",
"session.gitlabIntegration.connect.action": "Підключити GitLab",
"session.gitlabIntegration.search.issuesPlaceholder": "Шукати issue в GitLab",
"session.gitlabIntegration.search.mrsPlaceholder": "Шукати merge request у GitLab",
"session.gitlabIntegration.empty.noIssuesFound": "Issue не знайдено",
"session.gitlabIntegration.empty.noMergeRequestsFound": "Merge request не знайдено",
"session.gitlabIntegration.actions.loadMore": "Завантажити ще",
"session.gitlabIntegration.actions.cancel": "Скасувати",
"session.gitlabIntegration.actions.select": "Вибрати",
"session.gitlabIntegration.selected.issueNumber": "issue №{number}",
"session.gitlabIntegration.selected.mrNumber": "MR #{number}",
"session.gitlabIntegration.includeDiffAria": "Додати diff MR у контекст сесії",
"session.gitlabIntegration.includeDiff": "Додати diff MR",
"session.gitlabIntegration.error.notConnected": "GitLab не підключено",
"session.gitlabIntegration.error.loadDataFailed": "Не вдалося завантажити дані",
"session.gitlabIntegration.validation.branchAlreadyCheckedOut": "Гілку вже відкрито в worktree",
"session.gitlabIntegration.validation.branchAlreadyExists": "Гілка вже існує локально",
"session.gitlabIntegration.validation.failed": "Помилка перевірки",
"session.gitlabIntegration.draftBadge": "Чернетка",
"chat.fileAttachment.toast.attachFailed": "Не вдалося прикріпити файл", "chat.fileAttachment.toast.attachFailed": "Не вдалося прикріпити файл",
"chat.fileAttachment.toast.someFilesSkipped": "Деякі файли були пропущені:\n{summary}", "chat.fileAttachment.toast.someFilesSkipped": "Деякі файли були пропущені:\n{summary}",
"chat.fileAttachment.toast.vscodePickFailed": "Не вдалося вибрати файли в VS Code", "chat.fileAttachment.toast.vscodePickFailed": "Не вдалося вибрати файли в VS Code",
@@ -226,6 +226,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': '选择要编辑的提示词模板。', 'settings.magicPrompts.sidebar.description': '选择要编辑的提示词模板。',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': '规划', 'settings.magicPrompts.sidebar.group.planning': '规划',
'settings.magicPrompts.sidebar.group.session': '会话', 'settings.magicPrompts.sidebar.group.session': '会话',
'settings.magicPrompts.sidebar.item.gitCommitGenerate': '提交生成', 'settings.magicPrompts.sidebar.item.gitCommitGenerate': '提交生成',
@@ -237,6 +238,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 失败检查审查', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 失败检查审查',
'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR 评论审查', 'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR 评论审查',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '单条 PR 评论审查', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '单条 PR 评论审查',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'MR 审查',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': 'Issue 审查',
'settings.magicPrompts.sidebar.item.planTodo': '待办规划', 'settings.magicPrompts.sidebar.item.planTodo': '待办规划',
'settings.magicPrompts.sidebar.item.planImprove': '改进计划', 'settings.magicPrompts.sidebar.item.planImprove': '改进计划',
'settings.magicPrompts.sidebar.item.planImplement': '执行计划', 'settings.magicPrompts.sidebar.item.planImplement': '执行计划',
@@ -2076,6 +2079,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrCommentsReview.description': '用于 PR 评论分析的提示词。', 'settings.magicPrompts.page.group.githubPrCommentsReview.description': '用于 PR 评论分析的提示词。',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '单条 PR 评论审查', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '单条 PR 评论审查',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '用于单条 PR 评论分析的提示词。', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '用于单条 PR 评论分析的提示词。',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'MR 审查',
'settings.magicPrompts.page.group.gitlabPrReview.description': '用于 GitLab MR 审查流程的提示词:可见用户消息 + 隐藏指令负载。',
'settings.magicPrompts.page.group.gitlabIssueReview.title': 'Issue 审查',
'settings.magicPrompts.page.group.gitlabIssueReview.description': '用于 GitLab Issue 审查流程的提示词:可见用户消息 + 隐藏指令负载。',
'settings.magicPrompts.page.group.gitConflictResolve.title': '合并/Rebase 冲突解决', 'settings.magicPrompts.page.group.gitConflictResolve.title': '合并/Rebase 冲突解决',
'settings.magicPrompts.page.group.gitConflictResolve.description': '用于 AI 解决合并/Rebase 冲突的提示词。', 'settings.magicPrompts.page.group.gitConflictResolve.description': '用于 AI 解决合并/Rebase 冲突的提示词。',
'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 冲突解决', 'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 冲突解决',
@@ -1849,7 +1849,9 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature', 'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature',
'session.newWorktree.actions.change': '更改', 'session.newWorktree.actions.change': '更改',
'session.newWorktree.actions.startFromGitHubIssuePr': '从 GitHub Issue/PR 开始', 'session.newWorktree.actions.startFromGitHubIssuePr': '从 GitHub Issue/PR 开始',
'session.newWorktree.actions.startFromGitLabIssueMr': '从 GitLab Issue/MR 开始',
'session.newWorktree.usingPrBranch': '使用 PR 分支:{branch}', 'session.newWorktree.usingPrBranch': '使用 PR 分支:{branch}',
'session.newWorktree.usingMrBranch': '使用 MR 分支:{branch}',
'session.newWorktree.fromIssue': '来自 Issue #{number}{title}', 'session.newWorktree.fromIssue': '来自 Issue #{number}{title}',
'session.newWorktree.worktreeDirectory': '工作树目录', 'session.newWorktree.worktreeDirectory': '工作树目录',
'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory', 'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory',
@@ -1860,6 +1862,7 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.newBranchFromSource': '新分支将从 {source} 创建', 'session.newWorktree.newBranchFromSource': '新分支将从 {source} 创建',
'session.newWorktree.issueNumber': 'Issue #{number}', 'session.newWorktree.issueNumber': 'Issue #{number}',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.includeDiffBadge': '+差异', 'session.newWorktree.includeDiffBadge': '+差异',
'session.newWorktree.newSessionTitle': '新会话', 'session.newWorktree.newSessionTitle': '新会话',
'session.newWorktree.fromSource': '来自 {source}', 'session.newWorktree.fromSource': '来自 {source}',
@@ -1872,9 +1875,11 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.error.branchNameRequired': '分支名是必填项', 'session.newWorktree.error.branchNameRequired': '分支名是必填项',
'session.newWorktree.error.worktreeDirectoryRequired': '工作树目录为必填项', 'session.newWorktree.error.worktreeDirectoryRequired': '工作树目录为必填项',
'session.newWorktree.error.sendGitHubContextFailed': '发送 GitHub 上下文失败', 'session.newWorktree.error.sendGitHubContextFailed': '发送 GitHub 上下文失败',
'session.newWorktree.error.sendGitLabContextFailed': '发送 GitLab 上下文失败',
'session.newWorktree.error.createWorktreeFailed': '创建工作树失败', 'session.newWorktree.error.createWorktreeFailed': '创建工作树失败',
'session.newWorktree.toast.sessionFromIssue': '已从 Issue 创建会话', 'session.newWorktree.toast.sessionFromIssue': '已从 Issue 创建会话',
'session.newWorktree.toast.sessionFromPr': '已从 PR 创建会话', 'session.newWorktree.toast.sessionFromPr': '已从 PR 创建会话',
'session.newWorktree.toast.sessionFromMr': '已从 Merge Request 创建会话',
'session.newWorktree.toast.worktreeCreated': '工作树已创建', 'session.newWorktree.toast.worktreeCreated': '工作树已创建',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} - 正在后台初始化', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} - 正在后台初始化',
'session.githubIntegration.title': '从 GitHub 选择', 'session.githubIntegration.title': '从 GitHub 选择',
@@ -1899,6 +1904,29 @@ export const dict: Record<I18nKey, string> = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': '该分支已在某个工作树中检出', 'session.githubIntegration.validation.branchAlreadyCheckedOut': '该分支已在某个工作树中检出',
'session.githubIntegration.validation.branchAlreadyExists': '该分支已在本地存在', 'session.githubIntegration.validation.branchAlreadyExists': '该分支已在本地存在',
'session.githubIntegration.validation.failed': '校验失败', 'session.githubIntegration.validation.failed': '校验失败',
'session.gitlabIntegration.title': '从 GitLab 选择',
'session.gitlabIntegration.tabs.issues': 'Issues',
'session.gitlabIntegration.tabs.mergeRequests': 'Merge Requests',
'session.gitlabIntegration.connect.title': '连接到 GitLab',
'session.gitlabIntegration.connect.description': '关联 Issue 或 Merge Request 以自动填充工作树详情',
'session.gitlabIntegration.connect.action': '连接 GitLab',
'session.gitlabIntegration.search.issuesPlaceholder': '搜索 GitLab Issue',
'session.gitlabIntegration.search.mrsPlaceholder': '搜索 GitLab Merge Request',
'session.gitlabIntegration.empty.noIssuesFound': '未找到 Issue',
'session.gitlabIntegration.empty.noMergeRequestsFound': '未找到 Merge Request',
'session.gitlabIntegration.actions.loadMore': '加载更多',
'session.gitlabIntegration.actions.cancel': '取消',
'session.gitlabIntegration.actions.select': '选择',
'session.gitlabIntegration.selected.issueNumber': 'Issue #{number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': '在会话上下文中包含 MR 差异',
'session.gitlabIntegration.includeDiff': '包含 MR 差异',
'session.gitlabIntegration.error.notConnected': 'GitLab 未连接',
'session.gitlabIntegration.error.loadDataFailed': '加载数据失败',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': '该分支已在某个工作树中检出',
'session.gitlabIntegration.validation.branchAlreadyExists': '该分支已在本地存在',
'session.gitlabIntegration.validation.failed': '校验失败',
'session.gitlabIntegration.draftBadge': '草稿',
'chat.fileAttachment.toast.attachFailed': '附加文件失败', 'chat.fileAttachment.toast.attachFailed': '附加文件失败',
'chat.fileAttachment.toast.someFilesSkipped': '以下文件被跳过:\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': '以下文件被跳过:\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': '在 VS Code 中选择文件失败', 'chat.fileAttachment.toast.vscodePickFailed': '在 VS Code 中选择文件失败',
@@ -223,6 +223,7 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.description': '選擇要編輯的提示詞模板。', 'settings.magicPrompts.sidebar.description': '選擇要編輯的提示詞模板。',
'settings.magicPrompts.sidebar.group.git': 'Git', 'settings.magicPrompts.sidebar.group.git': 'Git',
'settings.magicPrompts.sidebar.group.github': 'GitHub', 'settings.magicPrompts.sidebar.group.github': 'GitHub',
'settings.magicPrompts.sidebar.group.gitlab': 'GitLab',
'settings.magicPrompts.sidebar.group.planning': '規劃', 'settings.magicPrompts.sidebar.group.planning': '規劃',
'settings.magicPrompts.sidebar.group.session': '工作階段', 'settings.magicPrompts.sidebar.group.session': '工作階段',
'settings.magicPrompts.sidebar.item.gitCommitGenerate': '提交生成', 'settings.magicPrompts.sidebar.item.gitCommitGenerate': '提交生成',
@@ -234,6 +235,8 @@ export const settingsDict = {
'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 失敗檢查審查', 'settings.magicPrompts.sidebar.item.githubPrFailedChecksReview': 'PR 失敗檢查審查',
'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR 評論審查', 'settings.magicPrompts.sidebar.item.githubPrCommentsReview': 'PR 評論審查',
'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '單則 PR 評論審查', 'settings.magicPrompts.sidebar.item.githubSinglePrCommentReview': '單則 PR 評論審查',
'settings.magicPrompts.sidebar.item.gitlabPrReview': 'MR 審查',
'settings.magicPrompts.sidebar.item.gitlabIssueReview': 'Issue 審查',
'settings.magicPrompts.sidebar.item.planTodo': '待辦規劃', 'settings.magicPrompts.sidebar.item.planTodo': '待辦規劃',
'settings.magicPrompts.sidebar.item.planImprove': '改進計畫', 'settings.magicPrompts.sidebar.item.planImprove': '改進計畫',
'settings.magicPrompts.sidebar.item.planImplement': '執行計畫', 'settings.magicPrompts.sidebar.item.planImplement': '執行計畫',
@@ -1983,6 +1986,10 @@ export const settingsDict = {
'settings.magicPrompts.page.group.githubPrCommentsReview.description': '用於 PR 評論分析的提示詞。', 'settings.magicPrompts.page.group.githubPrCommentsReview.description': '用於 PR 評論分析的提示詞。',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '單則 PR 評論審查', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.title': '單則 PR 評論審查',
'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '用於單則 PR 評論分析的提示詞。', 'settings.magicPrompts.page.group.githubSinglePrCommentReview.description': '用於單則 PR 評論分析的提示詞。',
'settings.magicPrompts.page.group.gitlabPrReview.title': 'MR 審查',
'settings.magicPrompts.page.group.gitlabPrReview.description': '用於 GitLab MR 審查流程的提示詞:可見使用者訊息 + 隱藏指令負載。',
'settings.magicPrompts.page.group.gitlabIssueReview.title': 'Issue 審查',
'settings.magicPrompts.page.group.gitlabIssueReview.description': '用於 GitLab Issue 審查流程的提示詞:可見使用者訊息 + 隱藏指令負載。',
'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase 衝突解決', 'settings.magicPrompts.page.group.gitConflictResolve.title': 'Merge/Rebase 衝突解決',
'settings.magicPrompts.page.group.gitConflictResolve.description': '用於 AI 解決 Merge/Rebase 衝突的提示詞。', 'settings.magicPrompts.page.group.gitConflictResolve.description': '用於 AI 解決 Merge/Rebase 衝突的提示詞。',
'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 衝突解決', 'settings.magicPrompts.page.group.gitCherrypickConflictResolve.title': 'Cherry-pick 衝突解決',
@@ -1853,7 +1853,9 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature', 'session.newWorktree.branchNamePlaceholder': 'feature/my-awesome-feature',
'session.newWorktree.actions.change': '變更', 'session.newWorktree.actions.change': '變更',
'session.newWorktree.actions.startFromGitHubIssuePr': '從 GitHub Issue/PR 開始', 'session.newWorktree.actions.startFromGitHubIssuePr': '從 GitHub Issue/PR 開始',
'session.newWorktree.actions.startFromGitLabIssueMr': '從 GitLab Issue/MR 開始',
'session.newWorktree.usingPrBranch': '使用 PR 分支:{branch}', 'session.newWorktree.usingPrBranch': '使用 PR 分支:{branch}',
'session.newWorktree.usingMrBranch': '使用 MR 分支:{branch}',
'session.newWorktree.fromIssue': '來自 Issue #{number}{title}', 'session.newWorktree.fromIssue': '來自 Issue #{number}{title}',
'session.newWorktree.worktreeDirectory': 'Worktree 目錄', 'session.newWorktree.worktreeDirectory': 'Worktree 目錄',
'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory', 'session.newWorktree.worktreeDirectoryPlaceholder': 'my-worktree-directory',
@@ -1864,6 +1866,7 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.newBranchFromSource': '新分支將從 {source} 建立', 'session.newWorktree.newBranchFromSource': '新分支將從 {source} 建立',
'session.newWorktree.issueNumber': 'Issue #{number}', 'session.newWorktree.issueNumber': 'Issue #{number}',
'session.newWorktree.prNumber': 'PR #{number}', 'session.newWorktree.prNumber': 'PR #{number}',
'session.newWorktree.mrNumber': 'MR #{number}',
'session.newWorktree.includeDiffBadge': '+diff', 'session.newWorktree.includeDiffBadge': '+diff',
'session.newWorktree.newSessionTitle': '新會話', 'session.newWorktree.newSessionTitle': '新會話',
'session.newWorktree.fromSource': '來自 {source}', 'session.newWorktree.fromSource': '來自 {source}',
@@ -1876,9 +1879,11 @@ export const dict: Record<I18nKey, string> = {
'session.newWorktree.error.branchNameRequired': '分支名稱是必填項', 'session.newWorktree.error.branchNameRequired': '分支名稱是必填項',
'session.newWorktree.error.worktreeDirectoryRequired': 'Worktree 目錄是必填項', 'session.newWorktree.error.worktreeDirectoryRequired': 'Worktree 目錄是必填項',
'session.newWorktree.error.sendGitHubContextFailed': '傳送 GitHub 上下文失敗', 'session.newWorktree.error.sendGitHubContextFailed': '傳送 GitHub 上下文失敗',
'session.newWorktree.error.sendGitLabContextFailed': '傳送 GitLab 上下文失敗',
'session.newWorktree.error.createWorktreeFailed': '建立 Worktree 失敗', 'session.newWorktree.error.createWorktreeFailed': '建立 Worktree 失敗',
'session.newWorktree.toast.sessionFromIssue': '已從 Issue 建立會話', 'session.newWorktree.toast.sessionFromIssue': '已從 Issue 建立會話',
'session.newWorktree.toast.sessionFromPr': '已從 PR 建立會話', 'session.newWorktree.toast.sessionFromPr': '已從 PR 建立會話',
'session.newWorktree.toast.sessionFromMr': '已從 Merge Request 建立會話',
'session.newWorktree.toast.worktreeCreated': 'Worktree 已建立', 'session.newWorktree.toast.worktreeCreated': 'Worktree 已建立',
'session.newWorktree.toast.worktreeCreatedDescription': '{target} - 正在背景初始化', 'session.newWorktree.toast.worktreeCreatedDescription': '{target} - 正在背景初始化',
'session.githubIntegration.title': '從 GitHub 選擇', 'session.githubIntegration.title': '從 GitHub 選擇',
@@ -1903,6 +1908,29 @@ export const dict: Record<I18nKey, string> = {
'session.githubIntegration.validation.branchAlreadyCheckedOut': '該分支已在某個 worktree 中簽出', 'session.githubIntegration.validation.branchAlreadyCheckedOut': '該分支已在某個 worktree 中簽出',
'session.githubIntegration.validation.branchAlreadyExists': '該分支已在本地存在', 'session.githubIntegration.validation.branchAlreadyExists': '該分支已在本地存在',
'session.githubIntegration.validation.failed': '驗證失敗', 'session.githubIntegration.validation.failed': '驗證失敗',
'session.gitlabIntegration.title': '從 GitLab 選擇',
'session.gitlabIntegration.tabs.issues': 'Issues',
'session.gitlabIntegration.tabs.mergeRequests': 'Merge Requests',
'session.gitlabIntegration.connect.title': '連接到 GitLab',
'session.gitlabIntegration.connect.description': '關聯 Issue 或 Merge Request 以自動填入 worktree 詳情',
'session.gitlabIntegration.connect.action': '連接 GitLab',
'session.gitlabIntegration.search.issuesPlaceholder': '搜尋 GitLab Issue',
'session.gitlabIntegration.search.mrsPlaceholder': '搜尋 GitLab Merge Request',
'session.gitlabIntegration.empty.noIssuesFound': '找不到 Issue',
'session.gitlabIntegration.empty.noMergeRequestsFound': '找不到 Merge Request',
'session.gitlabIntegration.actions.loadMore': '載入更多',
'session.gitlabIntegration.actions.cancel': '取消',
'session.gitlabIntegration.actions.select': '選擇',
'session.gitlabIntegration.selected.issueNumber': 'Issue #{number}',
'session.gitlabIntegration.selected.mrNumber': 'MR #{number}',
'session.gitlabIntegration.includeDiffAria': '在會話上下文中包含 MR diff',
'session.gitlabIntegration.includeDiff': '包含 MR diff',
'session.gitlabIntegration.error.notConnected': 'GitLab 未連線',
'session.gitlabIntegration.error.loadDataFailed': '載入資料失敗',
'session.gitlabIntegration.validation.branchAlreadyCheckedOut': '該分支已在某個 worktree 中簽出',
'session.gitlabIntegration.validation.branchAlreadyExists': '該分支已在本地存在',
'session.gitlabIntegration.validation.failed': '驗證失敗',
'session.gitlabIntegration.draftBadge': '草稿',
'chat.fileAttachment.toast.attachFailed': '附加檔案失敗', 'chat.fileAttachment.toast.attachFailed': '附加檔案失敗',
'chat.fileAttachment.toast.someFilesSkipped': '以下檔案被跳過:\n{summary}', 'chat.fileAttachment.toast.someFilesSkipped': '以下檔案被跳過:\n{summary}',
'chat.fileAttachment.toast.vscodePickFailed': '在 VS Code 中選擇檔案失敗', 'chat.fileAttachment.toast.vscodePickFailed': '在 VS Code 中選擇檔案失敗',
+31
View File
@@ -51,6 +51,37 @@ describe('buildLinkedIssue', () => {
expect(built.kind).toBe('pull'); expect(built.kind).toBe('pull');
}); });
test('parses GitLab issue urls with nested namespaces on any host', () => {
const built = buildLinkedIssue({
url: 'https://gitlab.example.com/a/b/project/-/issues/5',
number: 5,
title: 'Nested issue',
kind: 'issue',
linkedAt: 5,
});
expect(built.id).toBe('a/b/project#5');
});
test('parses GitLab merge request urls, including legacy non-/- paths', () => {
const modern = buildLinkedIssue({
url: 'https://gitlab.com/owner/repo/-/merge_requests/7',
number: 7,
title: 'Modern MR',
kind: 'pull',
linkedAt: 5,
});
expect(modern.id).toBe('owner/repo#7');
const legacy = buildLinkedIssue({
url: 'https://gitlab.example.com/owner/repo/merge_requests/9',
number: 9,
title: 'Legacy MR',
kind: 'pull',
linkedAt: 5,
});
expect(legacy.id).toBe('owner/repo#9');
});
test('falls back to a url-based id for an unparseable url', () => { test('falls back to a url-based id for an unparseable url', () => {
const built = buildLinkedIssue({ const built = buildLinkedIssue({
url: 'https://ghe.internal/x', url: 'https://ghe.internal/x',
+21 -4
View File
@@ -54,6 +54,26 @@ export const buildLinkedIssueId = (owner: string, repo: string, number: number):
* separately. A URL that does not parse falls back to itself, which is still * separately. A URL that does not parse falls back to itself, which is still
* unique per thread the id only has to identify an entry, not be pretty. * unique per thread the id only has to identify an entry, not be pretty.
*/ */
const GITHUB_URL_RE = /github\.com\/([^/]+)\/([^/]+)\//;
// GitLab puts the project path (possibly nested namespaces, e.g. a/b/project)
// before the `/-/issues|/merge_requests/` segment on any host. The legacy
// non-`/-/` issue/merge-request URLs are accepted too.
const GITLAB_URL_RE = /^https?:\/\/[^/]+\/(.+?)\/(?:-\/)?(?:issues|merge_requests)\/\d+/;
const buildStableIssueId = (url: string, number: number): string => {
const githubMatch = GITHUB_URL_RE.exec(url);
if (githubMatch) {
return buildLinkedIssueId(githubMatch[1], githubMatch[2], number);
}
const gitlabMatch = GITLAB_URL_RE.exec(url);
if (gitlabMatch) {
return `${gitlabMatch[1]}#${number}`;
}
return `${url}#${number}`;
};
export const buildLinkedIssue = (input: { export const buildLinkedIssue = (input: {
url: string; url: string;
number: number; number: number;
@@ -62,10 +82,7 @@ export const buildLinkedIssue = (input: {
author?: { login?: string; avatarUrl?: string } | null; author?: { login?: string; avatarUrl?: string } | null;
linkedAt: number; linkedAt: number;
}): LinkedIssue => { }): LinkedIssue => {
const match = /github\.com\/([^/]+)\/([^/]+)\//.exec(input.url); const id = buildStableIssueId(input.url, input.number);
const id = match
? buildLinkedIssueId(match[1], match[2], input.number)
: `${input.url}#${input.number}`;
return { return {
id, id,
+120 -1
View File
@@ -19,6 +19,10 @@ export type MagicPromptId =
| 'github.pr.comments.review.instructions' | 'github.pr.comments.review.instructions'
| 'github.pr.comment.single.visible' | 'github.pr.comment.single.visible'
| 'github.pr.comment.single.instructions' | 'github.pr.comment.single.instructions'
| 'gitlab.pr.review.visible'
| 'gitlab.pr.review.instructions'
| 'gitlab.issue.review.visible'
| 'gitlab.issue.review.instructions'
| 'plan.todo.visible' | 'plan.todo.visible'
| 'plan.todo.instructions' | 'plan.todo.instructions'
| 'plan.improve.visible' | 'plan.improve.visible'
@@ -56,7 +60,7 @@ export interface MagicPromptDefinition {
id: MagicPromptId; id: MagicPromptId;
title: string; title: string;
description: string; description: string;
group: 'Git' | 'GitHub' | 'Planning' | 'Session'; group: 'Git' | 'GitHub' | 'GitLab' | 'Planning' | 'Session';
template: string; template: string;
placeholders?: Array<{ key: string; description: string }>; placeholders?: Array<{ key: string; description: string }>;
} }
@@ -311,6 +315,121 @@ Do not implement changes until I confirm; end with: "Next actions: <1 sentence>"
- Identify exact code areas likely impacted. - Identify exact code areas likely impacted.
- Before proposing a plan: if the reviewer's intent is ambiguous or the required change depends on a tradeoff only I can decide, ask me focused clarifying questions in batches of at most 3 and wait for answers. Do not speculate. - Before proposing a plan: if the reviewer's intent is ambiguous or the required change depends on a tradeoff only I can decide, ask me focused clarifying questions in batches of at most 3 and wait for answers. Do not speculate.
- Once intent is clear, propose a minimal implementation plan and verification steps.`, - Once intent is clear, propose a minimal implementation plan and verification steps.`,
},
{
id: 'gitlab.pr.review.visible',
title: 'MR Review Visible Prompt',
group: 'GitLab',
description: 'Visible user message when creating merge request review requests from GitLab context.',
placeholders: [
{ key: 'mr_number', description: 'Merge request number.' },
],
template: 'Review this merge request !{{mr_number}} using the provided MR context',
},
{
id: 'gitlab.pr.review.instructions',
title: 'MR Review Instructions',
group: 'GitLab',
description: 'Hidden instructions attached when generating a GitLab merge request review response.',
template: `You are drafting a merge request review comment that will be posted back to the MR author. You are not the implementer; do not propose to write code or run commands.
Before drafting:
- Read the MR title and body first to anchor on the author's intent. Evaluate whether the implementation matches that intent missing pieces, incorrect behavior vs intent, scope creep.
- The MR diff is the source of truth for what changed; the repo on disk may not yet reflect those changes. Read the diff carefully. Use the repo only as ancillary context (imports, call sites, existing patterns, nearby code) when you need to verify a specific claim not to discover the changes themselves.
- No speculation: every reported issue must be grounded in the diff plus ancillary repo evidence you actually read. If a claim cannot be verified, drop it do not hedge or guess.
- Clarifying question: if the MR's intent itself is unreadable (title/body give no "why", diff is ambiguous on purpose), ask me one focused question about intent and stop. Do not open a discovery loop this is a review, not a planning session.
High-signal bar only report issues that meet all of:
- Objective and verifiable from the diff plus ancillary repo evidence.
- Introduced by this MR (not pre-existing).
- Material: bugs that will cause incorrect runtime behavior, security/privacy risks, correctness edge cases, backwards-compat breakage, missing implementations across modules/targets, boundary violations, OR a clear CLAUDE.md / AGENTS.md violation where you can quote the exact rule.
Do NOT report:
- Pre-existing issues unrelated to the diff.
- Pedantic nitpicks a senior engineer would not flag.
- Issues a linter would catch.
- Subjective style preferences not explicitly required by CLAUDE.md / AGENTS.md.
- "Might" / "could" / "potential" concerns without concrete evidence.
- Rules mentioned in CLAUDE.md / AGENTS.md but explicitly silenced in the code (e.g., via an ignore comment or documented exception).
- Missing tests / coverage gaps unless CLAUDE.md / AGENTS.md explicitly requires them for the changed area.
Validation pass: before writing the final comment, re-check each candidate issue against the diff + ancillary repo evidence. Drop anything you are not certain about. False positives waste the author's time.
Output rules:
- Produce a single review comment addressed to the MR author, using the exact format below.
- No emojis. No code snippets. No fenced blocks. Short inline code identifiers are fine.
- Reference evidence with file paths and line ranges (e.g., path/to/file.ts:120-138) derived from the diff. Use "approx" only as a last resort when the diff does not expose exact lines.
- One bullet per unique issue; do not duplicate an issue across sections.
- Keep the whole comment under ~300 words.
Format exactly:
<1-2 sentence summary of intent and top-level verdict>
Must-fix:
- <issue> - <brief why> - <file:line-range> - Action: <one-line action>
Nice-to-have:
- <issue> - <brief why> - <file:line-range> - Action: <one-line action>
If nothing clears the high-signal bar, write:
Must-fix:
- None
Nice-to-have:
- None`,
},
{
id: 'gitlab.issue.review.visible',
title: 'Issue Review Visible Prompt',
group: 'GitLab',
description: 'Visible user message when creating issue review requests from GitLab context.',
placeholders: [
{ key: 'issue_number', description: 'Issue number.' },
],
template: 'Review this issue #{{issue_number}} using the provided issue context',
},
{
id: 'gitlab.issue.review.instructions',
title: 'Issue Review Instructions',
group: 'GitLab',
description: 'Hidden instructions attached when generating a GitLab issue review response.',
template: `Review this GitLab issue using the provided issue context.
Process:
- First classify the issue type (bug / feature request / question/support / refactor / ops) and state it as: Type: <one label>.
- Gather any needed repository context (code, config, docs) to validate assumptions.
- After gathering, if anything is still unclear or cannot be verified, do not speculate state what's missing and ask targeted questions.
Mode selection by type:
- Bug / Question/Support / Ops: deliver the response directly using the matching template below. Do not bombard me with questions for straightforward diagnosis; use "Missing info" / "Repro/diagnostics needed" fields instead.
- Feature request / Refactor with substantive unknowns: this is effectively a planning session. Do not emit the Feature template on the first turn. Instead, ask me focused clarifying questions in batches of at most 3, one topic at a time (scope, constraints, tradeoffs, UX, etc.), wait for answers, drop questions that became irrelevant, and repeat until you have no more substantive questions. Only then emit the Feature template.
Output rules:
- Compact output; pick ONE template below and omit the others.
- No emojis. No code snippets. No fenced blocks.
- Short inline code identifiers allowed.
- Reference evidence with file paths and line ranges when applicable; if exact lines are not available, cite the file and say "approx" + why.
- Keep the entire response under ~300 words (applies to the final template output, not to clarifying-question turns).
Templates (choose one):
Bug:
- Summary (1-2 sentences)
- Likely cause (max 2)
- Repro/diagnostics needed (max 3)
- Fix approach (max 4 steps)
- Verification (max 3)
Feature:
- Summary (1-2 sentences)
- Requirements (max 4)
- Unknowns/questions (max 4)
- Proposed plan (max 5 steps)
- Verification (max 3)
Question/Support:
- Summary (1-2 sentences)
- Answer/guidance (max 6 lines)
- Missing info (max 4)
Do not implement changes until I confirm; end with: "Next actions: <1 sentence>".`,
}, },
{ {
id: 'git.conflict.resolve.visible', id: 'git.conflict.resolve.visible',