dsh-ide-git 0.21.2 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/client.js CHANGED
@@ -399,6 +399,30 @@ window.__ModuleLoader__.load({
399
399
  'operation.revert': '还原进行中',
400
400
  'operation.bisect': '二分定位进行中',
401
401
  'operation.hint': '该仓库还有一个多步操作没有结束,先完成或中止它再执行分支级操作',
402
+ 'worktrees.title': '工作树',
403
+ 'worktrees.new': '新建工作树',
404
+ 'worktrees.prune': '清理失效记录',
405
+ 'worktrees.back': '返回',
406
+ 'worktrees.current': '当前',
407
+ 'worktrees.primary': '主工作树',
408
+ 'worktrees.locked': '已锁定',
409
+ 'worktrees.prunable': '可清理',
410
+ 'worktrees.detached': '游离 HEAD',
411
+ 'worktrees.open': '在面板中打开',
412
+ 'worktrees.remove': '移除工作树',
413
+ 'worktrees.removeConfirm': '移除工作树 {path}?',
414
+ 'worktrees.removeDirty': '工作树 {path} 还有未提交的改动。强制移除会永久丢弃这些改动,确定?',
415
+ 'worktrees.path': '路径',
416
+ 'worktrees.branch': '分支',
417
+ 'worktrees.newBranch': '新分支',
418
+ 'worktrees.existingBranch': '已有分支',
419
+ 'worktrees.base': '起点',
420
+ 'worktrees.create': '创建',
421
+ 'worktrees.empty': '没有工作树',
422
+ 'worktrees.pruneConfirm': '清理已在磁盘上消失的工作树记录?',
423
+ 'toast.worktreeAdded': '已创建工作树 {path}',
424
+ 'toast.worktreeRemoved': '已移除工作树 {path}',
425
+ 'toast.worktreePruned': '已清理失效的工作树记录',
402
426
  'confirm.title': '确认操作',
403
427
  'confirm.cancel': '取消',
404
428
  'confirm.ok': '确定',
@@ -741,6 +765,30 @@ window.__ModuleLoader__.load({
741
765
  'operation.revert': 'Revert in progress',
742
766
  'operation.bisect': 'Bisect in progress',
743
767
  'operation.hint': 'This repository still has a multi-step operation open — finish or abort it before branch-level actions',
768
+ 'worktrees.title': 'Worktrees',
769
+ 'worktrees.new': 'New worktree',
770
+ 'worktrees.prune': 'Prune stale entries',
771
+ 'worktrees.back': 'Back',
772
+ 'worktrees.current': 'Current',
773
+ 'worktrees.primary': 'Primary',
774
+ 'worktrees.locked': 'Locked',
775
+ 'worktrees.prunable': 'Prunable',
776
+ 'worktrees.detached': 'Detached HEAD',
777
+ 'worktrees.open': 'Open in panel',
778
+ 'worktrees.remove': 'Remove worktree',
779
+ 'worktrees.removeConfirm': 'Remove worktree {path}?',
780
+ 'worktrees.removeDirty': 'Worktree {path} has uncommitted changes. Force removal permanently discards them. Continue?',
781
+ 'worktrees.path': 'Path',
782
+ 'worktrees.branch': 'Branch',
783
+ 'worktrees.newBranch': 'New branch',
784
+ 'worktrees.existingBranch': 'Existing branch',
785
+ 'worktrees.base': 'Start point',
786
+ 'worktrees.create': 'Create',
787
+ 'worktrees.empty': 'No worktrees',
788
+ 'worktrees.pruneConfirm': 'Prune worktree records whose directories are gone?',
789
+ 'toast.worktreeAdded': 'Created worktree {path}',
790
+ 'toast.worktreeRemoved': 'Removed worktree {path}',
791
+ 'toast.worktreePruned': 'Pruned stale worktree records',
744
792
  'confirm.title': 'Confirm',
745
793
  'confirm.cancel': 'Cancel',
746
794
  'confirm.ok': 'OK',
@@ -1091,6 +1139,30 @@ window.__ModuleLoader__.load({
1091
1139
  'operation.revert': '還原進行中',
1092
1140
  'operation.bisect': 'Bisect 進行中',
1093
1141
  'operation.hint': '呢個存放庫仲有未完成嘅多步操作 —— 請先完成或中止,再進行分支層級嘅操作',
1142
+ 'worktrees.title': '工作樹',
1143
+ 'worktrees.new': '新增工作樹',
1144
+ 'worktrees.prune': '清理失效記錄',
1145
+ 'worktrees.back': '返回',
1146
+ 'worktrees.current': '目前',
1147
+ 'worktrees.primary': '主工作樹',
1148
+ 'worktrees.locked': '已鎖定',
1149
+ 'worktrees.prunable': '可清理',
1150
+ 'worktrees.detached': '分離 HEAD',
1151
+ 'worktrees.open': '喺面板打開',
1152
+ 'worktrees.remove': '移除工作樹',
1153
+ 'worktrees.removeConfirm': '移除工作樹 {path}?',
1154
+ 'worktrees.removeDirty': '工作樹 {path} 仲有未提交嘅改動。強制移除會永久丟棄呢啲改動,確定?',
1155
+ 'worktrees.path': '路徑',
1156
+ 'worktrees.branch': '分支',
1157
+ 'worktrees.newBranch': '新分支',
1158
+ 'worktrees.existingBranch': '現有分支',
1159
+ 'worktrees.base': '起點',
1160
+ 'worktrees.create': '建立',
1161
+ 'worktrees.empty': '冇工作樹',
1162
+ 'worktrees.pruneConfirm': '清理喺磁碟上已經消失嘅工作樹記錄?',
1163
+ 'toast.worktreeAdded': '已建立工作樹 {path}',
1164
+ 'toast.worktreeRemoved': '已移除工作樹 {path}',
1165
+ 'toast.worktreePruned': '已清理失效嘅工作樹記錄',
1094
1166
  'confirm.title': '確認',
1095
1167
  'confirm.cancel': '取消',
1096
1168
  'confirm.ok': '確定',
@@ -1433,6 +1505,30 @@ window.__ModuleLoader__.load({
1433
1505
  'operation.revert': '還原進行中',
1434
1506
  'operation.bisect': 'Bisect 進行中',
1435
1507
  'operation.hint': '這個版本庫仍有未完成的多步驟操作 —— 請先完成或中止,再進行分支層級的操作',
1508
+ 'worktrees.title': '工作樹',
1509
+ 'worktrees.new': '新增工作樹',
1510
+ 'worktrees.prune': '清理失效記錄',
1511
+ 'worktrees.back': '返回',
1512
+ 'worktrees.current': '目前',
1513
+ 'worktrees.primary': '主工作樹',
1514
+ 'worktrees.locked': '已鎖定',
1515
+ 'worktrees.prunable': '可清理',
1516
+ 'worktrees.detached': '分離 HEAD',
1517
+ 'worktrees.open': '在面板中開啟',
1518
+ 'worktrees.remove': '移除工作樹',
1519
+ 'worktrees.removeConfirm': '移除工作樹 {path}?',
1520
+ 'worktrees.removeDirty': '工作樹 {path} 還有未提交的變更。強制移除會永久捨棄這些變更,確定?',
1521
+ 'worktrees.path': '路徑',
1522
+ 'worktrees.branch': '分支',
1523
+ 'worktrees.newBranch': '新分支',
1524
+ 'worktrees.existingBranch': '現有分支',
1525
+ 'worktrees.base': '起點',
1526
+ 'worktrees.create': '建立',
1527
+ 'worktrees.empty': '沒有工作樹',
1528
+ 'worktrees.pruneConfirm': '清理已在磁碟上消失的工作樹記錄?',
1529
+ 'toast.worktreeAdded': '已建立工作樹 {path}',
1530
+ 'toast.worktreeRemoved': '已移除工作樹 {path}',
1531
+ 'toast.worktreePruned': '已清理失效的工作樹記錄',
1436
1532
  'confirm.title': '確認',
1437
1533
  'confirm.cancel': '取消',
1438
1534
  'confirm.ok': '確定',
@@ -1775,6 +1871,30 @@ window.__ModuleLoader__.load({
1775
1871
  'operation.revert': '還原進行中',
1776
1872
  'operation.bisect': 'Bisect 進行中',
1777
1873
  'operation.hint': '呢個存放庫仲有未完成嘅多步操作 —— 請先完成或中止,再進行分支層級嘅操作',
1874
+ 'worktrees.title': '工作樹',
1875
+ 'worktrees.new': '新增工作樹',
1876
+ 'worktrees.prune': '清理失效記錄',
1877
+ 'worktrees.back': '返回',
1878
+ 'worktrees.current': '目前',
1879
+ 'worktrees.primary': '主工作樹',
1880
+ 'worktrees.locked': '已鎖定',
1881
+ 'worktrees.prunable': '可清理',
1882
+ 'worktrees.detached': '分離 HEAD',
1883
+ 'worktrees.open': '在面板中開啟',
1884
+ 'worktrees.remove': '移除工作樹',
1885
+ 'worktrees.removeConfirm': '移除工作樹 {path}?',
1886
+ 'worktrees.removeDirty': '工作樹 {path} 還有未提交的變更。強制移除會永久捨棄這些變更,確定?',
1887
+ 'worktrees.path': '路徑',
1888
+ 'worktrees.branch': '分支',
1889
+ 'worktrees.newBranch': '新分支',
1890
+ 'worktrees.existingBranch': '現有分支',
1891
+ 'worktrees.base': '起點',
1892
+ 'worktrees.create': '建立',
1893
+ 'worktrees.empty': '沒有工作樹',
1894
+ 'worktrees.pruneConfirm': '清理已在磁碟上消失的工作樹記錄?',
1895
+ 'toast.worktreeAdded': '已建立工作樹 {path}',
1896
+ 'toast.worktreeRemoved': '已移除工作樹 {path}',
1897
+ 'toast.worktreePruned': '已清理失效的工作樹記錄',
1778
1898
  'confirm.title': '確認',
1779
1899
  'confirm.cancel': '取消',
1780
1900
  'confirm.ok': '確定',
@@ -2117,6 +2237,30 @@ window.__ModuleLoader__.load({
2117
2237
  'operation.revert': '打ち消し中',
2118
2238
  'operation.bisect': 'bisect 中',
2119
2239
  'operation.hint': 'このリポジトリには未完了の多段階操作があります —— ブランチ操作の前に完了または中止してください',
2240
+ 'worktrees.title': 'ワークツリー',
2241
+ 'worktrees.new': '新しいワークツリー',
2242
+ 'worktrees.prune': '古い記録を整理',
2243
+ 'worktrees.back': '戻る',
2244
+ 'worktrees.current': '現在',
2245
+ 'worktrees.primary': 'メイン',
2246
+ 'worktrees.locked': 'ロック中',
2247
+ 'worktrees.prunable': '整理可能',
2248
+ 'worktrees.detached': '分離 HEAD',
2249
+ 'worktrees.open': 'パネルで開く',
2250
+ 'worktrees.remove': 'ワークツリーを削除',
2251
+ 'worktrees.removeConfirm': 'ワークツリー {path} を削除しますか?',
2252
+ 'worktrees.removeDirty': 'ワークツリー {path} には未コミットの変更があります。強制削除するとこれらの変更は完全に失われます。続行しますか?',
2253
+ 'worktrees.path': 'パス',
2254
+ 'worktrees.branch': 'ブランチ',
2255
+ 'worktrees.newBranch': '新しいブランチ',
2256
+ 'worktrees.existingBranch': '既存のブランチ',
2257
+ 'worktrees.base': '開始点',
2258
+ 'worktrees.create': '作成',
2259
+ 'worktrees.empty': 'ワークツリーはありません',
2260
+ 'worktrees.pruneConfirm': 'ディスク上に存在しないワークツリーの記録を整理しますか?',
2261
+ 'toast.worktreeAdded': 'ワークツリー {path} を作成しました',
2262
+ 'toast.worktreeRemoved': 'ワークツリー {path} を削除しました',
2263
+ 'toast.worktreePruned': '古いワークツリー記録を整理しました',
2120
2264
  'confirm.title': '確認',
2121
2265
  'confirm.cancel': 'キャンセル',
2122
2266
  'confirm.ok': 'OK',
@@ -2459,6 +2603,30 @@ window.__ModuleLoader__.load({
2459
2603
  'operation.revert': '되돌리기 진행 중',
2460
2604
  'operation.bisect': 'bisect 진행 중',
2461
2605
  'operation.hint': '이 저장소에 아직 끝나지 않은 다단계 작업이 있습니다 —— 브랜치 작업 전에 완료하거나 중단하세요',
2606
+ 'worktrees.title': '워크트리',
2607
+ 'worktrees.new': '새 워크트리',
2608
+ 'worktrees.prune': '오래된 기록 정리',
2609
+ 'worktrees.back': '뒤로',
2610
+ 'worktrees.current': '현재',
2611
+ 'worktrees.primary': '기본',
2612
+ 'worktrees.locked': '잠김',
2613
+ 'worktrees.prunable': '정리 가능',
2614
+ 'worktrees.detached': '분리된 HEAD',
2615
+ 'worktrees.open': '패널에서 열기',
2616
+ 'worktrees.remove': '워크트리 제거',
2617
+ 'worktrees.removeConfirm': '워크트리 {path}을(를) 제거할까요?',
2618
+ 'worktrees.removeDirty': '워크트리 {path}에 커밋되지 않은 변경 사항이 있습니다. 강제 제거하면 이 변경 사항이 영구적으로 사라집니다. 계속할까요?',
2619
+ 'worktrees.path': '경로',
2620
+ 'worktrees.branch': '브랜치',
2621
+ 'worktrees.newBranch': '새 브랜치',
2622
+ 'worktrees.existingBranch': '기존 브랜치',
2623
+ 'worktrees.base': '시작점',
2624
+ 'worktrees.create': '만들기',
2625
+ 'worktrees.empty': '워크트리가 없습니다',
2626
+ 'worktrees.pruneConfirm': '디스크에서 사라진 워크트리 기록을 정리할까요?',
2627
+ 'toast.worktreeAdded': '워크트리 {path}을(를) 만들었습니다',
2628
+ 'toast.worktreeRemoved': '워크트리 {path}을(를) 제거했습니다',
2629
+ 'toast.worktreePruned': '오래된 워크트리 기록을 정리했습니다',
2462
2630
  'confirm.title': '확인',
2463
2631
  'confirm.cancel': '취소',
2464
2632
  'confirm.ok': '확인',
@@ -2801,6 +2969,30 @@ window.__ModuleLoader__.load({
2801
2969
  'operation.revert': 'Revert läuft',
2802
2970
  'operation.bisect': 'Bisect läuft',
2803
2971
  'operation.hint': 'In diesem Repository läuft noch eine mehrstufige Operation —— bitte zuerst abschließen oder abbrechen',
2972
+ 'worktrees.title': 'Worktrees',
2973
+ 'worktrees.new': 'Neuer Worktree',
2974
+ 'worktrees.prune': 'Verwaiste Einträge bereinigen',
2975
+ 'worktrees.back': 'Zurück',
2976
+ 'worktrees.current': 'Aktuell',
2977
+ 'worktrees.primary': 'Primär',
2978
+ 'worktrees.locked': 'Gesperrt',
2979
+ 'worktrees.prunable': 'Bereinigbar',
2980
+ 'worktrees.detached': 'Losgelöster HEAD',
2981
+ 'worktrees.open': 'Im Panel öffnen',
2982
+ 'worktrees.remove': 'Worktree entfernen',
2983
+ 'worktrees.removeConfirm': 'Worktree {path} entfernen?',
2984
+ 'worktrees.removeDirty': 'Worktree {path} hat nicht committete Änderungen. Erzwungenes Entfernen verwirft sie dauerhaft. Fortfahren?',
2985
+ 'worktrees.path': 'Pfad',
2986
+ 'worktrees.branch': 'Branch',
2987
+ 'worktrees.newBranch': 'Neuer Branch',
2988
+ 'worktrees.existingBranch': 'Vorhandener Branch',
2989
+ 'worktrees.base': 'Startpunkt',
2990
+ 'worktrees.create': 'Erstellen',
2991
+ 'worktrees.empty': 'Keine Worktrees',
2992
+ 'worktrees.pruneConfirm': 'Einträge für nicht mehr vorhandene Worktrees bereinigen?',
2993
+ 'toast.worktreeAdded': 'Worktree {path} erstellt',
2994
+ 'toast.worktreeRemoved': 'Worktree {path} entfernt',
2995
+ 'toast.worktreePruned': 'Verwaiste Worktree-Einträge bereinigt',
2804
2996
  'confirm.title': 'Bestätigen',
2805
2997
  'confirm.cancel': 'Abbrechen',
2806
2998
  'confirm.ok': 'OK',
@@ -3143,6 +3335,30 @@ window.__ModuleLoader__.load({
3143
3335
  'operation.revert': 'Annulation en cours',
3144
3336
  'operation.bisect': 'Bisect en cours',
3145
3337
  'operation.hint': 'Ce dépôt a encore une opération multi-étapes en cours —— terminez-la ou abandonnez-la avant les actions de branche',
3338
+ 'worktrees.title': 'Arbres de travail',
3339
+ 'worktrees.new': 'Nouvel arbre de travail',
3340
+ 'worktrees.prune': 'Nettoyer les entrées obsolètes',
3341
+ 'worktrees.back': 'Retour',
3342
+ 'worktrees.current': 'Actuel',
3343
+ 'worktrees.primary': 'Principal',
3344
+ 'worktrees.locked': 'Verrouillé',
3345
+ 'worktrees.prunable': 'Nettoyable',
3346
+ 'worktrees.detached': 'HEAD détaché',
3347
+ 'worktrees.open': 'Ouvrir dans le panneau',
3348
+ 'worktrees.remove': 'Supprimer l’arbre de travail',
3349
+ 'worktrees.removeConfirm': 'Supprimer l’arbre de travail {path}?',
3350
+ 'worktrees.removeDirty': 'L’arbre de travail {path} contient des modifications non validées. Une suppression forcée les perdra définitivement. Continuer?',
3351
+ 'worktrees.path': 'Chemin',
3352
+ 'worktrees.branch': 'Branche',
3353
+ 'worktrees.newBranch': 'Nouvelle branche',
3354
+ 'worktrees.existingBranch': 'Branche existante',
3355
+ 'worktrees.base': 'Point de départ',
3356
+ 'worktrees.create': 'Créer',
3357
+ 'worktrees.empty': 'Aucun arbre de travail',
3358
+ 'worktrees.pruneConfirm': 'Nettoyer les enregistrements des arbres de travail disparus du disque?',
3359
+ 'toast.worktreeAdded': 'Arbre de travail {path} créé',
3360
+ 'toast.worktreeRemoved': 'Arbre de travail {path} supprimé',
3361
+ 'toast.worktreePruned': 'Enregistrements obsolètes nettoyés',
3146
3362
  'confirm.title': 'Confirmer',
3147
3363
  'confirm.cancel': 'Annuler',
3148
3364
  'confirm.ok': 'OK',
@@ -3485,6 +3701,30 @@ window.__ModuleLoader__.load({
3485
3701
  'operation.revert': 'Идёт отмена коммита',
3486
3702
  'operation.bisect': 'Идёт bisect',
3487
3703
  'operation.hint': 'В этом репозитории ещё не завершена многошаговая операция —— завершите или прервите её перед действиями с ветками',
3704
+ 'worktrees.title': 'Рабочие деревья',
3705
+ 'worktrees.new': 'Новое рабочее дерево',
3706
+ 'worktrees.prune': 'Очистить устаревшие записи',
3707
+ 'worktrees.back': 'Назад',
3708
+ 'worktrees.current': 'Текущее',
3709
+ 'worktrees.primary': 'Основное',
3710
+ 'worktrees.locked': 'Заблокировано',
3711
+ 'worktrees.prunable': 'Можно очистить',
3712
+ 'worktrees.detached': 'Отсоединённый HEAD',
3713
+ 'worktrees.open': 'Открыть в панели',
3714
+ 'worktrees.remove': 'Удалить рабочее дерево',
3715
+ 'worktrees.removeConfirm': 'Удалить рабочее дерево {path}?',
3716
+ 'worktrees.removeDirty': 'В рабочем дереве {path} есть незакоммиченные изменения. Принудительное удаление безвозвратно их удалит. Продолжить?',
3717
+ 'worktrees.path': 'Путь',
3718
+ 'worktrees.branch': 'Ветка',
3719
+ 'worktrees.newBranch': 'Новая ветка',
3720
+ 'worktrees.existingBranch': 'Существующая ветка',
3721
+ 'worktrees.base': 'Начальная точка',
3722
+ 'worktrees.create': 'Создать',
3723
+ 'worktrees.empty': 'Нет рабочих деревьев',
3724
+ 'worktrees.pruneConfirm': 'Очистить записи рабочих деревьев, исчезнувших с диска?',
3725
+ 'toast.worktreeAdded': 'Рабочее дерево {path} создано',
3726
+ 'toast.worktreeRemoved': 'Рабочее дерево {path} удалено',
3727
+ 'toast.worktreePruned': 'Устаревшие записи очищены',
3488
3728
  'confirm.title': 'Подтверждение',
3489
3729
  'confirm.cancel': 'Отмена',
3490
3730
  'confirm.ok': 'OK',
@@ -3827,6 +4067,30 @@ window.__ModuleLoader__.load({
3827
4067
  'operation.revert': 'Reversão em andamento',
3828
4068
  'operation.bisect': 'Bisect em andamento',
3829
4069
  'operation.hint': 'Este repositório ainda tem uma operação de várias etapas aberta —— conclua ou aborte antes das ações de branch',
4070
+ 'worktrees.title': 'Árvores de trabalho',
4071
+ 'worktrees.new': 'Nova árvore de trabalho',
4072
+ 'worktrees.prune': 'Limpar registros obsoletos',
4073
+ 'worktrees.back': 'Voltar',
4074
+ 'worktrees.current': 'Atual',
4075
+ 'worktrees.primary': 'Principal',
4076
+ 'worktrees.locked': 'Bloqueada',
4077
+ 'worktrees.prunable': 'Limpável',
4078
+ 'worktrees.detached': 'HEAD destacado',
4079
+ 'worktrees.open': 'Abrir no painel',
4080
+ 'worktrees.remove': 'Remover árvore de trabalho',
4081
+ 'worktrees.removeConfirm': 'Remover a árvore de trabalho {path}?',
4082
+ 'worktrees.removeDirty': 'A árvore de trabalho {path} tem alterações não commitadas. A remoção forçada irá descartá-las permanentemente. Continuar?',
4083
+ 'worktrees.path': 'Caminho',
4084
+ 'worktrees.branch': 'Branch',
4085
+ 'worktrees.newBranch': 'Nova branch',
4086
+ 'worktrees.existingBranch': 'Branch existente',
4087
+ 'worktrees.base': 'Ponto de partida',
4088
+ 'worktrees.create': 'Criar',
4089
+ 'worktrees.empty': 'Nenhuma árvore de trabalho',
4090
+ 'worktrees.pruneConfirm': 'Limpar registros de árvores de trabalho que não existem mais no disco?',
4091
+ 'toast.worktreeAdded': 'Árvore de trabalho {path} criada',
4092
+ 'toast.worktreeRemoved': 'Árvore de trabalho {path} removida',
4093
+ 'toast.worktreePruned': 'Registros obsoletos limpos',
3830
4094
  'confirm.title': 'Confirmar',
3831
4095
  'confirm.cancel': 'Cancelar',
3832
4096
  'confirm.ok': 'OK',
@@ -4169,6 +4433,30 @@ window.__ModuleLoader__.load({
4169
4433
  'operation.revert': 'Annullamento in corso',
4170
4434
  'operation.bisect': 'Bisect in corso',
4171
4435
  'operation.hint': 'Questo repository ha ancora un’operazione a più passaggi aperta —— completala o interrompila prima delle azioni sui branch',
4436
+ 'worktrees.title': 'Alberi di lavoro',
4437
+ 'worktrees.new': 'Nuovo albero di lavoro',
4438
+ 'worktrees.prune': 'Pulisci record obsoleti',
4439
+ 'worktrees.back': 'Indietro',
4440
+ 'worktrees.current': 'Attuale',
4441
+ 'worktrees.primary': 'Principale',
4442
+ 'worktrees.locked': 'Bloccato',
4443
+ 'worktrees.prunable': 'Pulibile',
4444
+ 'worktrees.detached': 'HEAD scollegato',
4445
+ 'worktrees.open': 'Apri nel pannello',
4446
+ 'worktrees.remove': 'Rimuovi albero di lavoro',
4447
+ 'worktrees.removeConfirm': 'Rimuovere l’albero di lavoro {path}?',
4448
+ 'worktrees.removeDirty': 'L’albero di lavoro {path} ha modifiche non committate. La rimozione forzata le eliminerà definitivamente. Continuare?',
4449
+ 'worktrees.path': 'Percorso',
4450
+ 'worktrees.branch': 'Branch',
4451
+ 'worktrees.newBranch': 'Nuovo branch',
4452
+ 'worktrees.existingBranch': 'Branch esistente',
4453
+ 'worktrees.base': 'Punto di partenza',
4454
+ 'worktrees.create': 'Crea',
4455
+ 'worktrees.empty': 'Nessun albero di lavoro',
4456
+ 'worktrees.pruneConfirm': 'Pulisci i record degli alberi di lavoro scomparsi dal disco?',
4457
+ 'toast.worktreeAdded': 'Albero di lavoro {path} creato',
4458
+ 'toast.worktreeRemoved': 'Albero di lavoro {path} rimosso',
4459
+ 'toast.worktreePruned': 'Record obsoleti puliti',
4172
4460
  'confirm.title': 'Conferma',
4173
4461
  'confirm.cancel': 'Annulla',
4174
4462
  'confirm.ok': 'OK',
@@ -4511,6 +4799,30 @@ window.__ModuleLoader__.load({
4511
4799
  'operation.revert': 'Terugdraaien bezig',
4512
4800
  'operation.bisect': 'Bisect bezig',
4513
4801
  'operation.hint': 'Deze repository heeft nog een meerstapsbewerking openstaan —— rond die af of breek die af voordat je branchacties uitvoert',
4802
+ 'worktrees.title': 'Werkbomen',
4803
+ 'worktrees.new': 'Nieuwe werkboom',
4804
+ 'worktrees.prune': 'Verouderde records opschonen',
4805
+ 'worktrees.back': 'Terug',
4806
+ 'worktrees.current': 'Huidige',
4807
+ 'worktrees.primary': 'Primair',
4808
+ 'worktrees.locked': 'Vergrendeld',
4809
+ 'worktrees.prunable': 'Opschoonbaar',
4810
+ 'worktrees.detached': 'Losgekoppelde HEAD',
4811
+ 'worktrees.open': 'In paneel openen',
4812
+ 'worktrees.remove': 'Werkboom verwijderen',
4813
+ 'worktrees.removeConfirm': 'Werkboom {path} verwijderen?',
4814
+ 'worktrees.removeDirty': 'Werkboom {path} heeft niet-gecommitte wijzigingen. Geforceerd verwijderen gooit ze definitief weg. Doorgaan?',
4815
+ 'worktrees.path': 'Pad',
4816
+ 'worktrees.branch': 'Branch',
4817
+ 'worktrees.newBranch': 'Nieuwe branch',
4818
+ 'worktrees.existingBranch': 'Bestaande branch',
4819
+ 'worktrees.base': 'Startpunt',
4820
+ 'worktrees.create': 'Aanmaken',
4821
+ 'worktrees.empty': 'Geen werkbomen',
4822
+ 'worktrees.pruneConfirm': 'Records van werkbomen die niet meer op schijf staan opschonen?',
4823
+ 'toast.worktreeAdded': 'Werkboom {path} aangemaakt',
4824
+ 'toast.worktreeRemoved': 'Werkboom {path} verwijderd',
4825
+ 'toast.worktreePruned': 'Verouderde werkboomrecords opgeschoond',
4514
4826
  'confirm.title': 'Bevestigen',
4515
4827
  'confirm.cancel': 'Annuleren',
4516
4828
  'confirm.ok': 'OK',
@@ -4853,6 +5165,30 @@ window.__ModuleLoader__.load({
4853
5165
  'operation.revert': 'Trwa wycofywanie',
4854
5166
  'operation.bisect': 'Trwa bisect',
4855
5167
  'operation.hint': 'W tym repozytorium wciąż trwa wieloetapowa operacja —— zakończ ją lub przerwij przed działaniami na gałęziach',
5168
+ 'worktrees.title': 'Drzewa robocze',
5169
+ 'worktrees.new': 'Nowe drzewo robocze',
5170
+ 'worktrees.prune': 'Wyczyść nieaktualne wpisy',
5171
+ 'worktrees.back': 'Wstecz',
5172
+ 'worktrees.current': 'Bieżące',
5173
+ 'worktrees.primary': 'Główne',
5174
+ 'worktrees.locked': 'Zablokowane',
5175
+ 'worktrees.prunable': 'Do wyczyszczenia',
5176
+ 'worktrees.detached': 'Odłączony HEAD',
5177
+ 'worktrees.open': 'Otwórz w panelu',
5178
+ 'worktrees.remove': 'Usuń drzewo robocze',
5179
+ 'worktrees.removeConfirm': 'Usunąć drzewo robocze {path}?',
5180
+ 'worktrees.removeDirty': 'Drzewo robocze {path} ma niezatwierdzone zmiany. Wymuszone usunięcie bezpowrotnie je utraci. Kontynuować?',
5181
+ 'worktrees.path': 'Ścieżka',
5182
+ 'worktrees.branch': 'Gałąź',
5183
+ 'worktrees.newBranch': 'Nowa gałąź',
5184
+ 'worktrees.existingBranch': 'Istniejąca gałąź',
5185
+ 'worktrees.base': 'Punkt początkowy',
5186
+ 'worktrees.create': 'Utwórz',
5187
+ 'worktrees.empty': 'Brak drzew roboczych',
5188
+ 'worktrees.pruneConfirm': 'Wyczyścić wpisy drzew roboczych, które zniknęły z dysku?',
5189
+ 'toast.worktreeAdded': 'Utworzono drzewo robocze {path}',
5190
+ 'toast.worktreeRemoved': 'Usunięto drzewo robocze {path}',
5191
+ 'toast.worktreePruned': 'Wyczyszczono nieaktualne wpisy',
4856
5192
  'confirm.title': 'Potwierdzenie',
4857
5193
  'confirm.cancel': 'Anuluj',
4858
5194
  'confirm.ok': 'OK',
@@ -5195,6 +5531,30 @@ window.__ModuleLoader__.load({
5195
5531
  'operation.revert': 'Återställning pågår',
5196
5532
  'operation.bisect': 'Bisect pågår',
5197
5533
  'operation.hint': 'Det här arkivet har fortfarande en flerstegsoperation öppen —— slutför eller avbryt den före grenåtgärder',
5534
+ 'worktrees.title': 'Arbetsträd',
5535
+ 'worktrees.new': 'Nytt arbetsträd',
5536
+ 'worktrees.prune': 'Rensa inaktuella poster',
5537
+ 'worktrees.back': 'Tillbaka',
5538
+ 'worktrees.current': 'Aktuellt',
5539
+ 'worktrees.primary': 'Primärt',
5540
+ 'worktrees.locked': 'Låst',
5541
+ 'worktrees.prunable': 'Rensningsbart',
5542
+ 'worktrees.detached': 'Frånkopplad HEAD',
5543
+ 'worktrees.open': 'Öppna i panelen',
5544
+ 'worktrees.remove': 'Ta bort arbetsträd',
5545
+ 'worktrees.removeConfirm': 'Ta bort arbetsträdet {path}?',
5546
+ 'worktrees.removeDirty': 'Arbetsträdet {path} har ej committade ändringar. Tvingad borttagning slänger dem permanent. Fortsätt?',
5547
+ 'worktrees.path': 'Sökväg',
5548
+ 'worktrees.branch': 'Gren',
5549
+ 'worktrees.newBranch': 'Ny gren',
5550
+ 'worktrees.existingBranch': 'Befintlig gren',
5551
+ 'worktrees.base': 'Startpunkt',
5552
+ 'worktrees.create': 'Skapa',
5553
+ 'worktrees.empty': 'Inga arbetsträd',
5554
+ 'worktrees.pruneConfirm': 'Rensa poster för arbetsträd som försvunnit från disken?',
5555
+ 'toast.worktreeAdded': 'Arbetsträdet {path} skapat',
5556
+ 'toast.worktreeRemoved': 'Arbetsträdet {path} borttaget',
5557
+ 'toast.worktreePruned': 'Inaktuella arbetsträdsposter rensade',
5198
5558
  'confirm.title': 'Bekräfta',
5199
5559
  'confirm.cancel': 'Avbryt',
5200
5560
  'confirm.ok': 'OK',
@@ -5537,6 +5897,30 @@ window.__ModuleLoader__.load({
5537
5897
  'operation.revert': 'Geri alma sürüyor',
5538
5898
  'operation.bisect': 'Bisect sürüyor',
5539
5899
  'operation.hint': 'Bu depoda hâlâ açık çok adımlı bir işlem var —— dal işlemlerinden önce tamamlayın veya iptal edin',
5900
+ 'worktrees.title': 'Çalışma ağaçları',
5901
+ 'worktrees.new': 'Yeni çalışma ağacı',
5902
+ 'worktrees.prune': 'Eskimiş kayıtları temizle',
5903
+ 'worktrees.back': 'Geri',
5904
+ 'worktrees.current': 'Geçerli',
5905
+ 'worktrees.primary': 'Birincil',
5906
+ 'worktrees.locked': 'Kilitli',
5907
+ 'worktrees.prunable': 'Temizlenebilir',
5908
+ 'worktrees.detached': 'Ayrık HEAD',
5909
+ 'worktrees.open': 'Panelde aç',
5910
+ 'worktrees.remove': 'Çalışma ağacını kaldır',
5911
+ 'worktrees.removeConfirm': '{path} çalışma ağacı kaldırılsın mı?',
5912
+ 'worktrees.removeDirty': '{path} çalışma ağacında işlenmemiş değişiklikler var. Zorla kaldırma bunları kalıcı olarak siler. Devam?',
5913
+ 'worktrees.path': 'Yol',
5914
+ 'worktrees.branch': 'Dal',
5915
+ 'worktrees.newBranch': 'Yeni dal',
5916
+ 'worktrees.existingBranch': 'Mevcut dal',
5917
+ 'worktrees.base': 'Başlangıç noktası',
5918
+ 'worktrees.create': 'Oluştur',
5919
+ 'worktrees.empty': 'Çalışma ağacı yok',
5920
+ 'worktrees.pruneConfirm': 'Diskten kaybolan çalışma ağacı kayıtları temizlensin mi?',
5921
+ 'toast.worktreeAdded': '{path} çalışma ağacı oluşturuldu',
5922
+ 'toast.worktreeRemoved': '{path} çalışma ağacı kaldırıldı',
5923
+ 'toast.worktreePruned': 'Eskimiş çalışma ağacı kayıtları temizlendi',
5540
5924
  'confirm.title': 'Onayla',
5541
5925
  'confirm.cancel': 'İptal',
5542
5926
  'confirm.ok': 'Tamam',
@@ -5879,6 +6263,30 @@ window.__ModuleLoader__.load({
5879
6263
  'operation.revert': 'Pembatalan berlangsung',
5880
6264
  'operation.bisect': 'Bisect berlangsung',
5881
6265
  'operation.hint': 'Repositori ini masih punya operasi bertahap yang terbuka —— selesaikan atau batalkan sebelum tindakan tingkat branch',
6266
+ 'worktrees.title': 'Worktree',
6267
+ 'worktrees.new': 'Worktree baru',
6268
+ 'worktrees.prune': 'Bersihkan catatan usang',
6269
+ 'worktrees.back': 'Kembali',
6270
+ 'worktrees.current': 'Saat ini',
6271
+ 'worktrees.primary': 'Utama',
6272
+ 'worktrees.locked': 'Terkunci',
6273
+ 'worktrees.prunable': 'Dapat dibersihkan',
6274
+ 'worktrees.detached': 'HEAD terlepas',
6275
+ 'worktrees.open': 'Buka di panel',
6276
+ 'worktrees.remove': 'Hapus worktree',
6277
+ 'worktrees.removeConfirm': 'Hapus worktree {path}?',
6278
+ 'worktrees.removeDirty': 'Worktree {path} memiliki perubahan yang belum di-commit. Penghapusan paksa akan membuangnya secara permanen. Lanjutkan?',
6279
+ 'worktrees.path': 'Jalur',
6280
+ 'worktrees.branch': 'Branch',
6281
+ 'worktrees.newBranch': 'Branch baru',
6282
+ 'worktrees.existingBranch': 'Branch yang ada',
6283
+ 'worktrees.base': 'Titik awal',
6284
+ 'worktrees.create': 'Buat',
6285
+ 'worktrees.empty': 'Tidak ada worktree',
6286
+ 'worktrees.pruneConfirm': 'Bersihkan catatan worktree yang sudah hilang dari disk?',
6287
+ 'toast.worktreeAdded': 'Worktree {path} dibuat',
6288
+ 'toast.worktreeRemoved': 'Worktree {path} dihapus',
6289
+ 'toast.worktreePruned': 'Catatan worktree usang dibersihkan',
5882
6290
  'confirm.title': 'Konfirmasi',
5883
6291
  'confirm.cancel': 'Batal',
5884
6292
  'confirm.ok': 'OK',
@@ -6221,6 +6629,30 @@ window.__ModuleLoader__.load({
6221
6629
  'operation.revert': 'Đang hoàn tác',
6222
6630
  'operation.bisect': 'Đang bisect',
6223
6631
  'operation.hint': 'Kho này vẫn còn một thao tác nhiều bước chưa xong —— hãy hoàn tất hoặc huỷ trước khi thao tác ở mức nhánh',
6632
+ 'worktrees.title': 'Cây làm việc',
6633
+ 'worktrees.new': 'Cây làm việc mới',
6634
+ 'worktrees.prune': 'Dọn bản ghi cũ',
6635
+ 'worktrees.back': 'Quay lại',
6636
+ 'worktrees.current': 'Hiện tại',
6637
+ 'worktrees.primary': 'Chính',
6638
+ 'worktrees.locked': 'Đã khóa',
6639
+ 'worktrees.prunable': 'Có thể dọn',
6640
+ 'worktrees.detached': 'HEAD tách rời',
6641
+ 'worktrees.open': 'Mở trong bảng',
6642
+ 'worktrees.remove': 'Xóa cây làm việc',
6643
+ 'worktrees.removeConfirm': 'Xóa cây làm việc {path}?',
6644
+ 'worktrees.removeDirty': 'Cây làm việc {path} có thay đổi chưa commit. Xóa cưỡng bức sẽ mất vĩnh viễn. Tiếp tục?',
6645
+ 'worktrees.path': 'Đường dẫn',
6646
+ 'worktrees.branch': 'Nhánh',
6647
+ 'worktrees.newBranch': 'Nhánh mới',
6648
+ 'worktrees.existingBranch': 'Nhánh hiện có',
6649
+ 'worktrees.base': 'Điểm bắt đầu',
6650
+ 'worktrees.create': 'Tạo',
6651
+ 'worktrees.empty': 'Không có cây làm việc',
6652
+ 'worktrees.pruneConfirm': 'Dọn bản ghi cây làm việc đã biến mất khỏi ổ đĩa?',
6653
+ 'toast.worktreeAdded': 'Đã tạo cây làm việc {path}',
6654
+ 'toast.worktreeRemoved': 'Đã xóa cây làm việc {path}',
6655
+ 'toast.worktreePruned': 'Đã dọn bản ghi cũ',
6224
6656
  'confirm.title': 'Xác nhận',
6225
6657
  'confirm.cancel': 'Huỷ',
6226
6658
  'confirm.ok': 'OK',
@@ -6563,6 +6995,30 @@ window.__ModuleLoader__.load({
6563
6995
  'operation.revert': 'التراجع جارٍ',
6564
6996
  'operation.bisect': 'bisect جارٍ',
6565
6997
  'operation.hint': 'لا يزال في هذا المستودع إجراء متعدد الخطوات مفتوح —— أكمله أو ألغِه قبل إجراءات الفروع',
6998
+ 'worktrees.title': 'أشجار العمل',
6999
+ 'worktrees.new': 'شجرة عمل جديدة',
7000
+ 'worktrees.prune': 'تنظيف السجلات القديمة',
7001
+ 'worktrees.back': 'رجوع',
7002
+ 'worktrees.current': 'الحالي',
7003
+ 'worktrees.primary': 'الرئيسي',
7004
+ 'worktrees.locked': 'مقفل',
7005
+ 'worktrees.prunable': 'قابل للتنظيف',
7006
+ 'worktrees.detached': 'HEAD منفصل',
7007
+ 'worktrees.open': 'فتح في اللوحة',
7008
+ 'worktrees.remove': 'إزالة شجرة العمل',
7009
+ 'worktrees.removeConfirm': 'إزالة شجرة العمل {path}؟',
7010
+ 'worktrees.removeDirty': 'شجرة العمل {path} تحتوي على تغييرات غير مُودعة. الإزالة القسرية ستحذفها نهائيًا. هل تريد المتابعة؟',
7011
+ 'worktrees.path': 'المسار',
7012
+ 'worktrees.branch': 'الفرع',
7013
+ 'worktrees.newBranch': 'فرع جديد',
7014
+ 'worktrees.existingBranch': 'فرع موجود',
7015
+ 'worktrees.base': 'نقطة البداية',
7016
+ 'worktrees.create': 'إنشاء',
7017
+ 'worktrees.empty': 'لا توجد أشجار عمل',
7018
+ 'worktrees.pruneConfirm': 'تنظيف سجلات أشجار العمل التي اختفت من القرص؟',
7019
+ 'toast.worktreeAdded': 'تم إنشاء شجرة العمل {path}',
7020
+ 'toast.worktreeRemoved': 'تمت إزالة شجرة العمل {path}',
7021
+ 'toast.worktreePruned': 'تم تنظيف السجلات القديمة',
6566
7022
  'confirm.title': 'تأكيد',
6567
7023
  'confirm.cancel': 'إلغاء',
6568
7024
  'confirm.ok': 'موافق',
@@ -6905,6 +7361,30 @@ window.__ModuleLoader__.load({
6905
7361
  'operation.revert': 'वापसी जारी है',
6906
7362
  'operation.bisect': 'bisect जारी है',
6907
7363
  'operation.hint': 'इस रिपॉज़िटरी में अभी एक बहु-चरणीय कार्य खुला है —— शाखा क्रियाओं से पहले उसे पूरा करें या रद्द करें',
7364
+ 'worktrees.title': 'वर्कट्री',
7365
+ 'worktrees.new': 'नई वर्कट्री',
7366
+ 'worktrees.prune': 'पुराने रिकॉर्ड साफ़ करें',
7367
+ 'worktrees.back': 'वापस',
7368
+ 'worktrees.current': 'मौजूदा',
7369
+ 'worktrees.primary': 'प्राथमिक',
7370
+ 'worktrees.locked': 'लॉक किया गया',
7371
+ 'worktrees.prunable': 'साफ़ करने योग्य',
7372
+ 'worktrees.detached': 'अलग HEAD',
7373
+ 'worktrees.open': 'पैनल में खोलें',
7374
+ 'worktrees.remove': 'वर्कट्री हटाएँ',
7375
+ 'worktrees.removeConfirm': 'वर्कट्री {path} हटाएँ?',
7376
+ 'worktrees.removeDirty': 'वर्कट्री {path} में अन-कमिट बदलाव हैं। ज़बरदस्ती हटाने से ये हमेशा के लिए चले जाएँगे। जारी रखें?',
7377
+ 'worktrees.path': 'पाथ',
7378
+ 'worktrees.branch': 'शाखा',
7379
+ 'worktrees.newBranch': 'नई शाखा',
7380
+ 'worktrees.existingBranch': 'मौजूदा शाखा',
7381
+ 'worktrees.base': 'शुरुआती बिंदु',
7382
+ 'worktrees.create': 'बनाएँ',
7383
+ 'worktrees.empty': 'कोई वर्कट्री नहीं',
7384
+ 'worktrees.pruneConfirm': 'डिस्क से गायब वर्कट्री रिकॉर्ड साफ़ करें?',
7385
+ 'toast.worktreeAdded': 'वर्कट्री {path} बनाई गई',
7386
+ 'toast.worktreeRemoved': 'वर्कट्री {path} हटाई गई',
7387
+ 'toast.worktreePruned': 'पुराने वर्कट्री रिकॉर्ड साफ़ किए गए',
6908
7388
  'confirm.title': 'पुष्टि',
6909
7389
  'confirm.cancel': 'रद्द करें',
6910
7390
  'confirm.ok': 'ठीक',
@@ -7247,6 +7727,30 @@ window.__ModuleLoader__.load({
7247
7727
  'operation.revert': 'กำลังย้อน',
7248
7728
  'operation.bisect': 'กำลัง bisect',
7249
7729
  'operation.hint': 'รีโพซิทอรีนี้ยังมีงานหลายขั้นตอนค้างอยู่ —— ทำให้เสร็จหรือยกเลิกก่อนทำการกับแบรนช์',
7730
+ 'worktrees.title': 'เวิร์กทรี',
7731
+ 'worktrees.new': 'เวิร์กทรีใหม่',
7732
+ 'worktrees.prune': 'ล้างบันทึกที่ค้างอยู่',
7733
+ 'worktrees.back': 'กลับ',
7734
+ 'worktrees.current': 'ปัจจุบัน',
7735
+ 'worktrees.primary': 'หลัก',
7736
+ 'worktrees.locked': 'ถูกล็อก',
7737
+ 'worktrees.prunable': 'ล้างได้',
7738
+ 'worktrees.detached': 'HEAD แยก',
7739
+ 'worktrees.open': 'เปิดในแผง',
7740
+ 'worktrees.remove': 'ลบเวิร์กทรี',
7741
+ 'worktrees.removeConfirm': 'ลบเวิร์กทรี {path}?',
7742
+ 'worktrees.removeDirty': 'เวิร์กทรี {path} มีการเปลี่ยนแปลงที่ยังไม่คอมมิต การลบแบบบังคับจะทิ้งถาวร ดำเนินการต่อ?',
7743
+ 'worktrees.path': 'พาธ',
7744
+ 'worktrees.branch': 'แบรนช์',
7745
+ 'worktrees.newBranch': 'แบรนช์ใหม่',
7746
+ 'worktrees.existingBranch': 'แบรนช์ที่มีอยู่',
7747
+ 'worktrees.base': 'จุดเริ่มต้น',
7748
+ 'worktrees.create': 'สร้าง',
7749
+ 'worktrees.empty': 'ไม่มีเวิร์กทรี',
7750
+ 'worktrees.pruneConfirm': 'ล้างบันทึกเวิร์กทรีที่หายไปจากดิสก์?',
7751
+ 'toast.worktreeAdded': 'สร้างเวิร์กทรี {path} แล้ว',
7752
+ 'toast.worktreeRemoved': 'ลบเวิร์กทรี {path} แล้ว',
7753
+ 'toast.worktreePruned': 'ล้างบันทึกเวิร์กทรีที่ค้างแล้ว',
7250
7754
  'confirm.title': 'ยืนยัน',
7251
7755
  'confirm.cancel': 'ยกเลิก',
7252
7756
  'confirm.ok': 'ตกลง',
@@ -7917,6 +8421,7 @@ window.__ModuleLoader__.load({
7917
8421
  compact is the only chrome with a header button, and it used to render
7918
8422
  that button only while the tree was OPEN. */
7919
8423
  { id: 'tree', icon: 'branch', key: 'toolbar.tree', tone: 'secondary' },
8424
+ { id: 'worktrees', icon: 'folder', key: 'worktrees.title', tone: 'secondary' },
7920
8425
  /* The official right-sidebar dock (float / re-dock / split / full screen).
7921
8426
  They only render where that service exists — see dockFaceOf(). */
7922
8427
  { id: 'float', icon: 'float', key: 'action.float', tone: 'accent' },
@@ -7944,7 +8449,7 @@ window.__ModuleLoader__.load({
7944
8449
  const RAIL_IDS = RAIL_SPECS.map((spec) => spec.id)
7945
8450
  /* Actions that arrange the view rather than touch the repository, so a running
7946
8451
  git command never greys them out. */
7947
- const RAIL_VIEW_IDS = ['tree', 'float', 'split', 'fullscreen']
8452
+ const RAIL_VIEW_IDS = ['tree', 'worktrees', 'float', 'split', 'fullscreen']
7948
8453
  const RAIL_DOCK_IDS = ['float', 'split', 'fullscreen']
7949
8454
 
7950
8455
  function normalizeRail(raw) {
@@ -10562,6 +11067,79 @@ window.__ModuleLoader__.load({
10562
11067
  E('button', { type: 'button', className: 'dig-btn dig-btn-primary', disabled: ready === false, onClick: submit }, props.okLabel))))
10563
11068
  }
10564
11069
 
11070
+ /* A worktree create dialog: unlike CloneDialog it has a mode (a NEW branch
11071
+ versus an existing one), so the branch field means two different things
11072
+ and the base field only exists in the first mode. Validation is local
11073
+ (non-empty fields) plus whatever the host rejects; onSubmit resolves to
11074
+ null on success or the message to show under the fields. */
11075
+ function WorktreeDialog(props) {
11076
+ const t = props.t
11077
+ const [mode, setMode] = useState('new')
11078
+ const [path, setPath] = useState('')
11079
+ const [branch, setBranch] = useState('')
11080
+ const [base, setBase] = useState('')
11081
+ const [error, setError] = useState(null)
11082
+ const [sending, setSending] = useState(false)
11083
+ const pathRef = useRef(null)
11084
+ const alive = useRef(true)
11085
+ useEffect(() => { if (pathRef.current !== null) pathRef.current.focus() }, [])
11086
+ useEffect(() => () => { alive.current = false }, [])
11087
+ const ready = path.trim() !== '' && branch.trim() !== '' && sending === false
11088
+ const submit = async () => {
11089
+ if (ready !== true) return
11090
+ const draft = { path: path.trim(), branch: branch.trim(), createBranch: mode === 'new' }
11091
+ if (mode === 'new' && base.trim() !== '') draft.base = base.trim()
11092
+ setError(null)
11093
+ setSending(true)
11094
+ try {
11095
+ const message = await props.onSubmit(draft)
11096
+ if (alive.current === true && typeof message === 'string' && message !== '') setError(message)
11097
+ } finally {
11098
+ if (alive.current === true) setSending(false)
11099
+ }
11100
+ }
11101
+ const onKey = (event) => {
11102
+ if (event.key === 'Enter') { event.preventDefault(); void submit() }
11103
+ if (event.key === 'Escape') { event.preventDefault(); props.onCancel() }
11104
+ }
11105
+ return E('div', { className: 'dig-overlay' },
11106
+ E('div', { className: 'dig-dialog dig-wt-dialog' },
11107
+ E('div', { className: 'dig-dialog-title' }, props.title),
11108
+ E('label', { className: 'dig-wt-field' },
11109
+ E('span', { className: 'dig-wt-label' }, t('worktrees.path')),
11110
+ E('input', {
11111
+ ref: pathRef, className: 'dig-input', value: path, spellCheck: false,
11112
+ placeholder: '/abs/path/to/worktree',
11113
+ onChange: (event) => setPath(event.target.value), onKeyDown: onKey,
11114
+ })),
11115
+ E('div', { className: 'dig-wt-field' },
11116
+ E('span', { className: 'dig-wt-label' }, t('worktrees.branch')),
11117
+ E(Segmented, {
11118
+ value: mode,
11119
+ onChange: setMode,
11120
+ items: [
11121
+ { id: 'new', label: t('worktrees.newBranch') },
11122
+ { id: 'existing', label: t('worktrees.existingBranch') },
11123
+ ],
11124
+ }),
11125
+ E('input', {
11126
+ className: 'dig-input', value: branch, spellCheck: false,
11127
+ placeholder: 'feature/name',
11128
+ onChange: (event) => setBranch(event.target.value), onKeyDown: onKey,
11129
+ })),
11130
+ mode === 'new' ? E('label', { className: 'dig-wt-field' },
11131
+ E('span', { className: 'dig-wt-label' }, t('worktrees.base')),
11132
+ E('input', {
11133
+ className: 'dig-input', value: base, spellCheck: false,
11134
+ placeholder: 'HEAD',
11135
+ onChange: (event) => setBase(event.target.value), onKeyDown: onKey,
11136
+ })) : null,
11137
+ error === null ? null : E('div', { className: 'dig-wt-error' }, error),
11138
+ E('div', { className: 'dig-dialog-actions' },
11139
+ E('button', { type: 'button', className: 'dig-btn', onClick: props.onCancel }, props.cancelLabel),
11140
+ E('button', { type: 'button', className: 'dig-btn dig-btn-primary', disabled: ready !== true, onClick: () => { void submit() } }, t('worktrees.create')))))
11141
+ }
11142
+
10565
11143
  /* VS Code's "Git output" view (showOutput): the tail of the host's git-run
10566
11144
  ring buffer, fetched through the gitLogs method. A debugging view —
10567
11145
  opened on demand, refreshed by hand; newest land at the bottom and the
@@ -11516,7 +12094,7 @@ window.__ModuleLoader__.load({
11516
12094
  title: t('changes.aiQuota'),
11517
12095
  onClick: () => { if (message.trim() === '') void aiRun(); else setAiAsk(true) },
11518
12096
  }, aiBusy === true ? t('changes.aiBusy') : t('changes.aiWrite')),
11519
- E(ModelRoutePicker, { sessionId: props.sessionId, t: t }),
12097
+ E(ModelRoutePicker, { sessionId: props.sessionId, t: t, ctx: props.ctx }),
11520
12098
  E('button', {
11521
12099
  type: 'button', className: 'dig-btn dig-btn-primary dig-btn-small',
11522
12100
  disabled: message.trim() === '' || props.busy === true,
@@ -11538,7 +12116,7 @@ window.__ModuleLoader__.load({
11538
12116
  disabled: aiBusy === true || props.busy === true,
11539
12117
  onClick: () => { if (message.trim() === '') void aiRun(); else setAiAsk(true) },
11540
12118
  }, aiBusy === true ? t('changes.aiBusy') : t('changes.aiWrite')),
11541
- E(ModelRoutePicker, { sessionId: props.sessionId, t: t }),
12119
+ E(ModelRoutePicker, { sessionId: props.sessionId, t: t, ctx: props.ctx }),
11542
12120
  E('span', { className: 'dig-commit-ai-hint' }, t('changes.aiQuota')),
11543
12121
  aiUndo === null ? null : E('button', {
11544
12122
  type: 'button', className: 'dig-link',
@@ -12323,6 +12901,86 @@ window.__ModuleLoader__.load({
12323
12901
  file.deletions > 0 ? E('span', { className: 'dig-stat-del' }, '-' + file.deletions) : null))))
12324
12902
  }
12325
12903
 
12904
+ /* Worktrees view (v0.22.0): the repository's real working trees, read from
12905
+ summary.worktrees (git worktree list --porcelain -z). It is a full-body
12906
+ view rather than a fourth pane: opening one switches the panel's
12907
+ repository to that path, and every row action stays inside the current
12908
+ panel. Current / primary / locked / prunable trees are protected here for
12909
+ the same reasons the host refuses them; the host is still the authority. */
12910
+ function WorktreesPane(props) {
12911
+ const t = props.t
12912
+ const items = Array.isArray(props.worktrees) ? props.worktrees : []
12913
+ const busy = props.busy === true
12914
+ const hasPrunable = items.some((item) => item.prunable === true)
12915
+ const open = (item) => {
12916
+ if (item.current === true || item.prunable === true) return
12917
+ props.onOpen(item.path)
12918
+ }
12919
+ const badgesOf = (item) => {
12920
+ const badges = []
12921
+ if (item.current === true) badges.push({ key: 'current', className: 'dig-wt-badge-current', label: t('worktrees.current'), title: undefined })
12922
+ if (item.primary === true) badges.push({ key: 'primary', className: 'dig-wt-badge-primary', label: t('worktrees.primary'), title: undefined })
12923
+ if (item.locked === true) badges.push({ key: 'locked', className: 'dig-wt-badge-locked', label: t('worktrees.locked'), title: item.lockReason === '' || item.lockReason === undefined ? t('worktrees.locked') : item.lockReason })
12924
+ if (item.prunable === true) badges.push({ key: 'prunable', className: 'dig-wt-badge-prunable', label: t('worktrees.prunable'), title: item.pruneReason === '' || item.pruneReason === undefined ? t('worktrees.prunable') : item.pruneReason })
12925
+ return badges
12926
+ }
12927
+ const removable = (item) => item.current !== true && item.primary !== true && item.locked !== true && item.prunable !== true
12928
+ return E('div', { className: 'dig-wt' },
12929
+ E('div', { className: 'dig-wt-head' },
12930
+ E('span', { className: 'dig-wt-title' }, t('worktrees.title')),
12931
+ E('span', { className: 'dig-wt-count' }, String(items.length)),
12932
+ E('span', { className: 'dig-topbar-spacer' }),
12933
+ E('button', {
12934
+ type: 'button', className: 'dig-icon-btn', title: t('worktrees.new'), disabled: busy,
12935
+ onClick: props.onCreate,
12936
+ }, E(Icon, { name: 'branchCreate', size: 14 })),
12937
+ E('button', {
12938
+ type: 'button', className: 'dig-icon-btn', title: t('worktrees.prune'), disabled: busy || hasPrunable !== true,
12939
+ onClick: props.onPrune,
12940
+ }, E(Icon, { name: 'trash', size: 14 })),
12941
+ E('button', {
12942
+ type: 'button', className: 'dig-icon-btn', title: t('worktrees.back'),
12943
+ onClick: props.onBack,
12944
+ }, E(Icon, { name: 'chevron', size: 14 }))),
12945
+ items.length === 0
12946
+ ? E('div', { className: 'dig-empty' }, t('worktrees.empty'))
12947
+ : E('div', { className: 'dig-wt-scroll' }, items.map((item) => {
12948
+ const badges = badgesOf(item)
12949
+ const label = item.detached === true ? t('worktrees.detached') : String(item.branch === undefined || item.branch === '' ? t('worktrees.detached') : item.branch)
12950
+ return E('div', {
12951
+ key: item.path,
12952
+ className: 'dig-wt-row' + (item.current === true ? ' dig-wt-row-current' : ''),
12953
+ onDoubleClick: () => open(item),
12954
+ },
12955
+ E('div', { className: 'dig-wt-row-main' },
12956
+ E('div', { className: 'dig-wt-top' },
12957
+ E(Icon, { name: item.detached === true ? 'commit' : 'branch', size: 13 }),
12958
+ E('span', { className: 'dig-wt-branch', title: label }, label),
12959
+ badges.length === 0 ? null : E('span', { className: 'dig-wt-badges' }, badges.map((badge) => E('span', {
12960
+ key: badge.key, className: 'dig-wt-badge ' + badge.className, title: badge.title === undefined ? badge.label : badge.title,
12961
+ }, badge.label)))),
12962
+ E('div', { className: 'dig-wt-path dig-mono', title: item.path }, String(item.path)),
12963
+ E('div', { className: 'dig-wt-meta' },
12964
+ item.head === undefined || item.head === null || item.head === '' ? null : E('span', { className: 'dig-wt-hash dig-mono' }, String(item.head).slice(0, 8)),
12965
+ item.pruneReason === '' || item.pruneReason === undefined ? null : E('span', { className: 'dig-wt-reason', title: item.pruneReason }, item.pruneReason))),
12966
+ E('div', { className: 'dig-wt-row-actions' },
12967
+ E('button', {
12968
+ type: 'button', className: 'dig-icon-btn dig-icon-btn-small', title: t('worktrees.open'),
12969
+ disabled: busy || item.current === true || item.prunable === true,
12970
+ onClick: () => open(item),
12971
+ }, E(Icon, { name: 'checkout', size: 13 })),
12972
+ E('button', {
12973
+ type: 'button', className: 'dig-icon-btn dig-icon-btn-small', title: t('action.copyPath'),
12974
+ onClick: () => props.onCopy(item.path),
12975
+ }, E(Icon, { name: 'copy', size: 13 })),
12976
+ E('button', {
12977
+ type: 'button', className: 'dig-icon-btn dig-icon-btn-small', title: t('worktrees.remove'),
12978
+ disabled: busy || removable(item) !== true,
12979
+ onClick: () => props.onRemove(item),
12980
+ }, E(Icon, { name: 'trash', size: 13 }))))
12981
+ })))
12982
+ }
12983
+
12326
12984
  /* ============================== panel ============================== */
12327
12985
 
12328
12986
  function Panel(props) {
@@ -13306,6 +13964,67 @@ window.__ModuleLoader__.load({
13306
13964
  pushToast({ text: fill(t('selection.copied'), { n: values.length }), icon: 'tag', tone: 'ok', ttl: 2500 })
13307
13965
  }, [pushToast, t])
13308
13966
 
13967
+ /* ---------- worktrees (v0.22.0) ---------- */
13968
+ /* These bypass run(): worktreeAdd/Remove/Prune have their own payload
13969
+ shapes and refresh only the repository's worktree list, and a dirty
13970
+ removal is a two-step confirm (the first attempt returns
13971
+ worktree-dirty, which reopens the confirm with the destructive force
13972
+ wording). Busy is held by hand because refresh() has its own guard. */
13973
+ const createWorktree = async (draft) => {
13974
+ setBusy(true)
13975
+ setError(null)
13976
+ try {
13977
+ await request('worktreeAdd', Object.assign({}, base, draft))
13978
+ setDialog(null)
13979
+ pushToast({ text: fill(t('toast.worktreeAdded'), { path: draft.path }), icon: 'check', tone: 'ok' })
13980
+ await refresh()
13981
+ return null
13982
+ } catch (caught) {
13983
+ return caught instanceof Error ? caught.message : String(caught)
13984
+ } finally {
13985
+ setBusy(false)
13986
+ }
13987
+ }
13988
+ const removeWorktree = async (tree, force) => {
13989
+ setBusy(true)
13990
+ setError(null)
13991
+ try {
13992
+ await request('worktreeRemove', Object.assign({}, base, { path: tree.path, confirm: true, force: force === true }))
13993
+ setDialog(null)
13994
+ pushToast({ text: fill(t('toast.worktreeRemoved'), { path: tree.path }), icon: 'check', tone: 'ok' })
13995
+ await refresh()
13996
+ return null
13997
+ } catch (caught) {
13998
+ const message = caught instanceof Error ? caught.message : String(caught)
13999
+ if (caught instanceof Error && caught.code === 'worktree-dirty' && force !== true) {
14000
+ setDialog({ kind: 'worktreeRemove', tree: tree, force: true })
14001
+ return message
14002
+ }
14003
+ setDialog(null)
14004
+ setError(message)
14005
+ return message
14006
+ } finally {
14007
+ setBusy(false)
14008
+ }
14009
+ }
14010
+ const pruneWorktrees = async () => {
14011
+ setBusy(true)
14012
+ setError(null)
14013
+ try {
14014
+ const data = await request('worktreePrune', Object.assign({}, base, { confirm: true }))
14015
+ setDialog(null)
14016
+ pushToast({ text: t('toast.worktreePruned'), icon: 'check', tone: 'ok' })
14017
+ await refresh()
14018
+ return data
14019
+ } catch (caught) {
14020
+ setDialog(null)
14021
+ setError(caught instanceof Error ? caught.message : String(caught))
14022
+ return null
14023
+ } finally {
14024
+ setBusy(false)
14025
+ }
14026
+ }
14027
+
13309
14028
  /* Resolve the change selection against the CURRENT summary: paths move
13310
14029
  between groups on every stage/unstage, so the key ('group:path') is
13311
14030
  the only stable handle and the entry lookup must be fresh. */
@@ -13812,13 +14531,28 @@ window.__ModuleLoader__.load({
13812
14531
  /* ---------- shared pieces ---------- */
13813
14532
 
13814
14533
  const repoOptions = repoState === null ? [] : repoState.repos
14534
+ /* A linked worktree opened from the worktree view is a repository root
14535
+ the workspace scan never listed. Without a header entry the top bar
14536
+ kept naming the primary checkout while every branch and change below
14537
+ it came from the worktree. Append the current root as a transient
14538
+ option so the header names what the panel is actually showing. */
14539
+ let headerRepos = repoOptions
14540
+ if (repoRoot !== null && repoOptions.every((repo) => repo.path !== repoRoot)) {
14541
+ const origin = summary === null ? '' : summary.origin
14542
+ headerRepos = repoOptions.concat([{
14543
+ path: repoRoot,
14544
+ name: origin !== undefined && origin !== null && origin !== '' ? origin : baseNameOf(repoRoot),
14545
+ branch: branches === null ? null : branches.branch,
14546
+ worktree: true,
14547
+ }])
14548
+ }
13815
14549
  const dirty = summary === null ? 0 : summary.changes.staged.length + summary.changes.unstaged.length + summary.changes.untracked.length + summary.changes.conflicted.length
13816
14550
 
13817
14551
  /* Both header switchers are menu-driven now (see RepoSelect): the
13818
14552
  popovers reuse openMenuAt, so they clamp to the panel box and share
13819
14553
  the opaque, frosted menu surface instead of the OS select popup. */
13820
14554
  const openRepoMenu = useCallback((event) => {
13821
- openMenuAt(event, repoOptions.map((repo) => ({
14555
+ openMenuAt(event, headerRepos.map((repo) => ({
13822
14556
  id: 'repo:' + repo.path,
13823
14557
  icon: 'folder',
13824
14558
  tone: 'accent',
@@ -13826,7 +14560,7 @@ window.__ModuleLoader__.load({
13826
14560
  active: repo.path === repoRoot,
13827
14561
  run: () => { if (repo.path !== repoRoot) pickRepo(repo.path) },
13828
14562
  })))
13829
- }, [openMenuAt, repoOptions, repoRoot, pickRepo])
14563
+ }, [openMenuAt, headerRepos, repoRoot, pickRepo])
13830
14564
 
13831
14565
  const openBranchSwitchMenu = useCallback((event) => {
13832
14566
  const local = branches === null ? [] : branches.local
@@ -13842,7 +14576,7 @@ window.__ModuleLoader__.load({
13842
14576
 
13843
14577
  const topBar = E('div', { className: 'dig-topbar' },
13844
14578
  E(RepoSelect, {
13845
- t: t, repos: repoOptions, value: repoRoot,
14579
+ t: t, repos: headerRepos, value: repoRoot,
13846
14580
  loading: repoState === null,
13847
14581
  onOpenMenu: openRepoMenu,
13848
14582
  }),
@@ -14165,7 +14899,7 @@ window.__ModuleLoader__.load({
14165
14899
  }
14166
14900
  const commitSettings = readCommitSettings()
14167
14901
  const changesPane = E(ChangesPanel, {
14168
- t: t, summary: summary, busy: busy, compact: compact, hideHeader: compact,
14902
+ t: t, ctx: props.ctx, summary: summary, busy: busy, compact: compact, hideHeader: compact,
14169
14903
  groupBy: groupBy, sortKey: sortKey, onGroupBy: setGroupBy,
14170
14904
  foldedDirs: foldedDirs, onFoldedDirs: setFoldedDirs,
14171
14905
  onMoreMenu: moreMenu,
@@ -14288,6 +15022,10 @@ window.__ModuleLoader__.load({
14288
15022
  else { entry.disabled = remoteReady !== true || blocked; entry.run = () => setDialog({ kind: 'push' }) }
14289
15023
  }
14290
15024
  else if (spec.id === 'tree') { entry.active = treeOpen; entry.run = () => foldTree(!treeOpen) }
15025
+ else if (spec.id === 'worktrees') {
15026
+ entry.active = view === 'worktrees'
15027
+ entry.run = () => { setPatch(''); setDiffContext(null); setView(view === 'worktrees' ? 'history' : 'worktrees') }
15028
+ }
14291
15029
  else if (spec.id === 'float') {
14292
15030
  // Label AND icon follow where the panel actually is: floating panels get
14293
15031
  // the way back, docked ones get the way out.
@@ -14429,7 +15167,7 @@ window.__ModuleLoader__.load({
14429
15167
 
14430
15168
  /* ---------- body per chrome ---------- */
14431
15169
 
14432
- /* ---------- body per chrome ---------- */
15170
+ const worktrees = summary !== null && Array.isArray(summary.worktrees) ? summary.worktrees : []
14433
15171
 
14434
15172
  /* The history↔diff separator only exists while a diff is on screen, and it
14435
15173
  lives inside the middle pane — the diff is the pane below it. */
@@ -14445,6 +15183,18 @@ window.__ModuleLoader__.load({
14445
15183
  body = E('div', { className: 'dig-body', ref: bodyRef }, E(RepoPicker, {
14446
15184
  t: t, cwd: cwd === undefined ? '' : cwd, repos: repoOptions, onPick: pickRepo,
14447
15185
  }))
15186
+ } else if (view === 'worktrees') {
15187
+ body = E('div', { className: 'dig-body dig-body-worktrees', ref: bodyRef }, E(WorktreesPane, {
15188
+ t: t,
15189
+ worktrees: worktrees,
15190
+ busy: busy,
15191
+ onBack: () => setView('history'),
15192
+ onCreate: () => setDialog({ kind: 'worktreeAdd' }),
15193
+ onPrune: () => setDialog({ kind: 'worktreePrune' }),
15194
+ onOpen: pickRepo,
15195
+ onCopy: (path) => copyValues([path]),
15196
+ onRemove: (tree) => setDialog({ kind: 'worktreeRemove', tree: tree, force: false }),
15197
+ }))
14448
15198
  } else if (compact) {
14449
15199
  body = E('div', { className: 'dig-body dig-body-compact', ref: bodyRef },
14450
15200
  E('div', { className: 'dig-compact-bar' },
@@ -14541,6 +15291,35 @@ window.__ModuleLoader__.load({
14541
15291
  onSubmit: (url, dir) => { setDialog(null); void run('clone', { url: url, dir: dir }) },
14542
15292
  }))
14543
15293
  }
15294
+ if (dialog !== null && dialog.kind === 'worktreeAdd') {
15295
+ overlays.push(E(WorktreeDialog, {
15296
+ key: 'worktreeAdd', t: t,
15297
+ title: t('worktrees.new'),
15298
+ cancelLabel: t('confirm.cancel'),
15299
+ onSubmit: (draft) => createWorktree(draft),
15300
+ }))
15301
+ }
15302
+ if (dialog !== null && dialog.kind === 'worktreeRemove') {
15303
+ const force = dialog.force === true
15304
+ overlays.push(E(ConfirmDialog, {
15305
+ key: 'worktreeRemove', t: t,
15306
+ title: t('worktrees.remove'),
15307
+ text: fill(force === true ? t('worktrees.removeDirty') : t('worktrees.removeConfirm'), { path: dialog.tree.path }),
15308
+ okLabel: t('worktrees.remove'), cancelLabel: t('confirm.cancel'),
15309
+ onCancel: () => setDialog(null),
15310
+ onConfirm: () => { const tree = dialog.tree; const forced = force; void removeWorktree(tree, forced) },
15311
+ }))
15312
+ }
15313
+ if (dialog !== null && dialog.kind === 'worktreePrune') {
15314
+ overlays.push(E(ConfirmDialog, {
15315
+ key: 'worktreePrune', t: t,
15316
+ title: t('worktrees.prune'),
15317
+ text: t('worktrees.pruneConfirm'),
15318
+ okLabel: t('worktrees.prune'), cancelLabel: t('confirm.cancel'),
15319
+ onCancel: () => setDialog(null),
15320
+ onConfirm: () => { void pruneWorktrees() },
15321
+ }))
15322
+ }
14544
15323
  /* SCM ▸ additions (v0.15): each destructive one is a ConfirmDialog whose
14545
15324
  text names the exact target; the tag/remote ones carry the picked
14546
15325
  remote through. */
@@ -15392,6 +16171,10 @@ window.__ModuleLoader__.load({
15392
16171
  '.dig-mrp-root{position:relative;display:inline-flex;flex:none;min-width:0}',
15393
16172
  '.dig-mrp-trigger{display:inline-flex;align-items:center;gap:4px;min-width:0;max-width:220px;font-size:11px;line-height:16px}',
15394
16173
  '.dig-mrp-trigger[data-open=true]{color:var(--dsw-alias-brand-primary)}',
16174
+ '.dig-mrp-badge{flex:none;display:inline-block;max-width:84px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle;padding:0 6px;border-radius:999px;corner-shape:round;font-size:10px;line-height:15px;font-weight:500;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary)}',
16175
+ '.dig-mrp-badge[data-tone=info]{background:color-mix(in srgb,var(--dsw-alias-state-business-primary,var(--dsw-alias-brand-primary)) 12%,transparent);color:var(--dsw-alias-state-business-primary,var(--dsw-alias-brand-primary))}',
16176
+ '.dig-mrp-badge[data-tone=success]{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}',
16177
+ '.dig-mrp-badge[data-tone=warning]{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary,var(--dsw-alias-brand-primary)) 12%,transparent);color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-brand-primary))}',
15395
16178
  '.dig-mrp-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
15396
16179
  '.dig-mrp-effort{flex:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:10px}',
15397
16180
  '.dig-mrp-menu{max-width:300px}',
@@ -15404,6 +16187,39 @@ window.__ModuleLoader__.load({
15404
16187
  '.dig-mrp-empty{padding:10px;color:var(--dsw-alias-label-tertiary);font-size:12px}',
15405
16188
  '.dig-mrp-error{padding:6px 10px;margin-bottom:2px;border-radius:var(--dsw-radius-sm,8px);background:rgba(220,38,38,.12);color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px;word-break:break-word}',
15406
16189
  'body[data-ds-dark-theme] .dig-mrp-error{background:rgba(248,113,113,.16)}',
16190
+ /* ---- worktrees view (v0.22.0) ---- */
16191
+ '.dig-body-worktrees{flex-direction:column;min-width:0}',
16192
+ '.dig-wt{display:flex;flex-direction:column;flex:1;min-height:0;min-width:0}',
16193
+ '.dig-wt-head{flex:none;display:flex;align-items:center;gap:5px;padding:4px 8px;min-height:26px;box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l1)}',
16194
+ '.dig-wt-title{font-weight:600;color:var(--dsw-alias-label-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
16195
+ '.dig-wt-count{flex:none;min-width:16px;padding:0 5px;border-radius:999px;corner-shape:round;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);font-size:10px;line-height:16px;text-align:center;font-variant-numeric:tabular-nums}',
16196
+ '.dig-wt-head .dig-icon-btn{flex:none}',
16197
+ '.dig-wt-scroll{flex:1;min-height:0;overflow:auto;padding:6px;display:flex;flex-direction:column;gap:4px}',
16198
+ '.dig-wt-row{display:flex;align-items:flex-start;gap:4px;flex-wrap:wrap;padding:7px 8px;min-width:0;border:1px solid transparent;border-radius:var(--dsw-radius-md,10px);background:var(--dsw-alias-bg-layer-1)}',
16199
+ '.dig-wt-row:hover{background:var(--dsw-alias-interactive-bg-hover)}',
16200
+ '.dig-wt-row-current{border-color:var(--dsw-alias-state-business-primary,var(--dsw-alias-brand-primary));background:var(--dsw-alias-bg-layer-2)}',
16201
+ '.dig-wt-row-current:hover{background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-bg-layer-2))}',
16202
+ '.dig-wt-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}',
16203
+ '.dig-wt-top{display:flex;align-items:center;gap:5px;min-width:0}',
16204
+ '.dig-wt-top svg{flex:none;color:var(--dsw-alias-label-secondary)}',
16205
+ '.dig-wt-branch{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-weight:600}',
16206
+ '.dig-wt-badges{display:inline-flex;flex-wrap:wrap;gap:3px;flex:none;margin-left:2px}',
16207
+ '.dig-wt-badge{display:inline-flex;align-items:center;padding:0 5px;border-radius:999px;corner-shape:round;font-size:10px;line-height:15px;font-weight:500;white-space:nowrap}',
16208
+ '.dig-wt-badge-current{background:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-label-primary-inverted,#fff)}',
16209
+ '.dig-wt-badge-primary{background:var(--dsw-alias-state-business-primary,var(--dsw-alias-brand-primary));color:var(--dsw-alias-label-primary-inverted,#fff)}',
16210
+ '.dig-wt-badge-locked{background:var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-label-primary-inverted,#fff)}',
16211
+ '.dig-wt-badge-prunable{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-inverted,#fff)}',
16212
+ '.dig-wt-path{color:var(--dsw-alias-label-secondary);font-size:11px;line-height:15px;word-break:break-all}',
16213
+ '.dig-wt-meta{display:flex;align-items:center;gap:6px;min-width:0;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:14px}',
16214
+ '.dig-wt-hash{flex:none;letter-spacing:.02em}',
16215
+ '.dig-wt-reason{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
16216
+ '.dig-wt-row-actions{flex:none;display:flex;align-items:center;gap:1px;margin-left:auto;opacity:.7}',
16217
+ '.dig-wt-row:hover .dig-wt-row-actions,.dig-wt-row-current .dig-wt-row-actions{opacity:1}',
16218
+ '.dig-wt-dialog{width:460px;max-width:calc(100% - 24px)}',
16219
+ '.dig-wt-field{display:flex;flex-direction:column;gap:4px;min-width:0;margin-bottom:10px}',
16220
+ '.dig-wt-label{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500}',
16221
+ '.dig-wt-error{padding:6px 8px;margin-bottom:8px;border-radius:var(--dsw-radius-sm,8px);background:rgba(220,38,38,.12);color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px;word-break:break-word}',
16222
+ 'body[data-ds-dark-theme] .dig-wt-error{background:rgba(248,113,113,.16)}',
15407
16223
  ].concat(LANE_TRACE_RULES).join('\n')
15408
16224
 
15409
16225
  /* ============================== plugin ============================== */
@@ -15649,6 +16465,30 @@ window.__ModuleLoader__.load({
15649
16465
  inject declaration); until it lands, and on any older host, the picker
15650
16466
  hides itself instead of throwing, and the AI-write button still works
15651
16467
  through the host's served-models fallback. */
16468
+ /* A listing badge's text may be a literal string or a language table
16469
+ (llm-deepseek only accepts lowercase language ids plus "en"). The
16470
+ official ModelSelect resolves this through its slot inject, which a
16471
+ panel-side picker cannot see; read the active tag here the same way the
16472
+ dictionary does, and fall back to English exactly like the host. */
16473
+ function modelBadgeTextOf(ctx, badge) {
16474
+ if (badge === null || typeof badge !== 'object') return ''
16475
+ const text = badge.text
16476
+ if (typeof text === 'string') return text
16477
+ if (text === null || typeof text !== 'object') return ''
16478
+ const tag = activeLocaleOf(ctx).toLowerCase()
16479
+ const keys = []
16480
+ if (tag !== '') {
16481
+ keys.push(tag)
16482
+ const primary = tag.split('-')[0]
16483
+ if (primary !== '' && primary !== tag) keys.push(primary)
16484
+ }
16485
+ keys.push('en')
16486
+ for (const key of keys) {
16487
+ const candidate = text[key]
16488
+ if (typeof candidate === 'string' && candidate !== '') return candidate
16489
+ }
16490
+ return ''
16491
+ }
15652
16492
  let modelDirectoriesRef = null
15653
16493
  const modelDirectorySubs = new Set()
15654
16494
  function ModelRoutePicker(props) {
@@ -15729,6 +16569,21 @@ window.__ModuleLoader__.load({
15729
16569
  ? (current.reasoningEffort === undefined ? '' : current.reasoningEffort)
15730
16570
  : (effectiveEffort === undefined ? t('modelRoute.effortDefault') : effortName(effectiveEffort))
15731
16571
  const modelName = current === null ? '' : routeModel === null ? current.model : routeModel.name
16572
+ /* Listing badges are optional and independently translated; a model
16573
+ without one renders exactly as before. Unknown tones fall to neutral,
16574
+ matching the host's listing decoder. */
16575
+ const badgeOf = (model) => {
16576
+ if (model === null || model === undefined || model.badge === null || typeof model.badge !== 'object') return null
16577
+ const text = modelBadgeTextOf(props.ctx, model.badge)
16578
+ if (text === '') return null
16579
+ const tone = model.badge.tone === 'info' || model.badge.tone === 'success' || model.badge.tone === 'warning' ? model.badge.tone : 'neutral'
16580
+ return { text: text, tone: tone }
16581
+ }
16582
+ const badgeNode = (model) => {
16583
+ const badge = badgeOf(model)
16584
+ return badge === null ? null : E('span', { className: 'dig-mrp-badge', 'data-tone': badge.tone }, badge.text)
16585
+ }
16586
+ const routeBadge = badgeOf(routeModel)
15732
16587
  const effortChoices = reasoning === undefined ? [] : ([
15733
16588
  ...(reasoning.defaultEffort === undefined ? [{ key: 'provider-default', effort: undefined, label: t('modelRoute.effortDefault') }] : []),
15734
16589
  ...reasoning.efforts.map((row) => ({ key: row.id, effort: row.id, label: row.name })),
@@ -15750,6 +16605,7 @@ window.__ModuleLoader__.load({
15750
16605
  onClick: () => { setOpen(!open); setPane('root') },
15751
16606
  },
15752
16607
  E(Icon, { name: 'settings', size: 11 }),
16608
+ routeBadge === null ? null : E('span', { className: 'dig-mrp-badge', 'data-tone': routeBadge.tone }, routeBadge.text),
15753
16609
  E('span', { className: 'dig-mrp-label' }, current === null ? t('modelRoute.pick') : modelName),
15754
16610
  effortLabel === '' ? null : E('span', { className: 'dig-mrp-effort' }, effortLabel),
15755
16611
  E(Icon, { name: 'chevron', size: 9 })),
@@ -15794,6 +16650,7 @@ window.__ModuleLoader__.load({
15794
16650
  onClick: () => choose({ provider: group.id, model: model.id }),
15795
16651
  },
15796
16652
  E('span', { className: 'dig-cs-item-name' }, model.name === undefined || model.name === null ? model.id : model.name),
16653
+ badgeNode(model),
15797
16654
  E('span', { className: 'dig-cs-item-note' }, selected === true ? E(Icon, { name: 'check', size: 11 }) : null))
15798
16655
  }))),
15799
16656
  pane === 'effort' && current !== null && effortChoices.map((level) => {