From 8fc08853b3a1be163f9c549b4d9e9c0e82ae7fc0 Mon Sep 17 00:00:00 2001 From: mattv8 Date: Thu, 20 Aug 2026 13:32:51 -0600 Subject: [PATCH] feat(sessions): confirm dirty-source worktree moves --- .../SessionWorktreeMoveConfirmDialog.test.tsx | 106 ++++++++++++++++++ .../SessionWorktreeMoveConfirmDialog.tsx | 81 +++++++++++++ packages/ui/src/lib/i18n/messages/de.ts | 14 ++- packages/ui/src/lib/i18n/messages/en.ts | 14 ++- packages/ui/src/lib/i18n/messages/es.ts | 14 ++- packages/ui/src/lib/i18n/messages/fr.ts | 14 ++- packages/ui/src/lib/i18n/messages/ja.ts | 14 ++- packages/ui/src/lib/i18n/messages/ko.ts | 14 ++- packages/ui/src/lib/i18n/messages/pl.ts | 14 ++- packages/ui/src/lib/i18n/messages/pt-BR.ts | 14 ++- packages/ui/src/lib/i18n/messages/uk.ts | 14 ++- packages/ui/src/lib/i18n/messages/zh-CN.ts | 14 ++- packages/ui/src/lib/i18n/messages/zh-TW.ts | 14 ++- 13 files changed, 330 insertions(+), 11 deletions(-) create mode 100644 packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.test.tsx create mode 100644 packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.tsx diff --git a/packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.test.tsx b/packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.test.tsx new file mode 100644 index 00000000..3920ec4d --- /dev/null +++ b/packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.test.tsx @@ -0,0 +1,106 @@ +import React from 'react'; +import { describe, expect, mock, test } from 'bun:test'; +import { renderToStaticMarkup } from 'react-dom/server'; + +import { I18nProvider } from '@/lib/i18n'; +import type { Session } from '@opencode-ai/sdk/v2'; +import type { + SessionTreeMoveIntent, + SessionTreeMoveMessages, +} from '@/lib/worktrees/sessionWorktreeMove'; + +type MockDialogProps = React.PropsWithChildren<{ + open?: boolean; + id?: string; + className?: string; +}>; + +mock.module('@/components/ui/dialog', () => ({ + Dialog: ({ children, open = true }: MockDialogProps) => (open ? <>{children} : null), + DialogContent: ({ children, id, className }: MockDialogProps) => ( +
{children}
+ ), + DialogDescription: ({ children }: MockDialogProps) =>

{children}

, + DialogFooter: ({ children, className }: MockDialogProps) =>
{children}
, + DialogHeader: ({ children }: MockDialogProps) =>
{children}
, + DialogTitle: ({ children }: MockDialogProps) =>

{children}

, +})); + +const { SessionWorktreeMoveConfirmDialog } = await import('./SessionWorktreeMoveConfirmDialog'); + +const makeMoveMessages = (): SessionTreeMoveMessages => ({ + success: 'move succeeded', + failure: 'move failed', + sourceVerificationFailed: 'source verification failed', + applyChangesFailed: 'apply changes failed', +}); + +const makeExistingIntent = (): SessionTreeMoveIntent => ({ + kind: 'existing', + root: { + id: 'root', + slug: 'root', + projectID: 'project-1', + directory: '/source', + title: 'Root session', + version: '1', + time: { created: 0, updated: 0 }, + } satisfies Session, + descendants: [], + sourceDirectory: '/source', + destination: { + path: '/destination', + projectDirectory: '/repo', + branch: 'feature', + label: 'Destination', + worktreeStatus: 'ready', + worktreeSource: 'existing', + }, + messages: makeMoveMessages(), +}); + +describe('SessionWorktreeMoveConfirmDialog', () => { + test('renders stable semantic hooks, dirty file count, and the staged warning', () => { + const markup = renderToStaticMarkup( + + {}} + onMoveAllChanges={() => {}} + onCancel={() => {}} + /> + , + ); + + expect(markup).toContain('id="session-worktree-move-confirm-dialog"'); + expect(markup).toContain('data-session-worktree-move-action="session-only"'); + expect(markup).toContain('data-session-worktree-move-action="all-changes"'); + expect(markup).toContain('data-session-worktree-move-action="cancel"'); + expect(markup).toContain('autofocus=""'); + expect(markup).toContain('2'); + expect(markup).toContain('data-session-worktree-move-staged-warning="true"'); + }); + + test('omits the staged warning when no staged files are present', () => { + const markup = renderToStaticMarkup( + + {}} + onMoveAllChanges={() => {}} + onCancel={() => {}} + /> + , + ); + + expect(markup).not.toContain('data-session-worktree-move-staged-warning="true"'); + }); +}); diff --git a/packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.tsx b/packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.tsx new file mode 100644 index 00000000..fe6ecca3 --- /dev/null +++ b/packages/ui/src/components/session/sidebar/SessionWorktreeMoveConfirmDialog.tsx @@ -0,0 +1,81 @@ +import React from 'react'; + +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { useI18n } from '@/lib/i18n'; +import type { SessionTreeMoveConfirmation } from '@/lib/worktrees/sessionWorktreeMove'; + +export type SessionWorktreeMoveConfirmDialogProps = { + value: SessionTreeMoveConfirmation | null; + onMoveSessionOnly: () => void; + onMoveAllChanges: () => void; + onCancel: () => void; +}; + +export function SessionWorktreeMoveConfirmDialog(props: SessionWorktreeMoveConfirmDialogProps): React.ReactNode { + const { t } = useI18n(); + const { value, onMoveSessionOnly, onMoveAllChanges, onCancel } = props; + + return ( + { if (!open) onCancel(); }}> + + + {t('sessions.sidebar.session.moveToWorktree.confirm.title')} + + {t('sessions.sidebar.session.moveToWorktree.confirm.changedFiles', { + count: value?.dirtyFileCount ?? 0, + })}{' '} + {t('sessions.sidebar.session.moveToWorktree.confirm.ownership')} + + +
+

{t('sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp')}

+

{t('sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp')}

+ {value && value.stagedFileCount > 0 ? ( +

+ {t('sessions.sidebar.session.moveToWorktree.confirm.stagedWarning')} +

+ ) : null} +

{t('sessions.sidebar.session.moveToWorktree.confirm.baseWarning')}

+
+ + + + + +
+
+ ); +} diff --git a/packages/ui/src/lib/i18n/messages/de.ts b/packages/ui/src/lib/i18n/messages/de.ts index caab5042..3e57a00f 100644 --- a/packages/ui/src/lib/i18n/messages/de.ts +++ b/packages/ui/src/lib/i18n/messages/de.ts @@ -2999,9 +2999,21 @@ export const dict = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': 'Sitzung in Worktree verschoben', 'sessions.sidebar.session.moveToWorktree.existingFailed': 'Sitzung konnte nicht in Worktree verschoben werden', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': 'Zeigt vorhandene Worktrees und die Option, für diese Sitzung einen neuen zu erstellen.', - 'sessions.sidebar.session.moveToWorktree.tooltip': 'Erstellt einen neuen Worktree aus dem aktuellen Branch, überträgt nicht gespeicherte Änderungen und verschiebt diese Sitzung samt Untersitzungen dorthin.', + 'sessions.sidebar.session.moveToWorktree.tooltip': 'Erstellt einen neuen Worktree aus dem aktuellen Branch und verschiebt diese Sitzung samt Untersitzungen dorthin. Bei ungespeicherten Änderungen in der Quelle wählst du, ob sie mit verschoben werden.', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': 'Verfügbar, wenn die Sitzung inaktiv ist. Warten Sie oder beenden Sie die aktuelle Aktivität.', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': 'Diese Sitzung wird bereits in einen neuen Worktree verschoben.', + 'sessions.sidebar.session.moveToWorktree.confirm.title': 'Die Quelle hat ungespeicherte Änderungen', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': 'Geänderte Dateien in diesem Worktree: {count}.', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCode verfolgt diese Änderungen nach Verzeichnis, nicht nach Sitzung.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': 'Verschiebt diese Sitzung und ihre Untersitzungen, ohne die Quelldateien zu verändern.', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': 'Überträgt die Änderungen im Sitzungsverzeichnis. Nicht committete und unversionierte Dateien verlassen die Quelle nach Erfolg.', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': 'Gemappte (staged) Änderungen bleiben in der Quelle und werden ans Ziel kopiert.', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': 'Die Übertragung kann fehlschlagen, wenn das Ziel eine andere Git-Basis verwendet.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': 'Nur Sitzung verschieben', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': 'Alle Quelländerungen verschieben', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': 'Abbrechen', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': 'Die Änderungen in der Quelle konnten nicht geprüft werden. Es wurde kein Worktree und keine Sitzung geändert.', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': 'Das Ziel konnte die Änderungen der Quelle nicht übernehmen. Sitzung und Änderungen wurden nicht verschoben. Versuche es erneut und wähle Nur Sitzung verschieben.', 'sessions.sidebar.session.export.failedLoadHistory': 'Die vollständige Sitzungshistorie konnte nicht geladen werden', 'sessions.sidebar.session.status.movingToWorktree': 'Sitzung wird in einen neuen Worktree verschoben', 'gitView.header.updateBranch': 'Branch aktualisieren', diff --git a/packages/ui/src/lib/i18n/messages/en.ts b/packages/ui/src/lib/i18n/messages/en.ts index 2d820570..080b4fb6 100644 --- a/packages/ui/src/lib/i18n/messages/en.ts +++ b/packages/ui/src/lib/i18n/messages/en.ts @@ -547,9 +547,21 @@ export const dict = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': 'Session moved to worktree', 'sessions.sidebar.session.moveToWorktree.existingFailed': 'Failed to move session to worktree', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': 'Shows existing worktrees and the option to create a new one for this session.', - 'sessions.sidebar.session.moveToWorktree.tooltip': 'Creates a new worktree from the current branch, transfers uncommitted changes, and moves this session and its sub-sessions there.', + 'sessions.sidebar.session.moveToWorktree.tooltip': 'Creates a new worktree from the current branch and moves this session and its sub-sessions there. When the source has uncommitted changes, you choose whether to move them.', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': 'Available when the session is idle. Stop or wait for the current activity to finish.', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': 'This session is already being moved to a new worktree.', + 'sessions.sidebar.session.moveToWorktree.confirm.title': 'Source has uncommitted changes', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': 'Changed files in this worktree: {count}.', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCode tracks these changes by directory, not by session.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': 'Move this session and its sub-sessions while leaving every source file unchanged.', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': 'Transfer changes under the session directory. Unstaged and untracked files leave the source after success.', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': 'Staged changes remain in the source and are copied to the destination.', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': 'The transfer can fail when the destination uses a different Git base.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': 'Move session only', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': 'Move all source changes', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': 'Cancel', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': 'Source changes could not be verified. No worktree or session was changed.', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': 'The destination could not accept the source changes. The session and source changes were not moved. Retry and choose Move session only.', 'sessions.sidebar.session.menu.runFusion': 'Run fusion', 'sessions.sidebar.session.menu.openInSidePanel': 'Open in Side Panel', 'sessions.sidebar.session.actions.openInEditor': 'Open in Editor', diff --git a/packages/ui/src/lib/i18n/messages/es.ts b/packages/ui/src/lib/i18n/messages/es.ts index 8b8b656b..e565a91b 100644 --- a/packages/ui/src/lib/i18n/messages/es.ts +++ b/packages/ui/src/lib/i18n/messages/es.ts @@ -548,9 +548,21 @@ export const dict: Record = { "sessions.sidebar.session.moveToWorktree.existingSuccess": "Sesión movida al worktree", "sessions.sidebar.session.moveToWorktree.existingFailed": "No se pudo mover la sesión al worktree", "sessions.sidebar.session.moveToWorktree.tooltipTargets": "Muestra los worktrees existentes y la opción de crear uno nuevo para esta sesión.", - "sessions.sidebar.session.moveToWorktree.tooltip": "Crea un worktree nuevo desde la rama actual, transfiere los cambios sin confirmar y mueve allí esta sesión y sus subsesiones.", + "sessions.sidebar.session.moveToWorktree.tooltip": "Crea un worktree nuevo desde la rama actual y mueve allí esta sesión y sus subsesiones. Si la fuente tiene cambios sin confirmar, decides si se transfieren.", "sessions.sidebar.session.moveToWorktree.tooltipBusy": "Disponible cuando la sesión está inactiva. Detén la actividad actual o espera a que termine.", "sessions.sidebar.session.moveToWorktree.tooltipMoving": "Esta sesión ya se está moviendo a un worktree nuevo.", + "sessions.sidebar.session.moveToWorktree.confirm.title": "La fuente tiene cambios sin confirmar", + "sessions.sidebar.session.moveToWorktree.confirm.changedFiles": "Archivos modificados en este worktree: {count}.", + "sessions.sidebar.session.moveToWorktree.confirm.ownership": "OpenCode rastrea estos cambios por directorio, no por sesión.", + "sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp": "Mueve esta sesión y sus subsesiones dejando intacto cada archivo de la fuente.", + "sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp": "Transfiere los cambios del directorio de la sesión. Los archivos sin confirmar y sin rastrear salen de la fuente tras el éxito.", + "sessions.sidebar.session.moveToWorktree.confirm.stagedWarning": "Los cambios en el índice permanecen en la fuente y se copian al destino.", + "sessions.sidebar.session.moveToWorktree.confirm.baseWarning": "La transferencia puede fallar si el destino usa una base de Git distinta.", + "sessions.sidebar.session.moveToWorktree.confirm.sessionOnly": "Mover solo la sesión", + "sessions.sidebar.session.moveToWorktree.confirm.allChanges": "Mover todos los cambios de la fuente", + "sessions.sidebar.session.moveToWorktree.confirm.cancel": "Cancelar", + "sessions.sidebar.session.moveToWorktree.sourceVerificationFailed": "No se pudieron verificar los cambios de la fuente. No se modificó ningún worktree ni sesión.", + "sessions.sidebar.session.moveToWorktree.applyChangesFailed": "El destino no pudo aceptar los cambios de la fuente. No se movieron la sesión ni los cambios. Reintenta y elige Mover solo la sesión.", "sessions.sidebar.session.menu.runFusion": "Ejecutar fusion", "sessions.sidebar.session.menu.openInSidePanel": "Abrir en panel lateral", "sessions.sidebar.session.actions.openInEditor": "Abrir en el editor", diff --git a/packages/ui/src/lib/i18n/messages/fr.ts b/packages/ui/src/lib/i18n/messages/fr.ts index 76e05ad3..b1718a0c 100644 --- a/packages/ui/src/lib/i18n/messages/fr.ts +++ b/packages/ui/src/lib/i18n/messages/fr.ts @@ -378,9 +378,21 @@ export const dict = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': 'Session déplacée vers le worktree', 'sessions.sidebar.session.moveToWorktree.existingFailed': 'Impossible de déplacer la session vers le worktree', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': 'Affiche les worktrees existants et l’option d’en créer un nouveau pour cette session.', - 'sessions.sidebar.session.moveToWorktree.tooltip': 'Crée un nouveau worktree depuis la branche actuelle, transfère les modifications non validées et y déplace cette session et ses sous-sessions.', + 'sessions.sidebar.session.moveToWorktree.tooltip': 'Crée un nouveau worktree depuis la branche actuelle et y déplace cette session et ses sous-sessions. Si la source contient des modifications non validées, vous choisissez de les transférer ou non.', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': 'Disponible lorsque la session est inactive. Arrêtez l’activité en cours ou attendez sa fin.', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': 'Cette session est déjà en cours de déplacement vers un nouveau worktree.', + 'sessions.sidebar.session.moveToWorktree.confirm.title': 'La source contient des modifications non validées', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': 'Fichiers modifiés dans ce worktree : {count}.', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCode suit ces modifications par répertoire, pas par session.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': 'Déplace cette session et ses sous-sessions en laissant chaque fichier source inchangé.', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': 'Transfère les modifications du répertoire de la session. Les fichiers non indexés et non suivis quittent la source après succès.', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': 'Les modifications indexées restent dans la source et sont copiées vers la destination.', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': 'Le transfert peut échouer si la destination utilise une base Git différente.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': 'Déplacer la session uniquement', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': 'Déplacer toutes les modifications de la source', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': 'Annuler', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': 'Les modifications de la source n’ont pas pu être vérifiées. Aucun worktree ni session n’a été modifié.', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': 'La destination n’a pas pu accepter les modifications de la source. La session et les modifications n’ont pas été déplacées. Réessayez et choisissez Déplacer la session uniquement.', 'sessions.sidebar.session.menu.runFusion': 'Exécuter la fusion', 'sessions.sidebar.session.menu.openInSidePanel': 'Ouvrir dans le panneau latéral', 'sessions.sidebar.session.actions.openInEditor': 'Ouvrir dans l\'éditeur', diff --git a/packages/ui/src/lib/i18n/messages/ja.ts b/packages/ui/src/lib/i18n/messages/ja.ts index cadc381f..e7b40882 100644 --- a/packages/ui/src/lib/i18n/messages/ja.ts +++ b/packages/ui/src/lib/i18n/messages/ja.ts @@ -548,9 +548,21 @@ export const dict: Record = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': 'セッションをworktreeへ移動しました', 'sessions.sidebar.session.moveToWorktree.existingFailed': 'セッションをworktreeへ移動できませんでした', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': '既存のworktreeと、このセッション用に新しいworktreeを作成するオプションを表示します。', - 'sessions.sidebar.session.moveToWorktree.tooltip': '現在のブランチから新しいworktreeを作成し、未コミットの変更とこのセッションおよびサブセッションを移動します。', + 'sessions.sidebar.session.moveToWorktree.tooltip': '現在のブランチから新しいworktreeを作成し、このセッションとサブセッションをそこへ移動します。ソースに未コミットの変更がある場合は、移動するかどうかを選択します。', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': 'セッションがアイドル状態のときに利用できます。現在の処理を停止するか、完了するまでお待ちください。', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': 'このセッションはすでに新しいworktreeへ移動中です。', + 'sessions.sidebar.session.moveToWorktree.confirm.title': 'ソースに未コミットの変更があります', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': 'このworktree内の変更されたファイル: {count}。', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCodeはこれらの変更をセッションではなくディレクトリ単位で追跡します。', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': 'ソースファイルを一切変更せずに、このセッションとサブセッションを移動します。', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': 'セッションディレクトリ配下の変更を転送します。ステージされていない・追跡されていないファイルは成功後にソースを離れます。', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': 'ステージ済みの変更はソースに残り、宛先へコピーされます。', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': '宛先が異なるGitベースを使用している場合、転送に失敗することがあります。', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': 'セッションのみ移動', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': 'ソースの変更をすべて移動', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': 'キャンセル', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': 'ソースの変更を検証できませんでした。worktreeもセッションも変更されませんでした。', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': '宛先がソースの変更を受け付けられませんでした。セッションもソースの変更も移動されていません。再試行して「セッションのみ移動」を選んでください。', 'sessions.sidebar.session.menu.runFusion': 'フュージョンを実行', 'sessions.sidebar.session.menu.openInSidePanel': 'サイドパネルで開く', 'sessions.sidebar.session.actions.openInEditor': 'エディターで開く', diff --git a/packages/ui/src/lib/i18n/messages/ko.ts b/packages/ui/src/lib/i18n/messages/ko.ts index d8389704..bedcb2b7 100644 --- a/packages/ui/src/lib/i18n/messages/ko.ts +++ b/packages/ui/src/lib/i18n/messages/ko.ts @@ -548,9 +548,21 @@ export const dict: Record = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': '세션을 worktree로 이동했습니다', 'sessions.sidebar.session.moveToWorktree.existingFailed': '세션을 worktree로 이동하지 못했습니다', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': '기존 worktree와 이 세션용 새 worktree를 만드는 옵션을 표시합니다.', - 'sessions.sidebar.session.moveToWorktree.tooltip': '현재 브랜치에서 새 worktree를 만들고 커밋되지 않은 변경 사항과 이 세션 및 하위 세션을 이동합니다.', + 'sessions.sidebar.session.moveToWorktree.tooltip': '현재 브랜치에서 새 worktree를 만들어 이 세션과 하위 세션을 그곳으로 이동합니다. 원본에 커밋되지 않은 변경 사항이 있으면 이동 여부를 선택합니다.', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': '세션이 유휴 상태일 때 사용할 수 있습니다. 현재 작업을 중지하거나 완료될 때까지 기다리세요.', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': '이 세션은 이미 새 worktree로 이동 중입니다.', + 'sessions.sidebar.session.moveToWorktree.confirm.title': '원본에 커밋되지 않은 변경 사항이 있습니다', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': '이 worktree에서 변경된 파일: {count}개.', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCode는 이 변경 사항을 세션이 아닌 디렉터리 기준으로 추적합니다.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': '원본 파일은 그대로 둔 채 이 세션과 하위 세션을 이동합니다.', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': '세션 디렉터리 아래의 변경 사항을 전송합니다. 스테이지되지 않거나 추적되지 않은 파일은 성공 후 원본을 떠납니다.', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': '스테이지된 변경 사항은 원본에 남고 목적지로 복사됩니다.', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': '목적지가 다른 Git 베이스를 사용하면 전송이 실패할 수 있습니다.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': '세션만 이동', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': '원본 변경 사항 모두 이동', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': '취소', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': '원본 변경 사항을 확인하지 못했습니다. worktree와 세션 모두 변경되지 않았습니다.', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': '목적지가 원본 변경 사항을 받아들이지 못했습니다. 세션과 원본 변경 사항이 이동되지 않았습니다. 다시 시도해 세션만 이동을 선택하세요.', 'sessions.sidebar.session.menu.runFusion': 'fusion 실행', 'sessions.sidebar.session.menu.openInSidePanel': '사이드 패널에서 열기', 'sessions.sidebar.session.actions.openInEditor': '편집기에서 열기', diff --git a/packages/ui/src/lib/i18n/messages/pl.ts b/packages/ui/src/lib/i18n/messages/pl.ts index c95038bd..4fd38373 100644 --- a/packages/ui/src/lib/i18n/messages/pl.ts +++ b/packages/ui/src/lib/i18n/messages/pl.ts @@ -341,9 +341,21 @@ export const dict: Record = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': 'Sesję przeniesiono do worktree', 'sessions.sidebar.session.moveToWorktree.existingFailed': 'Nie udało się przenieść sesji do worktree', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': 'Pokazuje istniejące worktree i opcję utworzenia nowego dla tej sesji.', - 'sessions.sidebar.session.moveToWorktree.tooltip': 'Tworzy nowy worktree z bieżącej gałęzi, przenosi niezacommitowane zmiany oraz tę sesję i jej podsesje.', + 'sessions.sidebar.session.moveToWorktree.tooltip': 'Tworzy nowy worktree z bieżącej gałęzi i przenosi tam tę sesję wraz z podsesjami. Jeśli w źródle są niezacommitowane zmiany, decydujesz, czy je przenieść.', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': 'Dostępne, gdy sesja jest bezczynna. Zatrzymaj bieżącą aktywność lub poczekaj na jej zakończenie.', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': 'Ta sesja jest już przenoszona do nowego worktree.', + 'sessions.sidebar.session.moveToWorktree.confirm.title': 'Źródło ma niezacommitowane zmiany', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': 'Zmienione pliki w tym worktree: {count}.', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCode śledzi te zmiany według katalogu, a nie sesji.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': 'Przenosi tę sesję i jej podsesje, pozostawiając każdy plik źródłowy bez zmian.', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': 'Przenosi zmiany w katalogu sesji. Pliki niezacommitowane i nieśledzone opuszczają źródło po sukcesie.', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': 'Zmiany w indeksie pozostają w źródle i są kopiowane do miejsca docelowego.', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': 'Przeniesienie może się nie udać, gdy cel używa innej bazy Git.', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': 'Przenieś tylko sesję', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': 'Przenieś wszystkie zmiany ze źródła', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': 'Anuluj', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': 'Nie udało się zweryfikować zmian w źródle. Żaden worktree ani sesja nie został zmieniony.', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': 'Cel nie mógł przyjąć zmian ze źródła. Sesja i zmiany w źródle nie zostały przeniesione. Spróbuj ponownie i wybierz Przenieś tylko sesję.', 'sessions.sidebar.session.menu.runFusion': 'Uruchom fusion', 'sessions.sidebar.session.menu.openInSidePanel': 'Otwórz w panelu bocznym', 'sessions.sidebar.session.actions.openInEditor': 'Otwórz w edytorze', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.ts b/packages/ui/src/lib/i18n/messages/pt-BR.ts index 8ab01425..4c73c4f3 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.ts @@ -548,9 +548,21 @@ export const dict: Record = { "sessions.sidebar.session.moveToWorktree.existingSuccess": "Sessão movida para o worktree", "sessions.sidebar.session.moveToWorktree.existingFailed": "Não foi possível mover a sessão para o worktree", "sessions.sidebar.session.moveToWorktree.tooltipTargets": "Mostra os worktrees existentes e a opção de criar um novo para esta sessão.", - "sessions.sidebar.session.moveToWorktree.tooltip": "Cria um novo worktree a partir da branch atual, transfere alterações não commitadas e move esta sessão e suas subsessões para lá.", + "sessions.sidebar.session.moveToWorktree.tooltip": "Cria um novo worktree a partir da branch atual e move esta sessão e suas subsessões para lá. Quando a fonte tem alterações não commitadas, você escolhe se as transfere.", "sessions.sidebar.session.moveToWorktree.tooltipBusy": "Disponível quando a sessão está ociosa. Interrompa a atividade atual ou aguarde sua conclusão.", "sessions.sidebar.session.moveToWorktree.tooltipMoving": "Esta sessão já está sendo movida para um novo worktree.", + "sessions.sidebar.session.moveToWorktree.confirm.title": "A fonte tem alterações não commitadas", + "sessions.sidebar.session.moveToWorktree.confirm.changedFiles": "Arquivos alterados neste worktree: {count}.", + "sessions.sidebar.session.moveToWorktree.confirm.ownership": "O OpenCode rastreia essas alterações por diretório, não por sessão.", + "sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp": "Move esta sessão e suas subsessões deixando todos os arquivos da fonte inalterados.", + "sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp": "Transfere as alterações no diretório da sessão. Arquivos não adicionados ao stage e não rastreados saem da fonte após o sucesso.", + "sessions.sidebar.session.moveToWorktree.confirm.stagedWarning": "Alterações já no stage permanecem na fonte e são copiadas para o destino.", + "sessions.sidebar.session.moveToWorktree.confirm.baseWarning": "A transferência pode falhar quando o destino usa uma base do Git diferente.", + "sessions.sidebar.session.moveToWorktree.confirm.sessionOnly": "Mover apenas a sessão", + "sessions.sidebar.session.moveToWorktree.confirm.allChanges": "Mover todas as alterações da fonte", + "sessions.sidebar.session.moveToWorktree.confirm.cancel": "Cancelar", + "sessions.sidebar.session.moveToWorktree.sourceVerificationFailed": "As alterações da fonte não puderam ser verificadas. Nenhum worktree ou sessão foi alterado.", + "sessions.sidebar.session.moveToWorktree.applyChangesFailed": "O destino não pôde aceitar as alterações da fonte. A sessão e as alterações da fonte não foram movidas. Tente novamente e escolha Mover apenas a sessão.", "sessions.sidebar.session.menu.runFusion": "Executar fusion", "sessions.sidebar.session.menu.openInSidePanel": "Abrir no painel lateral", "sessions.sidebar.session.actions.openInEditor": "Abrir no editor", diff --git a/packages/ui/src/lib/i18n/messages/uk.ts b/packages/ui/src/lib/i18n/messages/uk.ts index 5c46ddb0..cf06c3a9 100644 --- a/packages/ui/src/lib/i18n/messages/uk.ts +++ b/packages/ui/src/lib/i18n/messages/uk.ts @@ -548,9 +548,21 @@ export const dict: Record = { "sessions.sidebar.session.moveToWorktree.existingSuccess": "Сесію перенесено в worktree", "sessions.sidebar.session.moveToWorktree.existingFailed": "Не вдалося перенести сесію в worktree", "sessions.sidebar.session.moveToWorktree.tooltipTargets": "Показує наявні worktree і можливість створити новий для цієї сесії.", - "sessions.sidebar.session.moveToWorktree.tooltip": "Створює новий worktree з поточної гілки, переносить незакомічені зміни та переміщує туди цю сесію і її підсесії.", + "sessions.sidebar.session.moveToWorktree.tooltip": "Створює новий worktree з поточної гілки та переміщує туди цю сесію і її підсесії. Якщо у джерелі є незакомічені зміни, ви обираєте, переносити їх чи ні.", "sessions.sidebar.session.moveToWorktree.tooltipBusy": "Доступно, коли сесія неактивна. Зупиніть поточну активність або дочекайтеся її завершення.", "sessions.sidebar.session.moveToWorktree.tooltipMoving": "Ця сесія вже переноситься в новий worktree.", + "sessions.sidebar.session.moveToWorktree.confirm.title": "У джерелі є незакомічені зміни", + "sessions.sidebar.session.moveToWorktree.confirm.changedFiles": "Змінені файли у цьому worktree: {count}.", + "sessions.sidebar.session.moveToWorktree.confirm.ownership": "OpenCode відстежує ці зміни за каталогом, а не за сесією.", + "sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp": "Переносить цю сесію та її підсесії, не змінюючи жодного файла джерела.", + "sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp": "Переносить зміни з каталогу сесії. Незакомічені та невідстежувані файли залишають джерело після успіху.", + "sessions.sidebar.session.moveToWorktree.confirm.stagedWarning": "Закомічені в індекс зміни залишаються в джерелі та копіюються до призначення.", + "sessions.sidebar.session.moveToWorktree.confirm.baseWarning": "Перенесення може не вдатися, якщо призначення використовує іншу базу Git.", + "sessions.sidebar.session.moveToWorktree.confirm.sessionOnly": "Перенести лише сесію", + "sessions.sidebar.session.moveToWorktree.confirm.allChanges": "Перенести всі зміни з джерела", + "sessions.sidebar.session.moveToWorktree.confirm.cancel": "Скасувати", + "sessions.sidebar.session.moveToWorktree.sourceVerificationFailed": "Не вдалося перевірити зміни в джерелі. Жоден worktree чи сесію не змінено.", + "sessions.sidebar.session.moveToWorktree.applyChangesFailed": "Призначення не змогло прийняти зміни з джерела. Сесію та зміни в джерелі не перенесено. Спробуйте знову й оберіть Перенести лише сесію.", "sessions.sidebar.session.menu.runFusion": "Запустити fusion", "sessions.sidebar.session.menu.openInSidePanel": "Відкрити на бічній панелі", "sessions.sidebar.session.actions.openInEditor": "Відкрити в редакторі", diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.ts b/packages/ui/src/lib/i18n/messages/zh-CN.ts index 34504816..a9ccaeff 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.ts @@ -548,9 +548,21 @@ export const dict: Record = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': '会话已移至工作树', 'sessions.sidebar.session.moveToWorktree.existingFailed': '无法将会话移至工作树', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': '显示现有工作树,以及为此会话创建新工作树的选项。', - 'sessions.sidebar.session.moveToWorktree.tooltip': '从当前分支创建新工作树,转移未提交的更改,并将此会话及其子会话移至其中。', + 'sessions.sidebar.session.moveToWorktree.tooltip': '从当前分支创建新工作树,并将此会话及其子会话移至其中。当源有未提交的更改时,由你选择是否一并转移。', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': '仅在会话空闲时可用。请停止当前活动或等待其完成。', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': '此会话已在移至新工作树。', + 'sessions.sidebar.session.moveToWorktree.confirm.title': '源有未提交的更改', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': '此工作树中已更改的文件:{count}。', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCode 按目录而非会话跟踪这些更改。', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': '移动此会话及其子会话,同时保持每个源文件不变。', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': '转移会话目录下的更改。未暂存和未跟踪的文件在成功后离开源。', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': '已暂存的更改保留在源中,并复制到目的地。', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': '当目的地使用不同的 Git 基准时,转移可能失败。', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': '仅移动会话', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': '移动全部源更改', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': '取消', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': '无法验证源的更改。未更改任何工作树或会话。', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': '目的地无法接受源的更改。会话和源更改均未移动。请重试并选择“仅移动会话”。', 'sessions.sidebar.session.menu.runFusion': '运行融合', 'sessions.sidebar.session.menu.openInSidePanel': '在侧边面板中打开', 'sessions.sidebar.session.actions.openInEditor': '在编辑器中打开', diff --git a/packages/ui/src/lib/i18n/messages/zh-TW.ts b/packages/ui/src/lib/i18n/messages/zh-TW.ts index aefcb5e0..47ddc4b1 100644 --- a/packages/ui/src/lib/i18n/messages/zh-TW.ts +++ b/packages/ui/src/lib/i18n/messages/zh-TW.ts @@ -561,9 +561,21 @@ export const dict: Record = { 'sessions.sidebar.session.moveToWorktree.existingSuccess': '工作階段已移至工作樹', 'sessions.sidebar.session.moveToWorktree.existingFailed': '無法將工作階段移至工作樹', 'sessions.sidebar.session.moveToWorktree.tooltipTargets': '顯示現有工作樹,以及為此工作階段建立新工作樹的選項。', - 'sessions.sidebar.session.moveToWorktree.tooltip': '從目前分支建立新工作樹,轉移未提交的變更,並將此工作階段及其子工作階段移至其中。', + 'sessions.sidebar.session.moveToWorktree.tooltip': '從目前分支建立新工作樹,並將此工作階段及其子工作階段移至其中。當來源有未提交的變更時,由你選擇是否一併轉移。', 'sessions.sidebar.session.moveToWorktree.tooltipBusy': '僅在工作階段閒置時可用。請停止目前活動或等待其完成。', 'sessions.sidebar.session.moveToWorktree.tooltipMoving': '此工作階段已在移至新工作樹。', + 'sessions.sidebar.session.moveToWorktree.confirm.title': '來源有未提交的變更', + 'sessions.sidebar.session.moveToWorktree.confirm.changedFiles': '此工作樹中已變更的檔案:{count}。', + 'sessions.sidebar.session.moveToWorktree.confirm.ownership': 'OpenCode 依目錄而非工作階段追蹤這些變更。', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnlyHelp': '移動此工作階段及其子工作階段,同時保持每個來源檔案不變。', + 'sessions.sidebar.session.moveToWorktree.confirm.allChangesHelp': '轉移工作階段目錄下的變更。未暫存與未追蹤的檔案在成功後離開來源。', + 'sessions.sidebar.session.moveToWorktree.confirm.stagedWarning': '已暫存的變更保留在來源中,並複製到目的地。', + 'sessions.sidebar.session.moveToWorktree.confirm.baseWarning': '當目的地使用不同的 Git 基礎時,轉移可能失敗。', + 'sessions.sidebar.session.moveToWorktree.confirm.sessionOnly': '僅移動工作階段', + 'sessions.sidebar.session.moveToWorktree.confirm.allChanges': '移動全部來源變更', + 'sessions.sidebar.session.moveToWorktree.confirm.cancel': '取消', + 'sessions.sidebar.session.moveToWorktree.sourceVerificationFailed': '無法驗證來源的變更。未變更任何工作樹或工作階段。', + 'sessions.sidebar.session.moveToWorktree.applyChangesFailed': '目的地無法接受來源的變更。工作階段與來源變更均未移動。請重試並選擇「僅移動工作階段」。', 'sessions.sidebar.session.menu.runFusion': '執行 fusion', 'sessions.sidebar.session.menu.openInSidePanel': '在側邊面板中開啟', 'sessions.sidebar.session.actions.openInEditor': '在編輯器中開啟',