dsh-better-workspace 0.12.1 → 0.13.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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-better-workspace",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "main": "./src/index.js",
5
5
  "description": "侧边栏工作区两层层级树:工作区按磁盘目录嵌套(官方 workspace-tree 语义),名称中的 / 即虚拟分组(web/前端 · web/后端);添加工作区由官方目录流承载。Two-layer hierarchy tree for the DSH sidebar workspace list.",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-better-workspace",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "侧边栏工作区两层层级树:磁盘目录嵌套(官方 workspace-tree 语义)+ 名称 / 虚拟分组,添加工作区走官方目录流。Two-layer workspace tree for the DSH sidebar: disk-path nesting plus \"/\"-name groups; add-workspace rides the official directory flow.",
5
5
  "type": "module",
6
6
  "repository": {
package/src/client.js CHANGED
@@ -40,6 +40,16 @@ window.__ModuleLoader__.load({
40
40
  'empty': '暂无工作区',
41
41
  'empty.search': '没有匹配的结果',
42
42
  'session.new': '新会话',
43
+ 'viewOptions.label': '视图选项',
44
+ 'viewOptions.groupBy': '分组方式',
45
+ 'viewOptions.byWorkspace': '按工作区',
46
+ 'viewOptions.byWorkspaceTree': '按工作区树',
47
+ 'viewOptions.flat': '单列表',
48
+ 'viewOptions.orderBy': '排序方式',
49
+ 'viewOptions.manualOrder': '手动排序',
50
+ 'viewOptions.updatedOrder': '最近更新',
51
+ 'viewOptions.sessionSlash': '会话按"/"分组',
52
+ 'viewOptions.workspaceSlash': '工作区按"/"分组',
43
53
  'group.ungrouped': '未分组',
44
54
  'sessions.expand': '展开 {n} 个会话',
45
55
  'sessions.collapse': '收起',
@@ -150,6 +160,16 @@ window.__ModuleLoader__.load({
150
160
  'empty': 'No workspaces yet',
151
161
  'empty.search': 'No matches',
152
162
  'session.new': 'New session',
163
+ 'viewOptions.label': 'View options',
164
+ 'viewOptions.groupBy': 'Group by',
165
+ 'viewOptions.byWorkspace': 'Workspaces',
166
+ 'viewOptions.byWorkspaceTree': 'Workspace tree',
167
+ 'viewOptions.flat': 'In one list',
168
+ 'viewOptions.orderBy': 'Order by',
169
+ 'viewOptions.manualOrder': 'Manual',
170
+ 'viewOptions.updatedOrder': 'Last updated',
171
+ 'viewOptions.sessionSlash': 'Group sessions by "/"',
172
+ 'viewOptions.workspaceSlash': 'Group workspaces by "/"',
153
173
  'group.ungrouped': 'Ungrouped',
154
174
  'sessions.expand': 'Show {n} more sessions',
155
175
  'sessions.collapse': 'Collapse',
@@ -268,6 +288,16 @@ window.__ModuleLoader__.load({
268
288
  'empty': 'لا توجد مساحات عمل بعد',
269
289
  'empty.search': 'لا توجد نتائج مطابقة',
270
290
  'session.new': 'جلسة جديدة',
291
+ 'viewOptions.label': 'خيارات العرض',
292
+ 'viewOptions.groupBy': 'التجميع حسب',
293
+ 'viewOptions.byWorkspace': 'مساحات العمل',
294
+ 'viewOptions.byWorkspaceTree': 'شجرة مساحات العمل',
295
+ 'viewOptions.flat': 'قائمة واحدة',
296
+ 'viewOptions.orderBy': 'الترتيب حسب',
297
+ 'viewOptions.manualOrder': 'يدوي',
298
+ 'viewOptions.updatedOrder': 'آخر تحديث',
299
+ 'viewOptions.sessionSlash': 'تجميع الجلسات حسب "/"',
300
+ 'viewOptions.workspaceSlash': 'تجميع مساحات العمل حسب "/"',
271
301
  'group.ungrouped': 'بلا مجموعة',
272
302
  'sessions.expand': 'عرض {n} جلسات إضافية',
273
303
  'sessions.collapse': 'طيّ',
@@ -378,6 +408,16 @@ window.__ModuleLoader__.load({
378
408
  'empty': 'Noch keine Arbeitsbereiche',
379
409
  'empty.search': 'Keine Treffer',
380
410
  'session.new': 'Neue Sitzung',
411
+ 'viewOptions.label': 'Ansichtsoptionen',
412
+ 'viewOptions.groupBy': 'Gruppieren',
413
+ 'viewOptions.byWorkspace': 'Arbeitsbereiche',
414
+ 'viewOptions.byWorkspaceTree': 'Arbeitsbereichsbaum',
415
+ 'viewOptions.flat': 'In einer Liste',
416
+ 'viewOptions.orderBy': 'Sortieren',
417
+ 'viewOptions.manualOrder': 'Manuell',
418
+ 'viewOptions.updatedOrder': 'Zuletzt aktualisiert',
419
+ 'viewOptions.sessionSlash': 'Sitzungen nach "/" gruppieren',
420
+ 'viewOptions.workspaceSlash': 'Arbeitsbereiche nach "/" gruppieren',
381
421
  'group.ungrouped': 'Ohne Gruppe',
382
422
  'sessions.expand': '{n} Sitzungen einblenden',
383
423
  'sessions.collapse': 'Einklappen',
@@ -488,6 +528,16 @@ window.__ModuleLoader__.load({
488
528
  'empty': 'Aucun espace de travail',
489
529
  'empty.search': 'Aucun résultat',
490
530
  'session.new': 'Nouvelle session',
531
+ 'viewOptions.label': 'Options d’affichage',
532
+ 'viewOptions.groupBy': 'Regrouper par',
533
+ 'viewOptions.byWorkspace': 'Espaces de travail',
534
+ 'viewOptions.byWorkspaceTree': 'Arborescence des espaces',
535
+ 'viewOptions.flat': 'En une liste',
536
+ 'viewOptions.orderBy': 'Trier par',
537
+ 'viewOptions.manualOrder': 'Manuel',
538
+ 'viewOptions.updatedOrder': 'Dernière mise à jour',
539
+ 'viewOptions.sessionSlash': 'Grouper les sessions par « / »',
540
+ 'viewOptions.workspaceSlash': 'Grouper les espaces par « / »',
491
541
  'group.ungrouped': 'Sans groupe',
492
542
  'sessions.expand': 'Afficher {n} sessions',
493
543
  'sessions.collapse': 'Réduire',
@@ -598,6 +648,16 @@ window.__ModuleLoader__.load({
598
648
  'empty': 'अभी कोई कार्यस्थान नहीं',
599
649
  'empty.search': 'कोई मेल खाता परिणाम नहीं',
600
650
  'session.new': 'नया सत्र',
651
+ 'viewOptions.label': 'दृश्य विकल्प',
652
+ 'viewOptions.groupBy': 'समूहीकरण',
653
+ 'viewOptions.byWorkspace': 'कार्यक्षेत्र अनुसार',
654
+ 'viewOptions.byWorkspaceTree': 'कार्यक्षेत्र ट्री अनुसार',
655
+ 'viewOptions.flat': 'एक सूची में',
656
+ 'viewOptions.orderBy': 'क्रम',
657
+ 'viewOptions.manualOrder': 'मैन्युअल',
658
+ 'viewOptions.updatedOrder': 'हाल का अपडेट',
659
+ 'viewOptions.sessionSlash': 'सत्रों को "/" से समूहित करें',
660
+ 'viewOptions.workspaceSlash': 'कार्यक्षेत्रों को "/" से समूहित करें',
601
661
  'group.ungrouped': 'बिना समूह',
602
662
  'sessions.expand': '{n} सत्र दिखाएँ',
603
663
  'sessions.collapse': 'समेटें',
@@ -708,6 +768,16 @@ window.__ModuleLoader__.load({
708
768
  'empty': 'Belum ada ruang kerja',
709
769
  'empty.search': 'Tidak ada hasil yang cocok',
710
770
  'session.new': 'Sesi baru',
771
+ 'viewOptions.label': 'Opsi tampilan',
772
+ 'viewOptions.groupBy': 'Kelompokkan berdasarkan',
773
+ 'viewOptions.byWorkspace': 'Ruang kerja',
774
+ 'viewOptions.byWorkspaceTree': 'Pohon ruang kerja',
775
+ 'viewOptions.flat': 'Satu daftar',
776
+ 'viewOptions.orderBy': 'Urutkan',
777
+ 'viewOptions.manualOrder': 'Manual',
778
+ 'viewOptions.updatedOrder': 'Terakhir diperbarui',
779
+ 'viewOptions.sessionSlash': 'Kelompokkan sesi per "/"',
780
+ 'viewOptions.workspaceSlash': 'Kelompokkan ruang kerja per "/"',
711
781
  'group.ungrouped': 'Tanpa grup',
712
782
  'sessions.expand': 'Tampilkan {n} sesi',
713
783
  'sessions.collapse': 'Ciutkan',
@@ -818,6 +888,16 @@ window.__ModuleLoader__.load({
818
888
  'empty': 'Nessuna area di lavoro',
819
889
  'empty.search': 'Nessun risultato',
820
890
  'session.new': 'Nuova sessione',
891
+ 'viewOptions.label': 'Opzioni vista',
892
+ 'viewOptions.groupBy': 'Raggruppa per',
893
+ 'viewOptions.byWorkspace': 'Aree di lavoro',
894
+ 'viewOptions.byWorkspaceTree': 'Albero aree di lavoro',
895
+ 'viewOptions.flat': 'In un elenco',
896
+ 'viewOptions.orderBy': 'Ordina per',
897
+ 'viewOptions.manualOrder': 'Manuale',
898
+ 'viewOptions.updatedOrder': 'Ultimo aggiornamento',
899
+ 'viewOptions.sessionSlash': 'Raggruppa sessioni per "/"',
900
+ 'viewOptions.workspaceSlash': 'Raggruppa aree per "/"',
821
901
  'group.ungrouped': 'Senza gruppo',
822
902
  'sessions.expand': 'Mostra {n} sessioni',
823
903
  'sessions.collapse': 'Comprimi',
@@ -928,6 +1008,16 @@ window.__ModuleLoader__.load({
928
1008
  'empty': 'ワークスペースがありません',
929
1009
  'empty.search': '一致する結果がありません',
930
1010
  'session.new': '新しいセッション',
1011
+ 'viewOptions.label': '表示オプション',
1012
+ 'viewOptions.groupBy': 'グループ化',
1013
+ 'viewOptions.byWorkspace': 'ワークスペースごと',
1014
+ 'viewOptions.byWorkspaceTree': 'ワークスペースツリーごと',
1015
+ 'viewOptions.flat': '1 つのリスト',
1016
+ 'viewOptions.orderBy': '並べ替え',
1017
+ 'viewOptions.manualOrder': '手動',
1018
+ 'viewOptions.updatedOrder': '最近の更新',
1019
+ 'viewOptions.sessionSlash': 'セッションを「/」でグループ化',
1020
+ 'viewOptions.workspaceSlash': 'ワークスペースを「/」でグループ化',
931
1021
  'group.ungrouped': '未分類',
932
1022
  'sessions.expand': '{n} 件のセッションを展開',
933
1023
  'sessions.collapse': '折りたたむ',
@@ -1038,6 +1128,16 @@ window.__ModuleLoader__.load({
1038
1128
  'empty': '워크스페이스가 없습니다',
1039
1129
  'empty.search': '일치하는 결과가 없습니다',
1040
1130
  'session.new': '새 세션',
1131
+ 'viewOptions.label': '보기 옵션',
1132
+ 'viewOptions.groupBy': '그룹화',
1133
+ 'viewOptions.byWorkspace': '작업 공간별',
1134
+ 'viewOptions.byWorkspaceTree': '작업 공간 트리별',
1135
+ 'viewOptions.flat': '하나의 목록',
1136
+ 'viewOptions.orderBy': '정렬',
1137
+ 'viewOptions.manualOrder': '수동',
1138
+ 'viewOptions.updatedOrder': '최근 업데이트',
1139
+ 'viewOptions.sessionSlash': '세션을 "/"로 그룹화',
1140
+ 'viewOptions.workspaceSlash': '작업 공간을 "/"로 그룹화',
1041
1141
  'group.ungrouped': '미분류',
1042
1142
  'sessions.expand': '세션 {n}개 펼치기',
1043
1143
  'sessions.collapse': '접기',
@@ -1148,6 +1248,16 @@ window.__ModuleLoader__.load({
1148
1248
  'empty': 'Nog geen werkruimten',
1149
1249
  'empty.search': 'Geen resultaten',
1150
1250
  'session.new': 'Nieuwe sessie',
1251
+ 'viewOptions.label': 'Weergaveopties',
1252
+ 'viewOptions.groupBy': 'Groeperen op',
1253
+ 'viewOptions.byWorkspace': 'Werkruimtes',
1254
+ 'viewOptions.byWorkspaceTree': 'Werkruimteboom',
1255
+ 'viewOptions.flat': 'In één lijst',
1256
+ 'viewOptions.orderBy': 'Sorteren op',
1257
+ 'viewOptions.manualOrder': 'Handmatig',
1258
+ 'viewOptions.updatedOrder': 'Laatst bijgewerkt',
1259
+ 'viewOptions.sessionSlash': 'Sessies groeperen op "/"',
1260
+ 'viewOptions.workspaceSlash': 'Werkruimtes groeperen op "/"',
1151
1261
  'group.ungrouped': 'Zonder groep',
1152
1262
  'sessions.expand': '{n} sessies uitklappen',
1153
1263
  'sessions.collapse': 'Inklappen',
@@ -1258,6 +1368,16 @@ window.__ModuleLoader__.load({
1258
1368
  'empty': 'Brak obszarów roboczych',
1259
1369
  'empty.search': 'Brak wyników',
1260
1370
  'session.new': 'Nowa sesja',
1371
+ 'viewOptions.label': 'Opcje widoku',
1372
+ 'viewOptions.groupBy': 'Grupuj według',
1373
+ 'viewOptions.byWorkspace': 'Obszary robocze',
1374
+ 'viewOptions.byWorkspaceTree': 'Drzewo obszarów',
1375
+ 'viewOptions.flat': 'Jedna lista',
1376
+ 'viewOptions.orderBy': 'Sortuj według',
1377
+ 'viewOptions.manualOrder': 'Ręcznie',
1378
+ 'viewOptions.updatedOrder': 'Ostatnia aktualizacja',
1379
+ 'viewOptions.sessionSlash': 'Grupuj sesje po "/"',
1380
+ 'viewOptions.workspaceSlash': 'Grupuj obszary po "/"',
1261
1381
  'group.ungrouped': 'Bez grupy',
1262
1382
  'sessions.expand': 'Pokaż {n} sesji',
1263
1383
  'sessions.collapse': 'Zwiń',
@@ -1368,6 +1488,16 @@ window.__ModuleLoader__.load({
1368
1488
  'empty': 'Nenhum espaço de trabalho',
1369
1489
  'empty.search': 'Nenhum resultado',
1370
1490
  'session.new': 'Nova sessão',
1491
+ 'viewOptions.label': 'Opções de vista',
1492
+ 'viewOptions.groupBy': 'Agrupar por',
1493
+ 'viewOptions.byWorkspace': 'Áreas de trabalho',
1494
+ 'viewOptions.byWorkspaceTree': 'Árvore de áreas',
1495
+ 'viewOptions.flat': 'Numa lista',
1496
+ 'viewOptions.orderBy': 'Ordenar por',
1497
+ 'viewOptions.manualOrder': 'Manual',
1498
+ 'viewOptions.updatedOrder': 'Atualização recente',
1499
+ 'viewOptions.sessionSlash': 'Agrupar sessões por "/"',
1500
+ 'viewOptions.workspaceSlash': 'Agrupar áreas por "/"',
1371
1501
  'group.ungrouped': 'Sem grupo',
1372
1502
  'sessions.expand': 'Mostrar {n} sessões',
1373
1503
  'sessions.collapse': 'Recolher',
@@ -1478,6 +1608,16 @@ window.__ModuleLoader__.load({
1478
1608
  'empty': 'Рабочих областей пока нет',
1479
1609
  'empty.search': 'Ничего не найдено',
1480
1610
  'session.new': 'Новая сессия',
1611
+ 'viewOptions.label': 'Параметры вида',
1612
+ 'viewOptions.groupBy': 'Группировка',
1613
+ 'viewOptions.byWorkspace': 'По рабочим областям',
1614
+ 'viewOptions.byWorkspaceTree': 'По дереву областей',
1615
+ 'viewOptions.flat': 'Одним списком',
1616
+ 'viewOptions.orderBy': 'Сортировка',
1617
+ 'viewOptions.manualOrder': 'Вручную',
1618
+ 'viewOptions.updatedOrder': 'По обновлению',
1619
+ 'viewOptions.sessionSlash': 'Группировать сессии по «/»',
1620
+ 'viewOptions.workspaceSlash': 'Группировать области по «/»',
1481
1621
  'group.ungrouped': 'Без группы',
1482
1622
  'sessions.expand': 'Показать ещё {n} сессий',
1483
1623
  'sessions.collapse': 'Свернуть',
@@ -1588,6 +1728,16 @@ window.__ModuleLoader__.load({
1588
1728
  'empty': 'Inga arbetsytor ännu',
1589
1729
  'empty.search': 'Inga träffar',
1590
1730
  'session.new': 'Ny session',
1731
+ 'viewOptions.label': 'Visningsalternativ',
1732
+ 'viewOptions.groupBy': 'Gruppera efter',
1733
+ 'viewOptions.byWorkspace': 'Arbetsytor',
1734
+ 'viewOptions.byWorkspaceTree': 'Arbetsyta-träd',
1735
+ 'viewOptions.flat': 'I en lista',
1736
+ 'viewOptions.orderBy': 'Sortera efter',
1737
+ 'viewOptions.manualOrder': 'Manuellt',
1738
+ 'viewOptions.updatedOrder': 'Senast uppdaterad',
1739
+ 'viewOptions.sessionSlash': 'Gruppera sessioner efter "/"',
1740
+ 'viewOptions.workspaceSlash': 'Gruppera arbetsytor efter "/"',
1591
1741
  'group.ungrouped': 'Utan grupp',
1592
1742
  'sessions.expand': 'Visa {n} sessioner',
1593
1743
  'sessions.collapse': 'Fäll ihop',
@@ -1698,6 +1848,16 @@ window.__ModuleLoader__.load({
1698
1848
  'empty': 'ยังไม่มีพื้นที่ทำงาน',
1699
1849
  'empty.search': 'ไม่พบผลลัพธ์ที่ตรงกัน',
1700
1850
  'session.new': 'เซสชันใหม่',
1851
+ 'viewOptions.label': 'ตัวเลือกมุมมอง',
1852
+ 'viewOptions.groupBy': 'จัดกลุ่มตาม',
1853
+ 'viewOptions.byWorkspace': 'ตามพื้นที่ทำงาน',
1854
+ 'viewOptions.byWorkspaceTree': 'ตามแผนผังพื้นที่ทำงาน',
1855
+ 'viewOptions.flat': 'รายการเดียว',
1856
+ 'viewOptions.orderBy': 'เรียงตาม',
1857
+ 'viewOptions.manualOrder': 'ด้วยตนเอง',
1858
+ 'viewOptions.updatedOrder': 'อัปเดตล่าสุด',
1859
+ 'viewOptions.sessionSlash': 'จัดกลุ่มเซสชันตาม "/"',
1860
+ 'viewOptions.workspaceSlash': 'จัดกลุ่มพื้นที่ทำงานตาม "/"',
1701
1861
  'group.ungrouped': 'ไม่มีกลุ่ม',
1702
1862
  'sessions.expand': 'แสดงอีก {n} เซสชัน',
1703
1863
  'sessions.collapse': 'ย่อ',
@@ -1808,6 +1968,16 @@ window.__ModuleLoader__.load({
1808
1968
  'empty': 'Henüz çalışma alanı yok',
1809
1969
  'empty.search': 'Eşleşen sonuç yok',
1810
1970
  'session.new': 'Yeni oturum',
1971
+ 'viewOptions.label': 'Görünüm seçenekleri',
1972
+ 'viewOptions.groupBy': 'Gruplandır',
1973
+ 'viewOptions.byWorkspace': 'Çalışma alanları',
1974
+ 'viewOptions.byWorkspaceTree': 'Çalışma alanı ağacı',
1975
+ 'viewOptions.flat': 'Tek liste',
1976
+ 'viewOptions.orderBy': 'Sırala',
1977
+ 'viewOptions.manualOrder': 'El ile',
1978
+ 'viewOptions.updatedOrder': 'Son güncelleme',
1979
+ 'viewOptions.sessionSlash': 'Oturumları "/" ile gruplandır',
1980
+ 'viewOptions.workspaceSlash': 'Çalışma alanlarını "/" ile gruplandır',
1811
1981
  'group.ungrouped': 'Grubusuz',
1812
1982
  'sessions.expand': '{n} oturumu göster',
1813
1983
  'sessions.collapse': 'Daralt',
@@ -1918,6 +2088,16 @@ window.__ModuleLoader__.load({
1918
2088
  'empty': 'Chưa có không gian làm việc',
1919
2089
  'empty.search': 'Không có kết quả phù hợp',
1920
2090
  'session.new': 'Phiên mới',
2091
+ 'viewOptions.label': 'Tùy chọn hiển thị',
2092
+ 'viewOptions.groupBy': 'Nhóm theo',
2093
+ 'viewOptions.byWorkspace': 'Theo khu vực làm việc',
2094
+ 'viewOptions.byWorkspaceTree': 'Theo cây khu vực',
2095
+ 'viewOptions.flat': 'Một danh sách',
2096
+ 'viewOptions.orderBy': 'Sắp xếp theo',
2097
+ 'viewOptions.manualOrder': 'Thủ công',
2098
+ 'viewOptions.updatedOrder': 'Cập nhật gần đây',
2099
+ 'viewOptions.sessionSlash': 'Nhóm phiên theo "/"',
2100
+ 'viewOptions.workspaceSlash': 'Nhóm khu vực theo "/"',
1921
2101
  'group.ungrouped': 'Chưa phân nhóm',
1922
2102
  'sessions.expand': 'Hiện thêm {n} phiên',
1923
2103
  'sessions.collapse': 'Thu gọn',
@@ -2028,6 +2208,16 @@ window.__ModuleLoader__.load({
2028
2208
  'empty': '未有工作區',
2029
2209
  'empty.search': '搵唔到符合嘅結果',
2030
2210
  'session.new': '新對話',
2211
+ 'viewOptions.label': '檢視選項',
2212
+ 'viewOptions.groupBy': '分組方式',
2213
+ 'viewOptions.byWorkspace': '按工作區',
2214
+ 'viewOptions.byWorkspaceTree': '按工作區樹',
2215
+ 'viewOptions.flat': '單一列表',
2216
+ 'viewOptions.orderBy': '排序方式',
2217
+ 'viewOptions.manualOrder': '手動排序',
2218
+ 'viewOptions.updatedOrder': '最近更新',
2219
+ 'viewOptions.sessionSlash': '對話按「/」分組',
2220
+ 'viewOptions.workspaceSlash': '工作區按「/」分組',
2031
2221
  'group.ungrouped': '未分組',
2032
2222
  'sessions.expand': '展開 {n} 個對話',
2033
2223
  'sessions.collapse': '收起',
@@ -2138,6 +2328,16 @@ window.__ModuleLoader__.load({
2138
2328
  'empty': '未有工作區',
2139
2329
  'empty.search': '搵唔到符合嘅結果',
2140
2330
  'session.new': '新對話',
2331
+ 'viewOptions.label': '檢視選項',
2332
+ 'viewOptions.groupBy': '分組方式',
2333
+ 'viewOptions.byWorkspace': '按工作區',
2334
+ 'viewOptions.byWorkspaceTree': '按工作區樹',
2335
+ 'viewOptions.flat': '單一列表',
2336
+ 'viewOptions.orderBy': '排序方式',
2337
+ 'viewOptions.manualOrder': '手動排序',
2338
+ 'viewOptions.updatedOrder': '最近更新',
2339
+ 'viewOptions.sessionSlash': '對話按「/」分組',
2340
+ 'viewOptions.workspaceSlash': '工作區按「/」分組',
2141
2341
  'group.ungrouped': '未分組',
2142
2342
  'sessions.expand': '展開 {n} 個對話',
2143
2343
  'sessions.collapse': '收起',
@@ -2248,6 +2448,16 @@ window.__ModuleLoader__.load({
2248
2448
  'empty': '尚無工作區',
2249
2449
  'empty.search': '沒有相符的結果',
2250
2450
  'session.new': '新工作階段',
2451
+ 'viewOptions.label': '檢視選項',
2452
+ 'viewOptions.groupBy': '分組方式',
2453
+ 'viewOptions.byWorkspace': '按工作區',
2454
+ 'viewOptions.byWorkspaceTree': '按工作區樹',
2455
+ 'viewOptions.flat': '單一列表',
2456
+ 'viewOptions.orderBy': '排序方式',
2457
+ 'viewOptions.manualOrder': '手動排序',
2458
+ 'viewOptions.updatedOrder': '最近更新',
2459
+ 'viewOptions.sessionSlash': '工作階段按「/」分組',
2460
+ 'viewOptions.workspaceSlash': '工作區按「/」分組',
2251
2461
  'group.ungrouped': '未分組',
2252
2462
  'sessions.expand': '展開 {n} 個工作階段',
2253
2463
  'sessions.collapse': '收合',
@@ -2495,6 +2705,21 @@ window.__ModuleLoader__.load({
2495
2705
  && !(archivedSet && archivedSet.has(summary.id))
2496
2706
  && (!summary.blank || summary.id === current)
2497
2707
 
2708
+ /**
2709
+ * dsh 0.1.6-alpha.2 dropped SessionListState.current: the "open" session
2710
+ * is now the one retained under the mainView source — navigation belongs
2711
+ * to the view owner (official ui-workspace tree.ts mainSessionId). The
2712
+ * old wire field is gone, so reading it yields a permanent undefined
2713
+ * (no current highlight, and blank rows would filter out everywhere).
2714
+ */
2715
+ const mainSessionIdOf = (list) => {
2716
+ if (!list || !list.byId) return undefined
2717
+ for (const session of Object.values(list.byId)) {
2718
+ if (session && session.retainedBy && (session.retainedBy.mainView || 0) > 0) return session.id
2719
+ }
2720
+ return undefined
2721
+ }
2722
+
2498
2723
  /**
2499
2724
  * Active-schedule marker, mirroring the official tree's
2500
2725
  * hasActiveSchedule(): the list projection carries one entry per active
@@ -2548,9 +2773,15 @@ window.__ModuleLoader__.load({
2548
2773
  * titles. Groups are virtual (projection of names). Rows keep the Host
2549
2774
  * workspace.sessionIds (manual) order — drag-to-reorder must be visible.
2550
2775
  */
2551
- function buildSessionTree(rows) {
2776
+ function buildSessionTree(rows, groupBySlash) {
2552
2777
  const root = { path: '', name: '', groups: [], sessions: [] }
2553
2778
  const byPath = new Map([['', root]])
2779
+ // Slash grouping OFF (v0.13 view option): every row lands at the
2780
+ // root level and keeps its FULL title as the leaf — no levels.
2781
+ if (groupBySlash === false) {
2782
+ for (const row of rows || []) root.sessions.push({ ...row, leaf: row.title })
2783
+ return root
2784
+ }
2554
2785
  // SEGMENT-driven: paths arrive as already-split segment arrays (URL-aware
2555
2786
  // splitTitleSegs can yield segments containing "//", e.g. the
2556
2787
  // "scheme://host" authority segment) and are joined into the path KEY
@@ -2664,7 +2895,7 @@ window.__ModuleLoader__.load({
2664
2895
  }
2665
2896
  return map
2666
2897
  }
2667
- function buildTree(items) {
2898
+ function buildTree(items, groupBySlash) {
2668
2899
  const list = items || []
2669
2900
  const diskParentOf = diskParentMapOf(list)
2670
2901
  const childrenOf = new Map()
@@ -2705,7 +2936,7 @@ window.__ModuleLoader__.load({
2705
2936
  const folderPath = segs.slice(0, -1).join('/')
2706
2937
  const leaf = segs.length > 0 ? segs[segs.length - 1] : (basename(workspace.path) || String(workspace.title || '') || String(workspace.workspaceId || ''))
2707
2938
  const subList = childrenOf.get(workspace.workspaceId)
2708
- ensure(segs.slice(0, -1)).workspaces.push({
2939
+ const entry = {
2709
2940
  workspaceId: workspace.workspaceId,
2710
2941
  title: String(workspace.title || ''),
2711
2942
  path: String(workspace.path || ''),
@@ -2713,7 +2944,17 @@ window.__ModuleLoader__.load({
2713
2944
  leaf,
2714
2945
  folderPath,
2715
2946
  sub: subList ? buildLevel(subList, (idPrefix !== '' ? idPrefix + '//' : '') + workspace.workspaceId) : null,
2716
- })
2947
+ }
2948
+ // Slash grouping OFF (v0.13 view option): skip the name layer —
2949
+ // workspaces mount straight at their disk level; the DISK layer
2950
+ // is a filesystem fact and stays.
2951
+ if (groupBySlash === false) {
2952
+ entry.leaf = String(workspace.title || '') || leaf
2953
+ entry.folderPath = ''
2954
+ root.workspaces.push(entry)
2955
+ continue
2956
+ }
2957
+ ensure(segs.slice(0, -1)).workspaces.push(entry)
2717
2958
  }
2718
2959
  const sortRec = (node) => {
2719
2960
  node.folders.sort((a, b) => a.name.localeCompare(b.name, 'zh'))
@@ -2951,7 +3192,7 @@ window.__ModuleLoader__.load({
2951
3192
  /* ========================== view store =========================== */
2952
3193
 
2953
3194
  const createViewStore = () => storeKit.defineStore({
2954
- init: () => ({ expanded: {}, sessionsExpanded: {}, sessionGroups: {}, sessionOrder: {}, prefs: { compactChains: true }, styling: {} }),
3195
+ init: () => ({ expanded: {}, sessionsExpanded: {}, sessionGroups: {}, sessionOrder: {}, prefs: { compactChains: true }, styling: {}, groupBy: 'workspace-tree', orderBy: 'manual', sessionTitleSlash: true, workspaceTitleSlash: true }),
2955
3196
  // NOTE: hydration REPLACES the state with the persisted whole value —
2956
3197
  // init defaults never merge. Every action must tolerate a missing key
2957
3198
  // (states persisted by older plugin versions lack sessionGroups), and
@@ -2994,6 +3235,14 @@ window.__ModuleLoader__.load({
2994
3235
  if (!Array.isArray(order) || order.length === 0) delete d.sessionOrder[workspaceId]
2995
3236
  else d.sessionOrder[workspaceId] = order.slice()
2996
3237
  },
3238
+ // View options (v0.13): mirror the official browser's group/order
3239
+ // menu plus the two slash-grouping toggles. groupBy mirrors the
3240
+ // official literal set; the bw defaults keep the founding behaviour
3241
+ // (tree + both slash layers on + manual host order).
3242
+ setGroupBy: (d, value) => { d.groupBy = value },
3243
+ setOrderBy: (d, value) => { d.orderBy = value },
3244
+ setSessionTitleSlash: (d, value) => { d.sessionTitleSlash = value !== false },
3245
+ setWorkspaceTitleSlash: (d, value) => { d.workspaceTitleSlash = value !== false },
2997
3246
  },
2998
3247
  })
2999
3248
 
@@ -3951,6 +4200,60 @@ window.__ModuleLoader__.load({
3951
4200
  )
3952
4201
  }
3953
4202
 
4203
+ /* ------------------------- view options menu ---------------------- */
4204
+
4205
+ /**
4206
+ * View options (v0.13): mirrors the official browser's ViewOptionsMenu —
4207
+ * primitives Menu, label/separator/selectedIds structure, portal + dense
4208
+ * + end alignment. Group/order picks close the menu; the two slash
4209
+ * toggles flip in place (they ride selectedIds: present = on) and stay
4210
+ * open. Options that cannot affect the current mode render disabled:
4211
+ * slash toggles mean nothing in the flat list, and the WORKSPACE-name
4212
+ * toggle only shapes the tree mode (the flat workspace level has no
4213
+ * name layer). The primitives Menu is feature-probed like every
4214
+ * component — without it the button simply never renders.
4215
+ */
4216
+ function ViewOptionsMenu({ groupBy, orderBy, sessionSlash, workspaceSlash, onPick, onToggle, t }) {
4217
+ const [open, setOpen] = React.useState(false)
4218
+ if (typeof ui.Menu !== 'function') return null
4219
+ return E(ui.Menu, {
4220
+ open,
4221
+ onClose: () => { setOpen(false) },
4222
+ items: [
4223
+ { type: 'label', id: 'bw-group-by', text: t('viewOptions.groupBy') },
4224
+ { id: 'workspace', label: t('viewOptions.byWorkspace') },
4225
+ { id: 'workspace-tree', label: t('viewOptions.byWorkspaceTree') },
4226
+ { id: 'flat', label: t('viewOptions.flat') },
4227
+ { type: 'separator', id: 'bw-order-sep' },
4228
+ { type: 'label', id: 'bw-order-by', text: t('viewOptions.orderBy') },
4229
+ { id: 'manual', label: t('viewOptions.manualOrder') },
4230
+ { id: 'updated', label: t('viewOptions.updatedOrder') },
4231
+ { type: 'separator', id: 'bw-slash-sep' },
4232
+ { id: 'session-slash', label: t('viewOptions.sessionSlash'), disabled: groupBy === 'flat' },
4233
+ { id: 'workspace-slash', label: t('viewOptions.workspaceSlash'), disabled: groupBy !== 'workspace-tree' },
4234
+ ],
4235
+ selectedIds: [groupBy, orderBy]
4236
+ .concat(sessionSlash ? ['session-slash'] : [])
4237
+ .concat(workspaceSlash ? ['workspace-slash'] : []),
4238
+ onSelect: (id) => {
4239
+ if (id === 'workspace' || id === 'workspace-tree' || id === 'flat') { onPick('groupBy', id); setOpen(false); return }
4240
+ if (id === 'manual' || id === 'updated') { onPick('orderBy', id); setOpen(false); return }
4241
+ if (id === 'session-slash') { onToggle('sessionTitleSlash', !sessionSlash); return }
4242
+ if (id === 'workspace-slash') { onToggle('workspaceTitleSlash', !workspaceSlash); return }
4243
+ },
4244
+ align: 'end',
4245
+ dense: true,
4246
+ portal: true,
4247
+ anchor: E('button', {
4248
+ type: 'button',
4249
+ className: 'bw-icon-btn',
4250
+ 'aria-label': t('viewOptions.label'),
4251
+ title: t('viewOptions.label'),
4252
+ onClick: () => { setOpen(v => !v) },
4253
+ }, icon('IconPersonalizationOutline16')),
4254
+ })
4255
+ }
4256
+
3954
4257
  /* --------------------- customization dialog ----------------------- */
3955
4258
 
3956
4259
  const SWATCHES = ['', '#5b8def', '#3fb950', '#d29922', '#f85149', '#a371f7', '#39c5cf', '#ec6cb9', '#ff9f45', '#6e7681']
@@ -4442,6 +4745,13 @@ window.__ModuleLoader__.load({
4442
4745
  const prefsMap = useStore ? (useStore(s => s.prefs) || {}) : {}
4443
4746
  const stylingMap = useStore ? (useStore(s => s.styling) || {}) : {}
4444
4747
  const sessionOrderMap = useStore ? (useStore(s => s.sessionOrder) || {}) : {}
4748
+ // View options (v0.13). Selector reads take fallbacks: hydration
4749
+ // replaces the whole persisted value, so states written by older
4750
+ // plugin versions lack these keys (hard store discipline).
4751
+ const groupBy = useStore ? (useStore(s => s.groupBy) || 'workspace-tree') : 'workspace-tree'
4752
+ const orderBy = useStore ? (useStore(s => s.orderBy) || 'manual') : 'manual'
4753
+ const sessionSlash = useStore ? (useStore(s => s.sessionTitleSlash) !== false) : true
4754
+ const workspaceSlash = useStore ? (useStore(s => s.workspaceTitleSlash) !== false) : true
4445
4755
  // Dual-write wrappers: every preference mutation lands in the local
4446
4756
  // store (immediate echo + scope-less fallback) AND the host settings
4447
4757
  // store (durable cross-device copy for the manual pull on the other
@@ -4451,6 +4761,8 @@ window.__ModuleLoader__.load({
4451
4761
  const statusPulse = prefsMap.statusPulse !== false
4452
4762
  const archivedSet = React.useMemo(() => new Set(archivedSessionIds), [archivedSessionIds])
4453
4763
  const subCounts = React.useMemo(() => subagentRunningCounts(list ? list.byId : {}), [list ? list.byId : null])
4764
+ // Current session per the alpha.2 retention contract (see mainSessionIdOf).
4765
+ const currentId = React.useMemo(() => mainSessionIdOf(list), [list ? list.byId : null])
4454
4766
  // Last-known real titles for the cold-restart fallback window (see
4455
4767
  // the title-cache block). Read per render via getSnapshot: no
4456
4768
  // subscription, because a cache write only happens when summary.title
@@ -4670,7 +4982,7 @@ window.__ModuleLoader__.load({
4670
4982
  if (list && Array.isArray(list.ids)) {
4671
4983
  for (const id of list.ids) {
4672
4984
  const summary = list.byId[id]
4673
- if (accounted.has(id) || !sessionVisible(summary, list.current, archivedSet)) continue
4985
+ if (accounted.has(id) || !sessionVisible(summary, currentId, archivedSet)) continue
4674
4986
  ungrouped.push({
4675
4987
  id,
4676
4988
  title: sessionTitleOf(summary, t, rememberedTitleOf(id)),
@@ -4696,10 +5008,10 @@ window.__ModuleLoader__.load({
4696
5008
  // their drop targets live inside workspace rows, which compression merges.
4697
5009
  const draggingWorkspace = drag !== null && drag.kind === 'workspace'
4698
5010
  const tree = React.useMemo(() => {
4699
- const built = buildTree(items)
5011
+ const built = buildTree(items, workspaceSlash)
4700
5012
  if (!compactChains || draggingWorkspace) return built
4701
5013
  return { ...built, folders: built.folders.map((f) => materializeChain(compressTree(f))), workspaces: built.workspaces }
4702
- }, [items, compactChains, draggingWorkspace])
5014
+ }, [items, compactChains, draggingWorkspace, workspaceSlash])
4703
5015
  // Disk-layer ancestry for drag semantics (same derivation as buildTree).
4704
5016
  const diskParentMap = React.useMemo(() => diskParentMapOf(items), [items])
4705
5017
 
@@ -4714,7 +5026,7 @@ window.__ModuleLoader__.load({
4714
5026
  const rows = []
4715
5027
  for (const id of workspace.sessionIds || []) {
4716
5028
  const summary = list && list.byId ? list.byId[id] : undefined
4717
- if (!sessionVisible(summary, list ? list.current : undefined, archivedSet)) continue
5029
+ if (!sessionVisible(summary, currentId, archivedSet)) continue
4718
5030
  rows.push({
4719
5031
  id,
4720
5032
  title: sessionTitleOf(summary, t, rememberedTitleOf(id)),
@@ -4733,6 +5045,21 @@ window.__ModuleLoader__.load({
4733
5045
  // user dragged in, and is empty everywhere else — so a host that still
4734
5046
  // exposes the action keeps its authoritative order untouched.
4735
5047
  // Host order stays authoritative wherever the action exists.
5048
+ // Recency ordering (v0.13 view option, official orderBy semantics):
5049
+ // updatedAt descending with an id tie-break, and the CURRENT blank
5050
+ // session — the provisional New Session row — pinned on top. Purely
5051
+ // presentational: nothing is persisted, the host order is untouched,
5052
+ // and drag-to-reorder anchors are suppressed while active (an order
5053
+ // the very next render would re-sort is a lie).
5054
+ if (orderBy === 'updated') {
5055
+ const sorted = rows.slice().sort((a, b) => (b.updatedAt - a.updatedAt) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
5056
+ const pin = currentId !== undefined && sorted.find((row) => row.id === currentId && row.blank)
5057
+ if (pin) {
5058
+ const at = sorted.indexOf(pin)
5059
+ if (at > 0) { sorted.splice(at, 1); sorted.unshift(pin) }
5060
+ }
5061
+ return sorted
5062
+ }
4736
5063
  const local = typeof insertSessionBefore === 'function' ? [] : sessionOrderOf(workspace.workspaceId)
4737
5064
  if (local.length === 0) return rows
4738
5065
  const remaining = new Map(rows.map((row) => [row.id, row]))
@@ -4791,7 +5118,7 @@ window.__ModuleLoader__.load({
4791
5118
  // tree AND its disk-nested child levels.
4792
5119
  const wsAllPulseOf = (workspace) => {
4793
5120
  if (!statusPulse || searching) return null
4794
- let best = nodePulseOf(buildSessionTree(sessionsOf(workspace)))
5121
+ let best = nodePulseOf(buildSessionTree(sessionsOf(workspace), sessionSlash))
4795
5122
  if (workspace.sub) {
4796
5123
  for (const folder of workspace.sub.folders) {
4797
5124
  const s = folderPulseOf(folder)
@@ -4985,6 +5312,9 @@ window.__ModuleLoader__.load({
4985
5312
  /* ---------------------- session drag & drop --------------------- */
4986
5313
 
4987
5314
  const sessDropHalf = (sessionId) => {
5315
+ // Recency ordering is purely presentational: an anchor for a move
5316
+ // the very next render would re-sort is a lie — suppress it.
5317
+ if (orderBy === 'updated') return null
4988
5318
  if (!dragMatches('session')) return null
4989
5319
  const over = drag.over
4990
5320
  return over && over.kind === 'session' && over.target === sessionId ? over.half : null
@@ -5104,7 +5434,7 @@ window.__ModuleLoader__.load({
5104
5434
  if (name === target.name) { setDialog(null); return }
5105
5435
  const workspace = (items || []).find(w => w.workspaceId === target.workspaceId)
5106
5436
  if (!workspace) { setDialog(null); return }
5107
- const node = findSessionGroup(buildSessionTree(sessionsOf(workspace)), target.path)
5437
+ const node = findSessionGroup(buildSessionTree(sessionsOf(workspace), sessionSlash), target.path)
5108
5438
  if (!node) { setDialog(null); return }
5109
5439
  const parentPath = target.path.includes('/') ? target.path.slice(0, target.path.lastIndexOf('/')) : ''
5110
5440
  const nextPath = parentPath !== '' ? parentPath + '/' + name : name
@@ -5165,7 +5495,7 @@ window.__ModuleLoader__.load({
5165
5495
  if (!searching && !sessionsOpenOf(workspace.workspaceId)) return []
5166
5496
  const rows = sessionsOf(workspace)
5167
5497
  if (rows.length === 0) return []
5168
- return renderSessionNode(buildSessionTree(rows), workspace.workspaceId, depth)
5498
+ return renderSessionNode(buildSessionTree(rows, sessionSlash), workspace.workspaceId, depth)
5169
5499
  }
5170
5500
  const searchSessionNode = (node) => {
5171
5501
  const groups = []
@@ -5208,7 +5538,7 @@ window.__ModuleLoader__.load({
5208
5538
  key: session.id,
5209
5539
  node: session,
5210
5540
  depth,
5211
- current: list && list.current === session.id,
5541
+ current: currentId === session.id,
5212
5542
  now,
5213
5543
  onOpen: (id) => open(id),
5214
5544
  onContextMenu: (e) => openCtx('session', session, e),
@@ -5221,14 +5551,14 @@ window.__ModuleLoader__.load({
5221
5551
 
5222
5552
  const renderWorkspaceEntry = (entry, depth, pulse) => {
5223
5553
  const { workspace } = entry
5224
- const count = countSessionTree(buildSessionTree(sessionsOf(workspace)))
5554
+ const count = countSessionTree(buildSessionTree(sessionsOf(workspace), sessionSlash))
5225
5555
  const rows = [E(WorkspaceRow, {
5226
5556
  key: 'ws-' + workspace.workspaceId,
5227
5557
  workspace,
5228
5558
  depth,
5229
5559
  count,
5230
5560
  sessionsOpen: searching ? true : sessionsOpenOf(workspace.workspaceId),
5231
- currentInside: !!(list && list.current && (workspace.sessionIds || []).includes(list.current)),
5561
+ currentInside: !!(currentId && (workspace.sessionIds || []).includes(currentId)),
5232
5562
  onToggle: () => { if (!searching) actions.setSessionsExpanded(workspace.workspaceId, !sessionsOpenOf(workspace.workspaceId)) },
5233
5563
  // Starting a session force-expands the workspace row: the user must
5234
5564
  // SEE the new session appear, even if the row was collapsed.
@@ -5286,16 +5616,41 @@ window.__ModuleLoader__.load({
5286
5616
  return rows
5287
5617
  }
5288
5618
 
5619
+ // Single flat list (v0.13 groupBy:'flat', official FlatList semantics):
5620
+ // every visible session — each workspace's rows plus the ungrouped
5621
+ // account — as one depth-0 list. Rows keep their FULL title (no leaf
5622
+ // split, no levels), and render through the workspaceId-less path,
5623
+ // which carries no drag anchors by construction.
5624
+ const renderFlatRows = () => {
5625
+ const rows = []
5626
+ for (const workspace of items || []) rows.push(...sessionsOf(workspace))
5627
+ rows.push(...ungrouped)
5628
+ return rows.map((s) => renderSessionRow({ ...s, leaf: s.title }, 0, undefined))
5629
+ }
5630
+ const renderUngroupedBlock = () => {
5631
+ const rows = []
5632
+ if (ungrouped.length > 0) {
5633
+ rows.push(E('div', { key: 'ungrouped-label', className: 'bw-header-title', style: { padding: '10px 6px 2px' } }, t('group.ungrouped')))
5634
+ for (const s of ungrouped) rows.push(renderSessionRow(s, 0))
5635
+ }
5636
+ return rows
5637
+ }
5289
5638
  let bodyRows = []
5290
5639
  if (searching) {
5291
5640
  for (const entry of searched) bodyRows.push(...renderWorkspaceEntry(entry, 0))
5641
+ } else if (groupBy === 'flat') {
5642
+ bodyRows.push(...renderFlatRows())
5643
+ } else if (groupBy === 'workspace') {
5644
+ // Official 'workspace' mode (v0.13): one level — every workspace at
5645
+ // the root, no name groups, no disk nesting, no chain compression.
5646
+ // Session rows keep the slash toggle; disk-nested children do not
5647
+ // recurse here because raw items carry no .sub level.
5648
+ for (const workspace of items || []) bodyRows.push(...renderWorkspaceEntry({ workspace }, 0, wsPulseOf(workspace)))
5649
+ bodyRows.push(...renderUngroupedBlock())
5292
5650
  } else {
5293
5651
  for (const folder of tree.folders) bodyRows.push(...renderPlainFolder(folder, 0))
5294
5652
  for (const workspace of tree.workspaces) bodyRows.push(...renderWorkspaceEntry({ workspace }, 0, wsPulseOf(workspace)))
5295
- if (ungrouped.length > 0) {
5296
- bodyRows.push(E('div', { key: 'ungrouped-label', className: 'bw-header-title', style: { padding: '10px 6px 2px' } }, t('group.ungrouped')))
5297
- for (const s of ungrouped) bodyRows.push(renderSessionRow(s, 0))
5298
- }
5653
+ bodyRows.push(...renderUngroupedBlock())
5299
5654
  }
5300
5655
  const isEmpty = bodyRows.length === 0
5301
5656
  if (isEmpty) {
@@ -5453,6 +5808,15 @@ window.__ModuleLoader__.load({
5453
5808
  onKeyDown: (e) => { if (e.key === 'Escape') { setQuery(''); setSearchOpen(false) } },
5454
5809
  onBlur: () => { if (query === '') setSearchOpen(false) },
5455
5810
  }) : null,
5811
+ E(ViewOptionsMenu, {
5812
+ groupBy,
5813
+ orderBy,
5814
+ sessionSlash,
5815
+ workspaceSlash,
5816
+ onPick: (kind, value) => { if (kind === 'groupBy') actions.setGroupBy(value); else actions.setOrderBy(value) },
5817
+ onToggle: (key, value) => { if (key === 'sessionTitleSlash') actions.setSessionTitleSlash(value); else actions.setWorkspaceTitleSlash(value) },
5818
+ t,
5819
+ }),
5456
5820
  E('button', { type: 'button', className: 'bw-icon-btn', 'aria-label': t('search.placeholder'), onClick: () => setSearchOpen(v => !v) }, icon('IconSearchOutline16')),
5457
5821
  flowAvailable ? E('button', { type: 'button', className: 'bw-icon-btn', 'aria-label': t('add'), onClick: () => setFlowOpen(true) }, icon('IconProjectAddOutline16')) : null,
5458
5822
  ),
@@ -5571,22 +5935,28 @@ window.__ModuleLoader__.load({
5571
5935
  if (!result || !result.ok) throw new Error(result && result.error ? result.error.message : 'session search failed')
5572
5936
  return result.value
5573
5937
  }
5938
+ // dsh 0.1.6-alpha.2 retention contract: rename borrows through
5939
+ // sessions.using with an explicit source — the old plain binding(id)
5940
+ // only ever saw already-retained sessions, so renaming a closed row
5941
+ // reported "unknown session". Fork and open go through the uiWorkspace
5942
+ // navigation service: ISessions no longer carries open() at all
5943
+ // (navigation belongs to the view owner, replaceMain).
5574
5944
  const renameSession = async (sessionId, title) => {
5575
- const binding = sessions.binding(sessionId)
5576
- const session = binding && binding.session
5577
- if (!session) throw new Error('unknown session "' + sessionId + '"')
5578
- const result = await session.rename(title)
5945
+ const result = await sessions.using(
5946
+ sessionId,
5947
+ { source: 'workspaceOperation' },
5948
+ (reference) => reference.binding.session.rename(title),
5949
+ )
5579
5950
  if (!result || !result.ok) throw new Error(result && result.error ? result.error.message : 'session rename failed')
5580
5951
  }
5581
5952
  const forkSession = (sessionId) => {
5582
- sessions.fork({ sessionId, increaseTitle: true })
5583
- .then((childId) => sessions.open(childId))
5953
+ uiWorkspace.forkSession(sessionId)
5584
5954
  .catch(() => { /* keep current selection */ })
5585
5955
  }
5586
5956
 
5587
5957
  const browserInjected = () => ({
5588
5958
  startSession: (workspaceId) => { uiWorkspace.startSession(workspaceId) },
5589
- open: (sessionId) => { sessions.open(sessionId) },
5959
+ open: (sessionId) => { uiWorkspace.openSession(sessionId) },
5590
5960
  searchSessions,
5591
5961
  searchResultLimit: sessions.searchResultLimit !== undefined ? sessions.searchResultLimit : 20,
5592
5962
  renameSession,