@norman-else/dsh-claude 0.1.20 → 0.1.22

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/lib/client.js CHANGED
@@ -577,15 +577,15 @@ window.__ModuleLoader__.load({
577
577
  const settingsBody = {
578
578
  margin: 0,
579
579
  color: "var(--dsw-alias-label-secondary)",
580
- fontSize: 13,
581
- lineHeight: "20px"
580
+ fontSize: 14,
581
+ lineHeight: "22px"
582
582
  };
583
583
  const settingsCard = {
584
584
  display: "flex",
585
585
  flexDirection: "column",
586
586
  gap: 14,
587
587
  padding: 18,
588
- border: "1px solid var(--dsw-alias-border-l2)",
588
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
589
589
  borderRadius: 14,
590
590
  background: "var(--dsw-alias-bg-layer-1)"
591
591
  };
@@ -600,8 +600,8 @@ window.__ModuleLoader__.load({
600
600
  gridTemplateColumns: "minmax(130px, 0.36fr) minmax(0, 1fr)",
601
601
  gap: "10px 18px",
602
602
  padding: "14px 0",
603
- borderTop: "1px solid var(--dsw-alias-border-l2)",
604
- borderBottom: "1px solid var(--dsw-alias-border-l2)",
603
+ borderTop: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
604
+ borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
605
605
  fontSize: 13
606
606
  };
607
607
  const diagnosticLabel = { color: "var(--dsw-alias-label-tertiary)" };
@@ -620,13 +620,13 @@ window.__ModuleLoader__.load({
620
620
  boxSizing: "border-box",
621
621
  minHeight: 38,
622
622
  padding: "7px 13px",
623
- border: "1px solid var(--dsw-alias-border-l2)",
623
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
624
624
  borderRadius: 10,
625
625
  background: "var(--dsw-alias-bg-layer-2)",
626
626
  color: "var(--dsw-alias-label-primary)",
627
627
  font: "inherit",
628
- fontSize: 13,
629
- lineHeight: "20px"
628
+ fontSize: 14,
629
+ lineHeight: "22px"
630
630
  };
631
631
  const settingSelectTrigger = {
632
632
  width: "100%",
@@ -636,14 +636,14 @@ window.__ModuleLoader__.load({
636
636
  justifyContent: "space-between",
637
637
  gap: 12,
638
638
  padding: "7px 11px 7px 13px",
639
- border: "1px solid var(--dsw-alias-border-l2)",
639
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
640
640
  borderRadius: 10,
641
641
  background: "var(--dsw-alias-bg-layer-2)",
642
642
  color: "var(--dsw-alias-label-primary)",
643
643
  boxShadow: "0 1px 2px color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent)",
644
644
  font: "inherit",
645
- fontSize: 13,
646
- lineHeight: "20px",
645
+ fontSize: 14,
646
+ lineHeight: "22px",
647
647
  textAlign: "left",
648
648
  cursor: "pointer",
649
649
  transition: "border-color 120ms ease, box-shadow 120ms ease, background 120ms ease"
@@ -678,7 +678,7 @@ window.__ModuleLoader__.load({
678
678
  maxHeight: 240,
679
679
  overflowY: "auto",
680
680
  padding: 5,
681
- border: "1px solid var(--dsw-alias-border-l2)",
681
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
682
682
  borderRadius: 11,
683
683
  background: "var(--dsw-alias-bg-layer-1)",
684
684
  boxShadow: "0 12px 32px color-mix(in srgb, var(--dsw-alias-label-primary) 16%, transparent), 0 2px 8px color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent)"
@@ -695,8 +695,8 @@ window.__ModuleLoader__.load({
695
695
  background: "transparent",
696
696
  color: "var(--dsw-alias-label-primary)",
697
697
  font: "inherit",
698
- fontSize: 13,
699
- lineHeight: "20px",
698
+ fontSize: 14,
699
+ lineHeight: "22px",
700
700
  textAlign: "left",
701
701
  cursor: "pointer"
702
702
  };
@@ -728,7 +728,7 @@ window.__ModuleLoader__.load({
728
728
  flex: "none",
729
729
  minHeight: 34,
730
730
  padding: "6px 14px",
731
- border: "1px solid var(--dsw-alias-border-l2)",
731
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
732
732
  borderRadius: 9,
733
733
  background: "var(--dsw-alias-bg-layer-2)",
734
734
  color: "var(--dsw-alias-label-primary)",
@@ -752,7 +752,7 @@ window.__ModuleLoader__.load({
752
752
  minWidth: 0,
753
753
  margin: 8,
754
754
  overflow: "hidden",
755
- border: "1px solid var(--dsw-alias-border-l2)",
755
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
756
756
  borderRadius: 12,
757
757
  background: "var(--dsw-alias-bg-layer-1)",
758
758
  boxShadow: "0 4px 16px color-mix(in srgb, #000 12%, transparent)"
@@ -766,7 +766,7 @@ window.__ModuleLoader__.load({
766
766
  justifyContent: "space-between",
767
767
  gap: 10,
768
768
  padding: "9px 12px",
769
- borderBottom: "1px solid var(--dsw-alias-border-l2)"
769
+ borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))"
770
770
  };
771
771
  const tasksHeading = {
772
772
  display: "block",
@@ -830,8 +830,8 @@ window.__ModuleLoader__.load({
830
830
  alignItems: "center",
831
831
  gap: 6,
832
832
  color: "var(--dsw-alias-label-secondary)",
833
- fontSize: 13,
834
- lineHeight: "20px",
833
+ fontSize: 14,
834
+ lineHeight: "22px",
835
835
  fontWeight: 600
836
836
  };
837
837
  const tasksGroupToggle = {
@@ -843,8 +843,8 @@ window.__ModuleLoader__.load({
843
843
  background: "transparent",
844
844
  color: "var(--dsw-alias-label-secondary)",
845
845
  font: "inherit",
846
- fontSize: 13,
847
- lineHeight: "20px",
846
+ fontSize: 14,
847
+ lineHeight: "22px",
848
848
  fontWeight: 600,
849
849
  cursor: "pointer"
850
850
  };
@@ -868,7 +868,7 @@ window.__ModuleLoader__.load({
868
868
  const tasksFinishedSection = {
869
869
  marginTop: 12,
870
870
  paddingTop: 8,
871
- borderTop: "1px solid var(--dsw-alias-border-l2)"
871
+ borderTop: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))"
872
872
  };
873
873
  const taskCardList = {
874
874
  display: "flex",
@@ -878,12 +878,12 @@ window.__ModuleLoader__.load({
878
878
  };
879
879
  const taskCard = {
880
880
  padding: "11px 12px",
881
- border: "1px solid var(--dsw-alias-border-l2)",
881
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
882
882
  borderRadius: 10,
883
883
  background: "var(--dsw-alias-bg-layer-1)",
884
884
  boxShadow: "0 1px 3px color-mix(in srgb, #000 7%, transparent)"
885
885
  };
886
- const taskCardRunning = { borderColor: "var(--dsw-alias-border-l3)" };
886
+ const taskCardRunning = { borderColor: "var(--dsw-alias-border-l3, color-mix(in srgb, currentColor 24%, transparent))" };
887
887
  const taskCardTop = {
888
888
  display: "flex",
889
889
  alignItems: "flex-start",
@@ -994,7 +994,7 @@ window.__ModuleLoader__.load({
994
994
  };
995
995
  const tasksBadgeWrap = {
996
996
  display: "flex",
997
- justifyContent: "flex-end",
997
+ justifyContent: "flex-start",
998
998
  margin: "8px 0 4px"
999
999
  };
1000
1000
  const tasksBadgeSeat = {
@@ -1009,15 +1009,15 @@ window.__ModuleLoader__.load({
1009
1009
  border: "none",
1010
1010
  borderRadius: 6,
1011
1011
  background: "transparent",
1012
- color: "var(--dsw-alias-label-tertiary)",
1012
+ color: "var(--dsw-static-blue-450)",
1013
1013
  font: "inherit",
1014
- fontSize: 11,
1015
- lineHeight: "16px",
1014
+ fontSize: 14,
1015
+ lineHeight: "22px",
1016
1016
  fontVariantNumeric: "tabular-nums",
1017
1017
  cursor: "pointer",
1018
1018
  transition: "color 120ms ease, opacity 120ms ease"
1019
1019
  };
1020
- const tasksBadgeHovered = { color: "var(--dsw-alias-label-secondary)" };
1020
+ const tasksBadgeHovered = { textDecoration: "underline" };
1021
1021
  const tasksBadgeDone = { opacity: .7 };
1022
1022
  const tasksBadgeDot = {
1023
1023
  width: 8,
@@ -1028,10 +1028,10 @@ window.__ModuleLoader__.load({
1028
1028
  };
1029
1029
  const tasksBadgeDotError = { background: "var(--dsw-alias-state-error-primary)" };
1030
1030
  const tasksBadgeDotDone = { background: "var(--dsw-alias-state-success-primary, var(--dsw-static-green-500))" };
1031
- const tasksBadgeCount = { fontWeight: 600 };
1031
+ const tasksBadgeLabel = { fontWeight: 500 };
1032
1032
  const tasksHoverCard = {
1033
1033
  position: "absolute",
1034
- right: 0,
1034
+ left: 0,
1035
1035
  bottom: "calc(100% + 8px)",
1036
1036
  zIndex: 40,
1037
1037
  minWidth: 240,
@@ -1041,7 +1041,7 @@ window.__ModuleLoader__.load({
1041
1041
  flexDirection: "column",
1042
1042
  gap: 6,
1043
1043
  padding: "10px 12px",
1044
- border: "1px solid var(--dsw-alias-border-l2)",
1044
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1045
1045
  borderRadius: 12,
1046
1046
  background: "var(--dsw-alias-bg-layer-2)",
1047
1047
  boxShadow: "0 8px 24px color-mix(in srgb, #000 24%, transparent)",
@@ -1087,7 +1087,7 @@ window.__ModuleLoader__.load({
1087
1087
  const tasksHoverHint = {
1088
1088
  marginTop: 2,
1089
1089
  paddingTop: 6,
1090
- borderTop: "1px solid var(--dsw-alias-border-l1)",
1090
+ borderTop: "1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent))",
1091
1091
  color: "var(--dsw-alias-label-tertiary)",
1092
1092
  fontSize: 11
1093
1093
  };
@@ -1104,7 +1104,7 @@ window.__ModuleLoader__.load({
1104
1104
  alignItems: "center",
1105
1105
  minWidth: 0,
1106
1106
  padding: 2,
1107
- border: "1px solid var(--dsw-alias-border-l1)",
1107
+ border: "1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent))",
1108
1108
  borderRadius: 10,
1109
1109
  background: "var(--dsw-alias-interactive-bg-base, var(--dsw-alias-bg-layer-1))",
1110
1110
  color: "var(--dsw-alias-label-secondary)"
@@ -1149,7 +1149,7 @@ window.__ModuleLoader__.load({
1149
1149
  flexDirection: "column",
1150
1150
  gap: 4,
1151
1151
  padding: 4,
1152
- border: "1px solid var(--dsw-alias-border-inverted)",
1152
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1153
1153
  borderRadius: 10,
1154
1154
  background: "var(--dsw-specific-menu)",
1155
1155
  boxShadow: "var(--dsw-shadow-lv3)"
@@ -1161,7 +1161,7 @@ window.__ModuleLoader__.load({
1161
1161
  alignItems: "center",
1162
1162
  gap: 6,
1163
1163
  padding: "0 8px",
1164
- border: "1px solid var(--dsw-alias-border-l2)",
1164
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1165
1165
  borderRadius: 7,
1166
1166
  background: "var(--dsw-alias-bg-layer-1)",
1167
1167
  color: "var(--dsw-alias-label-tertiary)"
@@ -1221,7 +1221,7 @@ window.__ModuleLoader__.load({
1221
1221
  width: 1,
1222
1222
  height: 16,
1223
1223
  flex: "none",
1224
- background: "var(--dsw-alias-border-l2)"
1224
+ background: "var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))"
1225
1225
  };
1226
1226
  const heroWorktreeToggle = {
1227
1227
  height: 26,
@@ -1253,7 +1253,7 @@ window.__ModuleLoader__.load({
1253
1253
  display: "grid",
1254
1254
  placeItems: "center",
1255
1255
  flex: "none",
1256
- border: "1px solid var(--dsw-alias-border-inverted)",
1256
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1257
1257
  borderRadius: 4,
1258
1258
  background: "var(--dsw-alias-bg-layer-2)",
1259
1259
  boxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.08)",
@@ -1281,7 +1281,7 @@ window.__ModuleLoader__.load({
1281
1281
  flexDirection: "column",
1282
1282
  gap: 12,
1283
1283
  padding: 14,
1284
- border: "1px solid var(--dsw-alias-border-l2)",
1284
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1285
1285
  borderRadius: 12,
1286
1286
  background: "var(--dsw-alias-bg-layer-1)",
1287
1287
  boxShadow: "var(--dsw-shadow-lv3)"
@@ -1401,18 +1401,18 @@ window.__ModuleLoader__.load({
1401
1401
  alignItems: "center",
1402
1402
  gap: 9,
1403
1403
  padding: "7px 11px",
1404
- border: "1px solid var(--dsw-alias-border-l2)",
1404
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1405
1405
  borderRadius: 11,
1406
1406
  background: "var(--dsw-alias-bg-layer-1)",
1407
1407
  color: "var(--dsw-alias-label-primary)",
1408
1408
  boxShadow: "0 1px 2px color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent)",
1409
1409
  font: "inherit",
1410
- fontSize: 13,
1411
- lineHeight: "20px",
1410
+ fontSize: 14,
1411
+ lineHeight: "22px",
1412
1412
  textAlign: "left"
1413
1413
  };
1414
1414
  const repositoryBarMerged = {
1415
- borderColor: "color-mix(in srgb, #a78bfa 30%, var(--dsw-alias-border-l2))",
1415
+ borderColor: "color-mix(in srgb, #a78bfa 30%, var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent)))",
1416
1416
  background: "color-mix(in srgb, #a78bfa 5%, var(--dsw-alias-bg-layer-1))"
1417
1417
  };
1418
1418
  const repositoryPrIcon = {
@@ -1457,7 +1457,7 @@ window.__ModuleLoader__.load({
1457
1457
  flexDirection: "column",
1458
1458
  gap: 10,
1459
1459
  padding: "13px 14px",
1460
- border: "1px solid var(--dsw-alias-border-l2)",
1460
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1461
1461
  borderRadius: 12,
1462
1462
  background: "var(--dsw-alias-bg-layer-1)",
1463
1463
  boxShadow: "0 14px 38px color-mix(in srgb, #000 34%, transparent)",
@@ -1632,7 +1632,7 @@ window.__ModuleLoader__.load({
1632
1632
  gap: 4,
1633
1633
  minHeight: 26,
1634
1634
  padding: "3px 8px",
1635
- border: "1px solid var(--dsw-alias-border-l2)",
1635
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1636
1636
  borderRadius: 7,
1637
1637
  background: "var(--dsw-alias-bg-layer-2)",
1638
1638
  font: "inherit",
@@ -1645,6 +1645,23 @@ window.__ModuleLoader__.load({
1645
1645
  background: "transparent",
1646
1646
  color: "var(--dsw-alias-label-tertiary)"
1647
1647
  };
1648
+ const repositoryMergeTrigger = {
1649
+ flex: "none",
1650
+ display: "inline-flex",
1651
+ alignItems: "center",
1652
+ gap: 4,
1653
+ minHeight: 26,
1654
+ padding: "3px 8px",
1655
+ border: "1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent)",
1656
+ borderRadius: 7,
1657
+ background: "color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent)",
1658
+ color: "var(--dsw-alias-state-success-primary)",
1659
+ font: "inherit",
1660
+ fontSize: 12,
1661
+ lineHeight: "18px",
1662
+ fontWeight: 650,
1663
+ cursor: "pointer"
1664
+ };
1648
1665
  const diffAdd = { color: "var(--dsw-alias-state-success-primary)" };
1649
1666
  const diffDelete = { color: "var(--dsw-alias-state-error-primary)" };
1650
1667
  const diffCommentButtonClass = "dshClaudeDiffCommentButton";
@@ -1690,7 +1707,7 @@ window.__ModuleLoader__.load({
1690
1707
  left: 62,
1691
1708
  margin: "4px 8px 8px 62px",
1692
1709
  padding: "8px 10px",
1693
- border: "1px solid var(--dsw-alias-border-l2)",
1710
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1694
1711
  borderRadius: 8,
1695
1712
  background: "var(--dsw-alias-bg-layer-1)",
1696
1713
  fontFamily: "var(--dsw-font-family, system-ui)",
@@ -1717,7 +1734,7 @@ window.__ModuleLoader__.load({
1717
1734
  minHeight: 56,
1718
1735
  boxSizing: "border-box",
1719
1736
  padding: "6px 8px",
1720
- border: "1px solid var(--dsw-alias-border-l2)",
1737
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1721
1738
  borderRadius: 6,
1722
1739
  background: "var(--dsw-alias-bg-base)",
1723
1740
  color: "var(--dsw-alias-label-primary)",
@@ -1733,7 +1750,7 @@ window.__ModuleLoader__.load({
1733
1750
  const diffCommentActionButton = {
1734
1751
  minHeight: 24,
1735
1752
  padding: "2px 10px",
1736
- border: "1px solid var(--dsw-alias-border-l2)",
1753
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1737
1754
  borderRadius: 6,
1738
1755
  background: "transparent",
1739
1756
  color: "var(--dsw-alias-label-secondary)",
@@ -1768,7 +1785,7 @@ window.__ModuleLoader__.load({
1768
1785
  alignItems: "center",
1769
1786
  gap: 8,
1770
1787
  padding: "7px 11px",
1771
- border: "1px solid var(--dsw-alias-border-l2)",
1788
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1772
1789
  borderRadius: 11,
1773
1790
  background: "var(--dsw-alias-bg-layer-1)",
1774
1791
  boxShadow: "0 1px 2px color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent)",
@@ -1856,7 +1873,7 @@ window.__ModuleLoader__.load({
1856
1873
  minWidth: 0,
1857
1874
  margin: 8,
1858
1875
  overflow: "hidden",
1859
- border: "1px solid var(--dsw-alias-border-l2)",
1876
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1860
1877
  borderRadius: 12,
1861
1878
  background: "var(--dsw-alias-bg-layer-1)",
1862
1879
  boxShadow: "0 4px 16px color-mix(in srgb, #000 12%, transparent)"
@@ -1875,7 +1892,7 @@ window.__ModuleLoader__.load({
1875
1892
  justifyContent: "space-between",
1876
1893
  gap: 10,
1877
1894
  padding: "9px 12px",
1878
- borderBottom: "1px solid var(--dsw-alias-border-l2)"
1895
+ borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))"
1879
1896
  };
1880
1897
  const diffHeaderTitle = {
1881
1898
  minWidth: 0,
@@ -1939,7 +1956,7 @@ window.__ModuleLoader__.load({
1939
1956
  alignItems: "center",
1940
1957
  gap: 7,
1941
1958
  padding: "6px 12px",
1942
- borderBottom: "1px solid var(--dsw-alias-border-l2)",
1959
+ borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1943
1960
  color: "var(--dsw-alias-label-tertiary)",
1944
1961
  fontSize: 12
1945
1962
  };
@@ -1949,7 +1966,7 @@ window.__ModuleLoader__.load({
1949
1966
  overflow: "auto",
1950
1967
  background: "var(--dsw-alias-bg-base)"
1951
1968
  };
1952
- const diffFile = { borderBottom: "1px solid var(--dsw-alias-border-l2)" };
1969
+ const diffFile = { borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))" };
1953
1970
  const diffFileHeader = {
1954
1971
  width: "100%",
1955
1972
  minHeight: 38,
@@ -1984,8 +2001,8 @@ window.__ModuleLoader__.load({
1984
2001
  padding: "4px 0 8px",
1985
2002
  background: "var(--dsw-alias-bg-base)",
1986
2003
  fontFamily: "var(--dsw-font-family-mono, ui-monospace, SFMono-Regular, Consolas, monospace)",
1987
- fontSize: 13,
1988
- lineHeight: "20px"
2004
+ fontSize: 14,
2005
+ lineHeight: "22px"
1989
2006
  };
1990
2007
  const diffLine = {
1991
2008
  minHeight: 17,
@@ -2099,7 +2116,7 @@ window.__ModuleLoader__.load({
2099
2116
  maxHeight: 300,
2100
2117
  overflowX: "hidden",
2101
2118
  overflowY: "auto",
2102
- border: "1px solid var(--dsw-alias-border-l2)",
2119
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
2103
2120
  borderRadius: 8
2104
2121
  };
2105
2122
  const diffModalFile = {
@@ -2108,7 +2125,7 @@ window.__ModuleLoader__.load({
2108
2125
  gap: 12,
2109
2126
  minWidth: 0,
2110
2127
  padding: "10px 14px",
2111
- borderBottom: "1px solid var(--dsw-alias-border-l2)",
2128
+ borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
2112
2129
  color: "var(--dsw-alias-label-secondary)",
2113
2130
  fontSize: 15,
2114
2131
  lineHeight: "22px"
@@ -2576,8 +2593,8 @@ window.__ModuleLoader__.load({
2576
2593
  },
2577
2594
  "aria-hidden": "true"
2578
2595
  }), /* @__PURE__ */ jsx("span", {
2579
- style: tasksBadgeCount,
2580
- children: turnTasks.length
2596
+ style: tasksBadgeLabel,
2597
+ children: label
2581
2598
  })]
2582
2599
  })]
2583
2600
  })
@@ -2606,6 +2623,426 @@ window.__ModuleLoader__.load({
2606
2623
  });
2607
2624
  }
2608
2625
  //#endregion
2626
+ //#region src/client/projection.ts
2627
+ const EMPTY_CLAUDE_PROJECTION = {
2628
+ schemaVersion: 1,
2629
+ revision: 0,
2630
+ owned: false,
2631
+ commands: [],
2632
+ activities: []
2633
+ };
2634
+ const RETRY_DELAY_MS = 2e3;
2635
+ /** Coalesce stream deltas into at most one React notification per frame. */
2636
+ const FRAME_MS = 16;
2637
+ /** Typewriter smoothing: drain newly arrived prose over roughly this window,
2638
+ * so the CLI's paragraph-sized deltas read as a continuous character flow. */
2639
+ const REVEAL_WINDOW_MS = 1200;
2640
+ /** A burst larger than this (redaction rewrite, reconnect catch-up) shows
2641
+ * instantly instead of animating for a long stretch. */
2642
+ const MAX_INSTANT_REVEAL = 4e3;
2643
+ const MAX_ACTIVITIES = 1e4;
2644
+ const MAX_COMMANDS = 2e3;
2645
+ const MAX_REPOSITORY_TEXT_CHARS = 1024;
2646
+ const MAX_DIFF_CHARS = 262144;
2647
+ const MAX_REVIEW_COMMENTS = 50;
2648
+ const MAX_REVIEW_COMMENT_CHARS = 2e3;
2649
+ const MAX_TRANSCRIPT_CHARS = 64e3;
2650
+ function record$4(value) {
2651
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2652
+ }
2653
+ function nonNegativeInteger(value) {
2654
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
2655
+ }
2656
+ function optionalBoundedString(value) {
2657
+ return value === void 0 || typeof value === "string" && value.length <= MAX_REPOSITORY_TEXT_CHARS;
2658
+ }
2659
+ function validateRepository(value) {
2660
+ const repository = record$4(value);
2661
+ if (repository === void 0 || ![
2662
+ "ready",
2663
+ "not-repository",
2664
+ "unavailable"
2665
+ ].includes(String(repository.status)) || typeof repository.cwd !== "string" || repository.cwd.length > MAX_REPOSITORY_TEXT_CHARS || !optionalBoundedString(repository.root) || !optionalBoundedString(repository.branch) || !optionalBoundedString(repository.remote) || repository.detached !== void 0 && typeof repository.detached !== "boolean" || repository.worktree !== void 0 && typeof repository.worktree !== "boolean" || repository.dirty !== void 0 && typeof repository.dirty !== "boolean" || repository.upstream !== void 0 && typeof repository.upstream !== "boolean" || repository.ahead !== void 0 && !nonNegativeInteger(repository.ahead) || repository.behind !== void 0 && !nonNegativeInteger(repository.behind)) return false;
2666
+ if (repository.diff !== void 0) {
2667
+ const diff = record$4(repository.diff);
2668
+ if (diff === void 0 || !nonNegativeInteger(diff.additions) || !nonNegativeInteger(diff.deletions) || !nonNegativeInteger(diff.files) || typeof diff.truncated !== "boolean" || diff.patch !== void 0 && (typeof diff.patch !== "string" || diff.patch.length > MAX_DIFF_CHARS)) return false;
2669
+ }
2670
+ if (repository.pullRequest === void 0) return true;
2671
+ const pullRequest = record$4(repository.pullRequest);
2672
+ if (pullRequest === void 0 || !Number.isSafeInteger(pullRequest.number) || Number(pullRequest.number) <= 0 || typeof pullRequest.title !== "string" || pullRequest.title.length > MAX_REPOSITORY_TEXT_CHARS || typeof pullRequest.url !== "string" || pullRequest.url.length > MAX_REPOSITORY_TEXT_CHARS || ![
2673
+ "open",
2674
+ "closed",
2675
+ "merged"
2676
+ ].includes(String(pullRequest.state)) || typeof pullRequest.draft !== "boolean" || ![
2677
+ "approved",
2678
+ "changes-requested",
2679
+ "review-required",
2680
+ "none"
2681
+ ].includes(String(pullRequest.review)) || ![
2682
+ "passing",
2683
+ "pending",
2684
+ "failing",
2685
+ "none"
2686
+ ].includes(String(pullRequest.checks)) || !optionalBoundedString(pullRequest.mergeState) || !optionalBoundedString(pullRequest.author) || !optionalBoundedString(pullRequest.baseBranch) || pullRequest.createdAt !== void 0 && (typeof pullRequest.createdAt !== "string" || !Number.isFinite(Date.parse(pullRequest.createdAt))) || pullRequest.mergedAt !== void 0 && (typeof pullRequest.mergedAt !== "string" || !Number.isFinite(Date.parse(pullRequest.mergedAt)))) return false;
2687
+ try {
2688
+ const url = new URL(pullRequest.url);
2689
+ return url.protocol === "https:" && url.hostname === "github.com";
2690
+ } catch {
2691
+ return false;
2692
+ }
2693
+ }
2694
+ /** Validate the public route envelope before publishing it to UI components. */
2695
+ function parseClaudeClientProjection(value) {
2696
+ const input = record$4(value);
2697
+ if (input === void 0 || input.schemaVersion !== 1 || !nonNegativeInteger(input.revision) || typeof input.owned !== "boolean" || !Array.isArray(input.commands) || input.commands.length > MAX_COMMANDS || !Array.isArray(input.activities) || input.activities.length > MAX_ACTIVITIES) throw new Error("invalid Claude sidecar projection");
2698
+ for (const item of input.commands) {
2699
+ const command = record$4(item);
2700
+ if (command === void 0 || typeof command.publicName !== "string" || typeof command.claudeName !== "string" || typeof command.description !== "string" || command.hint !== void 0 && typeof command.hint !== "string" || typeof command.prefixed !== "boolean") throw new Error("invalid Claude command projection");
2701
+ }
2702
+ for (const item of input.activities) {
2703
+ const activity = record$4(item);
2704
+ if (activity === void 0 || !nonNegativeInteger(activity.turn) || !nonNegativeInteger(activity.step) || !nonNegativeInteger(activity.ordinal) || typeof activity.kind !== "string") throw new Error("invalid Claude sidecar activity");
2705
+ }
2706
+ if (input.contextUsage !== void 0 && record$4(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
2707
+ const tasks = input.tasks === void 0 ? void 0 : record$4(input.tasks);
2708
+ if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
2709
+ if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
2710
+ if (input.reviewComments !== void 0) {
2711
+ if (!Array.isArray(input.reviewComments) || input.reviewComments.length > MAX_REVIEW_COMMENTS) throw new Error("invalid Claude review comment projection");
2712
+ for (const item of input.reviewComments) {
2713
+ const comment = record$4(item);
2714
+ if (comment === void 0 || typeof comment.id !== "string" || comment.id.length === 0 || comment.id.length > 128 || typeof comment.path !== "string" || comment.path.length === 0 || comment.path.length > MAX_REPOSITORY_TEXT_CHARS || !nonNegativeInteger(comment.line) || comment.side !== "old" && comment.side !== "new" || typeof comment.text !== "string" || comment.text.length > MAX_REVIEW_COMMENT_CHARS) throw new Error("invalid Claude review comment projection");
2715
+ }
2716
+ }
2717
+ return input;
2718
+ }
2719
+ /** Validate one incremental delta payload with the same rules as a snapshot. */
2720
+ function validateEnvelopeFragment(fragment) {
2721
+ parseClaudeClientProjection({
2722
+ schemaVersion: 1,
2723
+ revision: 0,
2724
+ owned: false,
2725
+ commands: [],
2726
+ activities: [],
2727
+ ...fragment
2728
+ });
2729
+ }
2730
+ function stepKeyOf(turn, step) {
2731
+ return `${turn}:${step}`;
2732
+ }
2733
+ const EMPTY_ACTIVITIES = [];
2734
+ /** Identity-stable per-step slice; untouched steps never re-render while
2735
+ * another step streams. Falls back to filtering for snapshot-only hooks. */
2736
+ function selectStepActivities(value, turn, step) {
2737
+ const sliced = value.byStep?.get(stepKeyOf(turn, step));
2738
+ if (sliced !== void 0) return sliced;
2739
+ const filtered = value.activities.filter((activity) => activity.turn === turn && activity.step === step);
2740
+ return filtered.length === 0 ? EMPTY_ACTIVITIES : filtered;
2741
+ }
2742
+ function isAbort(error) {
2743
+ return error?.name === "AbortError";
2744
+ }
2745
+ function delay(ms) {
2746
+ return new Promise((resolve) => {
2747
+ setTimeout(resolve, ms).unref?.();
2748
+ });
2749
+ }
2750
+ /** Create one lazy source: active subscribers open the Host NDJSON stream, and
2751
+ * a dropped stream reconnects with a fresh snapshot after a bounded delay. */
2752
+ function createClaudeProjectionSource(sessionId, fetchProjection = fetch, retryDelayMs = RETRY_DELAY_MS) {
2753
+ let snapshot = EMPTY_CLAUDE_PROJECTION;
2754
+ let revision = 0;
2755
+ let owned = false;
2756
+ let commands = [];
2757
+ let contextUsage;
2758
+ let tasks;
2759
+ let repository;
2760
+ let reviewComments;
2761
+ const byStep = /* @__PURE__ */ new Map();
2762
+ const stepOrder = [];
2763
+ /** Streaming prose still being revealed: full arrived text plus shown chars. */
2764
+ const reveal = /* @__PURE__ */ new Map();
2765
+ let disposed = false;
2766
+ let running = false;
2767
+ let controller;
2768
+ let frame;
2769
+ let usedAnimationFrame = false;
2770
+ const listeners = /* @__PURE__ */ new Set();
2771
+ const ensureStep = (turn, step) => {
2772
+ const key = stepKeyOf(turn, step);
2773
+ const existing = byStep.get(key);
2774
+ if (existing !== void 0) return existing;
2775
+ const created = [];
2776
+ byStep.set(key, created);
2777
+ const at = stepOrder.findIndex((entry) => entry.turn > turn || entry.turn === turn && entry.step > step);
2778
+ stepOrder.splice(at === -1 ? stepOrder.length : at, 0, {
2779
+ turn,
2780
+ step,
2781
+ key
2782
+ });
2783
+ return created;
2784
+ };
2785
+ const upsertActivity = (activity) => {
2786
+ const key = stepKeyOf(activity.turn, activity.step);
2787
+ const next = ensureStep(activity.turn, activity.step).slice();
2788
+ const index = next.findIndex((item) => item.ordinal === activity.ordinal);
2789
+ if (index === -1) {
2790
+ const at = next.findIndex((item) => item.ordinal > activity.ordinal);
2791
+ next.splice(at === -1 ? next.length : at, 0, activity);
2792
+ } else next[index] = activity;
2793
+ byStep.set(key, next);
2794
+ };
2795
+ const reset = (activities) => {
2796
+ byStep.clear();
2797
+ stepOrder.length = 0;
2798
+ reveal.clear();
2799
+ for (const activity of activities) ensureStep(activity.turn, activity.step).push(activity);
2800
+ };
2801
+ /** Advance every pending typewriter reveal by one frame's worth of characters.
2802
+ * The per-frame step scales with the backlog so any burst drains in roughly
2803
+ * REVEAL_WINDOW_MS. Returns whether another frame is still needed. */
2804
+ const advanceReveals = () => {
2805
+ let remaining = false;
2806
+ for (const [key, entry] of reveal) {
2807
+ const total = entry.full.text?.length ?? 0;
2808
+ if (entry.shown >= total) {
2809
+ reveal.delete(key);
2810
+ continue;
2811
+ }
2812
+ const step = Math.max(1, Math.ceil((total - entry.shown) * FRAME_MS / REVEAL_WINDOW_MS));
2813
+ entry.shown = Math.min(total, entry.shown + step);
2814
+ upsertActivity({
2815
+ ...entry.full,
2816
+ text: (entry.full.text ?? "").slice(0, entry.shown)
2817
+ });
2818
+ if (entry.shown >= total) reveal.delete(key);
2819
+ else remaining = true;
2820
+ }
2821
+ return remaining;
2822
+ };
2823
+ const publish = () => {
2824
+ frame = void 0;
2825
+ if (disposed) return;
2826
+ const revealing = advanceReveals();
2827
+ const activities = [];
2828
+ for (const entry of stepOrder) {
2829
+ const slice = byStep.get(entry.key);
2830
+ if (slice !== void 0) for (const item of slice) activities.push(item);
2831
+ }
2832
+ snapshot = {
2833
+ schemaVersion: 1,
2834
+ revision,
2835
+ owned,
2836
+ commands,
2837
+ activities,
2838
+ ...contextUsage === void 0 ? {} : { contextUsage },
2839
+ ...tasks === void 0 ? {} : { tasks },
2840
+ ...repository === void 0 ? {} : { repository },
2841
+ ...reviewComments === void 0 ? {} : { reviewComments },
2842
+ byStep: new Map(byStep)
2843
+ };
2844
+ for (const listener of [...listeners]) listener();
2845
+ if (revealing) schedulePublish();
2846
+ };
2847
+ const cancelFrame = () => {
2848
+ if (frame === void 0) return;
2849
+ if (usedAnimationFrame) globalThis.cancelAnimationFrame?.(frame);
2850
+ else clearTimeout(frame);
2851
+ frame = void 0;
2852
+ };
2853
+ const schedulePublish = () => {
2854
+ if (disposed || frame !== void 0 || listeners.size === 0) return;
2855
+ const raf = globalThis.requestAnimationFrame;
2856
+ if (typeof raf === "function") {
2857
+ usedAnimationFrame = true;
2858
+ frame = raf(publish);
2859
+ } else {
2860
+ usedAnimationFrame = false;
2861
+ frame = setTimeout(publish, FRAME_MS);
2862
+ }
2863
+ };
2864
+ const applyText = (event) => {
2865
+ const { turn, step, ordinal, append, text } = event;
2866
+ if (!nonNegativeInteger(turn) || !nonNegativeInteger(step) || !nonNegativeInteger(ordinal)) return false;
2867
+ if (append !== void 0 && (typeof append !== "string" || append.length > MAX_TRANSCRIPT_CHARS)) return false;
2868
+ if (text !== void 0 && (typeof text !== "string" || text.length > MAX_TRANSCRIPT_CHARS)) return false;
2869
+ if (append === void 0 && text === void 0) return false;
2870
+ const revealKey = `${turn}:${step}:${ordinal}`;
2871
+ const existing = byStep.get(stepKeyOf(turn, step))?.find((item) => item.ordinal === ordinal);
2872
+ const pending = reveal.get(revealKey);
2873
+ if (existing === void 0 && pending === void 0 && typeof text !== "string") return false;
2874
+ const baseText = pending?.full.text ?? existing?.text ?? "";
2875
+ const fullText = (typeof text === "string" ? text : `${baseText}${append}`).slice(0, MAX_TRANSCRIPT_CHARS);
2876
+ const full = {
2877
+ ...pending?.full ?? existing ?? {
2878
+ turn,
2879
+ step,
2880
+ ordinal,
2881
+ kind: "text",
2882
+ phase: "updated"
2883
+ },
2884
+ text: fullText
2885
+ };
2886
+ const shown = Math.min(pending?.shown ?? existing?.text?.length ?? 0, fullText.length);
2887
+ if (fullText.length - shown > MAX_INSTANT_REVEAL) {
2888
+ reveal.delete(revealKey);
2889
+ upsertActivity(full);
2890
+ return true;
2891
+ }
2892
+ reveal.set(revealKey, {
2893
+ full,
2894
+ shown
2895
+ });
2896
+ upsertActivity({
2897
+ ...full,
2898
+ text: fullText.slice(0, shown)
2899
+ });
2900
+ return true;
2901
+ };
2902
+ const applyLine = (line) => {
2903
+ const trimmed = line.trim();
2904
+ if (trimmed.length === 0) return;
2905
+ let value;
2906
+ try {
2907
+ value = JSON.parse(trimmed);
2908
+ } catch {
2909
+ return;
2910
+ }
2911
+ const event = record$4(value);
2912
+ if (event === void 0 || typeof event.type !== "string") return;
2913
+ try {
2914
+ switch (event.type) {
2915
+ case "snapshot": {
2916
+ const next = parseClaudeClientProjection(event);
2917
+ revision = next.revision;
2918
+ owned = next.owned;
2919
+ commands = next.commands;
2920
+ contextUsage = next.contextUsage;
2921
+ tasks = next.tasks;
2922
+ repository = next.repository;
2923
+ reviewComments = next.reviewComments;
2924
+ reset(next.activities);
2925
+ break;
2926
+ }
2927
+ case "text":
2928
+ if (!applyText(event)) return;
2929
+ revision += 1;
2930
+ break;
2931
+ case "activity":
2932
+ validateEnvelopeFragment({ activities: [event.activity] });
2933
+ upsertActivity(event.activity);
2934
+ revision += 1;
2935
+ break;
2936
+ case "contextUsage":
2937
+ validateEnvelopeFragment({ contextUsage: event.value });
2938
+ contextUsage = event.value;
2939
+ revision += 1;
2940
+ break;
2941
+ case "tasks":
2942
+ validateEnvelopeFragment({ tasks: event.value });
2943
+ tasks = event.value;
2944
+ revision += 1;
2945
+ break;
2946
+ case "meta":
2947
+ validateEnvelopeFragment({
2948
+ owned: event.owned,
2949
+ commands: event.commands,
2950
+ ...event.repository === void 0 ? {} : { repository: event.repository },
2951
+ ...event.reviewComments === void 0 ? {} : { reviewComments: event.reviewComments }
2952
+ });
2953
+ owned = event.owned;
2954
+ commands = event.commands;
2955
+ repository = event.repository;
2956
+ reviewComments = event.reviewComments;
2957
+ revision += 1;
2958
+ break;
2959
+ default: return;
2960
+ }
2961
+ } catch {
2962
+ return;
2963
+ }
2964
+ schedulePublish();
2965
+ };
2966
+ const run = async () => {
2967
+ if (running) return;
2968
+ running = true;
2969
+ try {
2970
+ while (!disposed && listeners.size > 0) {
2971
+ controller = new AbortController();
2972
+ try {
2973
+ const response = await fetchProjection(`${CLAUDE_PROJECTION_PATH}/${encodeURIComponent(sessionId)}/stream`, {
2974
+ headers: { accept: "application/x-ndjson" },
2975
+ signal: controller.signal
2976
+ });
2977
+ if (!response.ok) throw new Error(`Claude projection stream failed (${response.status})`);
2978
+ if (response.body === null) throw new Error("Claude projection stream is unavailable");
2979
+ const reader = response.body.getReader();
2980
+ const decoder = new TextDecoder();
2981
+ let buffer = "";
2982
+ while (true) {
2983
+ if (disposed || listeners.size === 0) {
2984
+ await reader.cancel().catch(() => void 0);
2985
+ break;
2986
+ }
2987
+ const chunk = await reader.read();
2988
+ buffer += decoder.decode(chunk.value, { stream: !chunk.done });
2989
+ const lines = buffer.split("\n");
2990
+ buffer = lines.pop() ?? "";
2991
+ for (const line of lines) applyLine(line);
2992
+ if (chunk.done) break;
2993
+ }
2994
+ } catch (error) {
2995
+ if (isAbort(error)) return;
2996
+ } finally {
2997
+ controller = void 0;
2998
+ }
2999
+ if (disposed || listeners.size === 0) return;
3000
+ await delay(retryDelayMs);
3001
+ }
3002
+ } finally {
3003
+ running = false;
3004
+ }
3005
+ };
3006
+ return {
3007
+ getSnapshot: () => snapshot,
3008
+ subscribe(listener) {
3009
+ if (disposed) return () => {};
3010
+ const wasIdle = listeners.size === 0;
3011
+ listeners.add(listener);
3012
+ if (wasIdle) run();
3013
+ return () => {
3014
+ listeners.delete(listener);
3015
+ if (listeners.size !== 0) return;
3016
+ controller?.abort();
3017
+ controller = void 0;
3018
+ cancelFrame();
3019
+ };
3020
+ },
3021
+ dispose() {
3022
+ disposed = true;
3023
+ listeners.clear();
3024
+ controller?.abort();
3025
+ controller = void 0;
3026
+ cancelFrame();
3027
+ }
3028
+ };
3029
+ }
3030
+ var ClaudeProjectionStore = class {
3031
+ #sources = /* @__PURE__ */ new Map();
3032
+ source(sessionId) {
3033
+ let source = this.#sources.get(sessionId);
3034
+ if (source === void 0) {
3035
+ source = createClaudeProjectionSource(sessionId);
3036
+ this.#sources.set(sessionId, source);
3037
+ }
3038
+ return source;
3039
+ }
3040
+ dispose() {
3041
+ for (const source of this.#sources.values()) source.dispose();
3042
+ this.#sources.clear();
3043
+ }
3044
+ };
3045
+ //#endregion
2609
3046
  //#region src/client/ClaudeActivityNode.tsx
2610
3047
  const EMPTY_TASKS = [];
2611
3048
  const ACTIVITY_CSS = [
@@ -2613,8 +3050,8 @@ window.__ModuleLoader__.load({
2613
3050
  ".dsh-claude-transcript-text{color:var(--dsw-alias-label-primary);font-size:15px;line-height:24px;overflow-wrap:anywhere}",
2614
3051
  ".dsh-claude-tool-group-native{overflow:visible}",
2615
3052
  ".dsh-claude-tool-group-native>.dsh-claude-flow-row{padding:0}",
2616
- ".dsh-claude-tool-list{max-height:min(420px,calc(100vh - 320px));overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;margin-top:4px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;scrollbar-gutter:stable}",
2617
- ".dsh-claude-tool-item{border-top:1px solid var(--dsw-alias-border-l1)}",
3053
+ ".dsh-claude-tool-list{max-height:min(420px,calc(100vh - 320px));overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;margin-top:4px;border:1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent));border-radius:10px;scrollbar-gutter:stable}",
3054
+ ".dsh-claude-tool-item{border-top:1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent))}",
2618
3055
  ".dsh-claude-tool-item:first-child{border-top:0}",
2619
3056
  ".dsh-claude-tool-summary-row{display:flex;align-items:center;min-height:34px;gap:8px;padding:0 10px;cursor:pointer;list-style:none}",
2620
3057
  ".dsh-claude-tool-summary-row::-webkit-details-marker{display:none}",
@@ -2631,7 +3068,7 @@ window.__ModuleLoader__.load({
2631
3068
  ".dsh-claude-tool-path{overflow-wrap:anywhere;color:var(--dsw-alias-label-primary)}",
2632
3069
  ".dsh-claude-tool-code{max-height:260px;overflow:auto;margin:0;padding:8px 0;border-radius:8px;background:var(--dsw-alias-markdown-code-block);font:var(--dsw-font-markdown-code-block-small)}",
2633
3070
  ".dsh-claude-tool-code-line{display:grid;grid-template-columns:44px minmax(max-content,1fr);min-height:18px}",
2634
- ".dsh-claude-tool-line-number{padding-right:10px;text-align:right;user-select:none;color:var(--dsw-alias-label-caption);border-right:1px solid var(--dsw-alias-border-l1)}",
3071
+ ".dsh-claude-tool-line-number{padding-right:10px;text-align:right;user-select:none;color:var(--dsw-alias-label-caption);border-right:1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent))}",
2635
3072
  ".dsh-claude-tool-line-text{padding:0 10px;white-space:pre}",
2636
3073
  ".dsh-claude-tool-label{width:72px;flex:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}",
2637
3074
  ".dsh-claude-tool-description{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px;color:var(--dsw-alias-label-primary)}",
@@ -2649,7 +3086,7 @@ window.__ModuleLoader__.load({
2649
3086
  ".dsh-claude-flow-summary{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:24px;flex:auto}",
2650
3087
  ".dsh-claude-flow-summary[data-error]{color:var(--dsw-alias-state-error-primary)}",
2651
3088
  ".dsh-claude-flow-body{margin:4px 0 4px 22px;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:24px;white-space:pre-wrap;overflow-wrap:anywhere}",
2652
- ".dsh-claude-flow-detail{max-height:260px;overflow:auto;margin:4px 0 4px 4px;padding:12px 16px;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-markdown-code-block);color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap}",
3089
+ ".dsh-claude-flow-detail{max-height:260px;overflow:auto;margin:4px 0 4px 4px;padding:12px 16px;border:1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent));border-radius:12px;background:var(--dsw-alias-markdown-code-block);color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap}",
2653
3090
  ".dsh-claude-flow-subcalls{display:flex;flex-direction:column;gap:2px;margin:4px 0 4px 22px;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:22px}",
2654
3091
  ".dsh-claude-act-running{animation:dsh-claude-act-pulse 1.2s ease-in-out infinite}",
2655
3092
  "@keyframes dsh-claude-act-pulse{0%,100%{opacity:1}50%{opacity:.3}}"
@@ -2730,7 +3167,7 @@ window.__ModuleLoader__.load({
2730
3167
  return value;
2731
3168
  }
2732
3169
  }
2733
- function record$4(value) {
3170
+ function record$3(value) {
2734
3171
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2735
3172
  }
2736
3173
  function text(value) {
@@ -2744,7 +3181,7 @@ window.__ModuleLoader__.load({
2744
3181
  if (typeof value === "string") return value;
2745
3182
  if (typeof value === "number" || typeof value === "boolean") return String(value);
2746
3183
  if (Array.isArray(value)) return value.map(displayValue).join(", ");
2747
- return record$4(value) === void 0 ? String(value) : Object.entries(value).map(([key, item]) => `${key}: ${displayValue(item)}`).join("\n");
3184
+ return record$3(value) === void 0 ? String(value) : Object.entries(value).map(([key, item]) => `${key}: ${displayValue(item)}`).join("\n");
2748
3185
  }
2749
3186
  function Section({ title, children }) {
2750
3187
  return /* @__PURE__ */ jsxs("section", {
@@ -2814,15 +3251,15 @@ window.__ModuleLoader__.load({
2814
3251
  function ToolPresentation({ tool, t }) {
2815
3252
  const inputValue = parsedValue(tool.input);
2816
3253
  const outputValue = parsedValue(tool.output);
2817
- const input = record$4(inputValue);
2818
- const output = record$4(outputValue);
3254
+ const input = record$3(inputValue);
3255
+ const output = record$3(outputValue);
2819
3256
  const outputTitle = tool.isError === true ? t("toolError") : t("toolOutput");
2820
3257
  if (tool.diffs !== void 0) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(DiffBlock, { diffs: [...tool.diffs] }), /* @__PURE__ */ jsx(TextDetail, {
2821
3258
  title: outputTitle,
2822
3259
  value: typeof outputValue === "string" ? outputValue : void 0
2823
3260
  })] });
2824
3261
  if (tool.toolName === "Read") {
2825
- const file = record$4(output?.file);
3262
+ const file = record$3(output?.file);
2826
3263
  const path = text(file?.filePath) ?? text(input?.file_path);
2827
3264
  const content = text(file?.content) ?? (typeof outputValue === "string" ? outputValue : void 0);
2828
3265
  const offset = numberValue(input?.offset) ?? 1;
@@ -2984,7 +3421,7 @@ window.__ModuleLoader__.load({
2984
3421
  function ClaudeActivityNode({ node, useClaudeProjection, t }) {
2985
3422
  ensureCss();
2986
3423
  const marker = node.data;
2987
- const activities = useClaudeProjection((value) => value.activities);
3424
+ const activities = useClaudeProjection((value) => selectStepActivities(value, marker.turn, marker.step));
2988
3425
  const tasks = useClaudeProjection((value) => value.tasks?.tasks ?? EMPTY_TASKS);
2989
3426
  const items = useMemo(() => transcriptItemsForStep(activities, marker.turn, marker.step, tasks), [
2990
3427
  activities,
@@ -3515,32 +3952,110 @@ window.__ModuleLoader__.load({
3515
3952
  });
3516
3953
  }
3517
3954
  //#endregion
3518
- //#region src/client/ClaudeRepositoryStatus.tsx
3519
- const RATE_LIMIT_TITLE_PREFIX = "Claude rate limit";
3520
- const RATE_LIMIT_BLOCKING_TITLE = "Claude rate limit is blocking requests";
3521
- /** Whether the newest quota update in the activity feed reports a blocked state. */
3522
- function rateLimitBlocked(activities) {
3523
- for (let index = activities.length - 1; index >= 0; index -= 1) {
3524
- const title = activities[index]?.title;
3525
- if (title?.startsWith(RATE_LIMIT_TITLE_PREFIX) === true) return title === RATE_LIMIT_BLOCKING_TITLE;
3955
+ //#region src/client/repository-action-api.ts
3956
+ var RepositoryActionClientError = class extends Error {
3957
+ code;
3958
+ commit;
3959
+ constructor(message, code, commit) {
3960
+ super(message);
3961
+ this.name = "RepositoryActionClientError";
3962
+ if (code !== void 0) this.code = code;
3963
+ if (commit !== void 0) this.commit = commit;
3526
3964
  }
3527
- return false;
3528
- }
3529
- function StatusItem({ label, tone = "neutral" }) {
3530
- const toneStyle = tone === "success" ? repositoryItemSuccess : tone === "warning" ? repositoryItemWarning : tone === "error" ? repositoryItemError : {};
3531
- return /* @__PURE__ */ jsxs("span", {
3532
- style: {
3533
- ...repositoryItem,
3534
- ...toneStyle
3535
- },
3536
- children: [/* @__PURE__ */ jsx("span", {
3537
- style: repositoryItemDot,
3538
- "aria-hidden": "true"
3539
- }), label]
3540
- });
3965
+ };
3966
+ function record$2(value) {
3967
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3541
3968
  }
3542
- function PullRequestIcon({ size = 16, merged = false }) {
3543
- if (merged) return /* @__PURE__ */ jsxs("svg", {
3969
+ async function response$1(pending) {
3970
+ const result = await pending;
3971
+ const body = await result.json();
3972
+ if (!result.ok) {
3973
+ const error = record$2(body);
3974
+ throw new RepositoryActionClientError(typeof error?.message === "string" ? error.message : "Repository action failed.", typeof error?.error === "string" ? error.error : void 0, typeof error?.commit === "string" ? error.commit : void 0);
3975
+ }
3976
+ return body;
3977
+ }
3978
+ function preview(value) {
3979
+ const input = record$2(value);
3980
+ if (input === void 0 || typeof input.root !== "string" || typeof input.branch !== "string" || typeof input.head !== "string" || typeof input.fingerprint !== "string" || !Array.isArray(input.files) || typeof input.patch !== "string" || typeof input.truncated !== "boolean" || typeof input.hasStaged !== "boolean" || typeof input.hasUnstaged !== "boolean" || typeof input.hasUntracked !== "boolean" || input.upstream !== void 0 && typeof input.upstream !== "string" || !Array.isArray(input.unpushedCommits) || typeof input.unpushedTruncated !== "boolean") throw new Error("Invalid repository action preview.");
3981
+ for (const file of input.files) {
3982
+ const item = record$2(file);
3983
+ if (item === void 0 || typeof item.path !== "string" || typeof item.staged !== "boolean" || typeof item.unstaged !== "boolean" || typeof item.untracked !== "boolean") throw new Error("Invalid repository action file.");
3984
+ }
3985
+ for (const commit of input.unpushedCommits) {
3986
+ const item = record$2(commit);
3987
+ if (item === void 0 || typeof item.hash !== "string" || typeof item.subject !== "string") throw new Error("Invalid repository action commit.");
3988
+ }
3989
+ return input;
3990
+ }
3991
+ function result(value) {
3992
+ const input = record$2(value);
3993
+ if (input === void 0 || typeof input.commit !== "string" || typeof input.pushed !== "boolean" || input.pullRequestUrl !== void 0 && typeof input.pullRequestUrl !== "string") throw new Error("Invalid repository action result.");
3994
+ return input;
3995
+ }
3996
+ function endpoint(path, sessionId) {
3997
+ return `${CLAUDE_REPOSITORY_ACTION_PATH}${path}?sessionId=${encodeURIComponent(sessionId)}`;
3998
+ }
3999
+ async function loadRepositoryActionPreview(sessionId, signal) {
4000
+ return preview(await response$1(fetch(endpoint("/preview", sessionId), {
4001
+ method: "GET",
4002
+ credentials: "same-origin",
4003
+ headers: { accept: "application/json" },
4004
+ ...signal === void 0 ? {} : { signal }
4005
+ })));
4006
+ }
4007
+ async function generateCommitMessage(sessionId, fingerprint, signal) {
4008
+ const value = record$2(await response$1(fetch(endpoint("/message", sessionId), {
4009
+ method: "POST",
4010
+ credentials: "same-origin",
4011
+ headers: {
4012
+ accept: "application/json",
4013
+ "content-type": "application/json"
4014
+ },
4015
+ body: JSON.stringify({ fingerprint }),
4016
+ ...signal === void 0 ? {} : { signal }
4017
+ })));
4018
+ if (typeof value?.message !== "string") throw new Error("Invalid generated commit message.");
4019
+ return value.message;
4020
+ }
4021
+ function executeRepositoryAction(sessionId, request) {
4022
+ return response$1(fetch(endpoint("", sessionId), {
4023
+ method: "POST",
4024
+ credentials: "same-origin",
4025
+ headers: {
4026
+ accept: "application/json",
4027
+ "content-type": "application/json"
4028
+ },
4029
+ body: JSON.stringify(request)
4030
+ })).then(result);
4031
+ }
4032
+ //#endregion
4033
+ //#region src/client/ClaudeRepositoryStatus.tsx
4034
+ const RATE_LIMIT_TITLE_PREFIX = "Claude rate limit";
4035
+ const RATE_LIMIT_BLOCKING_TITLE = "Claude rate limit is blocking requests";
4036
+ /** Whether the newest quota update in the activity feed reports a blocked state. */
4037
+ function rateLimitBlocked(activities) {
4038
+ for (let index = activities.length - 1; index >= 0; index -= 1) {
4039
+ const title = activities[index]?.title;
4040
+ if (title?.startsWith(RATE_LIMIT_TITLE_PREFIX) === true) return title === RATE_LIMIT_BLOCKING_TITLE;
4041
+ }
4042
+ return false;
4043
+ }
4044
+ function StatusItem({ label, tone = "neutral" }) {
4045
+ const toneStyle = tone === "success" ? repositoryItemSuccess : tone === "warning" ? repositoryItemWarning : tone === "error" ? repositoryItemError : {};
4046
+ return /* @__PURE__ */ jsxs("span", {
4047
+ style: {
4048
+ ...repositoryItem,
4049
+ ...toneStyle
4050
+ },
4051
+ children: [/* @__PURE__ */ jsx("span", {
4052
+ style: repositoryItemDot,
4053
+ "aria-hidden": "true"
4054
+ }), label]
4055
+ });
4056
+ }
4057
+ function PullRequestIcon({ size = 16, merged = false }) {
4058
+ if (merged) return /* @__PURE__ */ jsxs("svg", {
3544
4059
  width: size,
3545
4060
  height: size,
3546
4061
  viewBox: "0 0 16 16",
@@ -3733,6 +4248,175 @@ window.__ModuleLoader__.load({
3733
4248
  })]
3734
4249
  });
3735
4250
  }
4251
+ const MERGE_METHODS = [
4252
+ "merge",
4253
+ "squash",
4254
+ "rebase"
4255
+ ];
4256
+ function MergePullRequestControl({ sessionId, repository, t }) {
4257
+ const [menuOpen, setMenuOpen] = useState(false);
4258
+ const [dialog, setDialog] = useState();
4259
+ const controller = useRef();
4260
+ const pullRequest = repository.pullRequest;
4261
+ useEffect(() => () => controller.current?.abort(), []);
4262
+ useEffect(() => {
4263
+ if (dialog?.merged !== true || dialog.error !== void 0) return;
4264
+ const timer = setTimeout(() => setDialog(void 0), 1200);
4265
+ return () => clearTimeout(timer);
4266
+ }, [dialog?.error, dialog?.merged]);
4267
+ if (pullRequest === void 0 || pullRequest.state !== "open" || pullRequest.draft || repository.detached === true) return null;
4268
+ const openMerge = (method) => {
4269
+ controller.current?.abort();
4270
+ setMenuOpen(false);
4271
+ setDialog({
4272
+ method,
4273
+ loading: true,
4274
+ submitting: false
4275
+ });
4276
+ const aborter = new AbortController();
4277
+ controller.current = aborter;
4278
+ loadRepositoryActionPreview(sessionId, aborter.signal).then((preview) => {
4279
+ setDialog({
4280
+ method,
4281
+ loading: false,
4282
+ submitting: false,
4283
+ fingerprint: preview.fingerprint
4284
+ });
4285
+ }, (error) => {
4286
+ if (!aborter.signal.aborted) setDialog({
4287
+ method,
4288
+ loading: false,
4289
+ submitting: false,
4290
+ error: error instanceof Error ? error.message : t("diffActionFailed")
4291
+ });
4292
+ });
4293
+ };
4294
+ const closeDialog = () => {
4295
+ if (dialog?.submitting === true) return;
4296
+ controller.current?.abort();
4297
+ controller.current = void 0;
4298
+ setDialog(void 0);
4299
+ };
4300
+ const confirmMerge = () => {
4301
+ if (dialog?.fingerprint === void 0 || dialog.submitting) return;
4302
+ const { error: _error, ...pending } = dialog;
4303
+ setDialog({
4304
+ ...pending,
4305
+ submitting: true
4306
+ });
4307
+ executeRepositoryAction(sessionId, {
4308
+ action: "merge-pr",
4309
+ fingerprint: dialog.fingerprint,
4310
+ message: "",
4311
+ includeUnstaged: false,
4312
+ mergeMethod: dialog.method
4313
+ }).then(() => {
4314
+ setDialog({
4315
+ ...pending,
4316
+ submitting: false,
4317
+ merged: true
4318
+ });
4319
+ }, (error) => {
4320
+ setDialog({
4321
+ ...pending,
4322
+ submitting: false,
4323
+ error: error instanceof Error ? error.message : t("diffActionFailed")
4324
+ });
4325
+ });
4326
+ };
4327
+ const items = MERGE_METHODS.map((method) => ({
4328
+ id: method,
4329
+ label: t(`diffMerge_${method}`)
4330
+ }));
4331
+ const merged = dialog?.merged === true;
4332
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
4333
+ /* @__PURE__ */ jsx(Menu, {
4334
+ open: menuOpen,
4335
+ items,
4336
+ onSelect: (id) => openMerge(id),
4337
+ onClose: () => setMenuOpen(false),
4338
+ align: "end",
4339
+ portal: true,
4340
+ anchor: /* @__PURE__ */ jsxs("button", {
4341
+ type: "button",
4342
+ style: repositoryMergeTrigger,
4343
+ "aria-label": t("repositoryMergeMenu"),
4344
+ "aria-haspopup": "menu",
4345
+ "aria-expanded": menuOpen,
4346
+ onClick: () => setMenuOpen((value) => !value),
4347
+ children: [t("diffMergePr"), /* @__PURE__ */ jsx(IconChevronDownOutline14, {})]
4348
+ })
4349
+ }),
4350
+ dialog === void 0 ? null : /* @__PURE__ */ jsx("style", {
4351
+ "data-dsh-claude-repository-modal-styles": true,
4352
+ children: diffModalCss
4353
+ }),
4354
+ /* @__PURE__ */ jsx(Modal, {
4355
+ className: "dshClaudeRepositoryActionModal",
4356
+ contentClassName: "dshClaudeRepositoryActionModalContent",
4357
+ open: dialog !== void 0,
4358
+ onClose: closeDialog,
4359
+ title: t("diffMergePr"),
4360
+ closeLabel: t("diffCancel"),
4361
+ description: t("diffMergeDescription"),
4362
+ footer: /* @__PURE__ */ jsxs("div", {
4363
+ style: diffModalFooter,
4364
+ children: [/* @__PURE__ */ jsx("button", {
4365
+ type: "button",
4366
+ style: {
4367
+ ...button,
4368
+ ...diffModalButton
4369
+ },
4370
+ disabled: dialog?.submitting === true,
4371
+ onClick: closeDialog,
4372
+ children: merged ? t("diffDone") : t("diffCancel")
4373
+ }), !merged ? /* @__PURE__ */ jsx("button", {
4374
+ type: "button",
4375
+ style: {
4376
+ ...primaryButton,
4377
+ ...diffModalButton
4378
+ },
4379
+ disabled: dialog?.loading === true || dialog?.submitting === true || dialog?.fingerprint === void 0,
4380
+ onClick: confirmMerge,
4381
+ children: dialog?.submitting === true ? t("diffSubmitting") : t("diffConfirm")
4382
+ }) : null]
4383
+ }),
4384
+ children: dialog === void 0 ? null : /* @__PURE__ */ jsxs("div", {
4385
+ style: diffModalBody,
4386
+ children: [
4387
+ /* @__PURE__ */ jsxs("div", {
4388
+ style: diffModalMeta,
4389
+ children: [/* @__PURE__ */ jsxs("strong", {
4390
+ style: diffModalMetaText,
4391
+ title: pullRequest.title,
4392
+ children: [
4393
+ t("repositoryPr", { number: pullRequest.number }),
4394
+ " → ",
4395
+ pullRequest.baseBranch ?? t("diffPrBaseDefault")
4396
+ ]
4397
+ }), /* @__PURE__ */ jsx("span", {
4398
+ style: diffModalFileState,
4399
+ children: t(`diffMerge_${dialog.method}`)
4400
+ })]
4401
+ }),
4402
+ /* @__PURE__ */ jsx("p", {
4403
+ style: diffModalStatus,
4404
+ children: pullRequest.title
4405
+ }),
4406
+ merged ? /* @__PURE__ */ jsx("p", {
4407
+ style: diffModalSuccess,
4408
+ children: t("diffMergeCompleted", { number: pullRequest.number })
4409
+ }) : null,
4410
+ dialog.error === void 0 ? null : /* @__PURE__ */ jsx("p", {
4411
+ role: "alert",
4412
+ style: diffModalError,
4413
+ children: dialog.error
4414
+ })
4415
+ ]
4416
+ })
4417
+ })
4418
+ ] });
4419
+ }
3736
4420
  function ClaudeRepositoryStatus({ sessionId, useSessions, useClaudeProjection, t, openDiff }) {
3737
4421
  const blank = useSessions((value) => value.byId[sessionId]?.blank === true);
3738
4422
  const projection = useClaudeProjection((value) => value);
@@ -3836,13 +4520,21 @@ window.__ModuleLoader__.load({
3836
4520
  children: ["· ", t("repositoryMergedAgo", { age: mergedAge })]
3837
4521
  })
3838
4522
  ]
3839
- }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(StatusItem, {
3840
- label: t(`repositoryChecks_${pullRequest.checks}`),
3841
- tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : pullRequest.checks === "pending" ? "warning" : "neutral"
3842
- }), /* @__PURE__ */ jsx(StatusItem, {
3843
- label: t(`repositoryReview_${pullRequest.review}`),
3844
- tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral"
3845
- })] })
4523
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
4524
+ /* @__PURE__ */ jsx(StatusItem, {
4525
+ label: t(`repositoryChecks_${pullRequest.checks}`),
4526
+ tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : pullRequest.checks === "pending" ? "warning" : "neutral"
4527
+ }),
4528
+ /* @__PURE__ */ jsx(StatusItem, {
4529
+ label: t(`repositoryReview_${pullRequest.review}`),
4530
+ tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral"
4531
+ }),
4532
+ /* @__PURE__ */ jsx(MergePullRequestControl, {
4533
+ sessionId,
4534
+ repository,
4535
+ t
4536
+ })
4537
+ ] })
3846
4538
  ]
3847
4539
  })
3848
4540
  ]
@@ -3851,7 +4543,7 @@ window.__ModuleLoader__.load({
3851
4543
  }
3852
4544
  //#endregion
3853
4545
  //#region src/client/review-comment-api.ts
3854
- function record$3(value) {
4546
+ function record$1(value) {
3855
4547
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3856
4548
  }
3857
4549
  async function post(path, sessionId, body) {
@@ -3866,13 +4558,13 @@ window.__ModuleLoader__.load({
3866
4558
  });
3867
4559
  const value = await response.json();
3868
4560
  if (!response.ok) {
3869
- const error = record$3(value);
4561
+ const error = record$1(value);
3870
4562
  throw new Error(typeof error?.message === "string" ? error.message : "Review comment request failed.");
3871
4563
  }
3872
4564
  return value;
3873
4565
  }
3874
4566
  async function addReviewComment(sessionId, comment) {
3875
- const created = record$3(record$3(await post("", sessionId, comment))?.comment);
4567
+ const created = record$1(record$1(await post("", sessionId, comment))?.comment);
3876
4568
  if (created === void 0 || typeof created.id !== "string") throw new Error("Invalid review comment response.");
3877
4569
  return created;
3878
4570
  }
@@ -4026,84 +4718,6 @@ window.__ModuleLoader__.load({
4026
4718
  });
4027
4719
  }
4028
4720
  //#endregion
4029
- //#region src/client/repository-action-api.ts
4030
- var RepositoryActionClientError = class extends Error {
4031
- code;
4032
- commit;
4033
- constructor(message, code, commit) {
4034
- super(message);
4035
- this.name = "RepositoryActionClientError";
4036
- if (code !== void 0) this.code = code;
4037
- if (commit !== void 0) this.commit = commit;
4038
- }
4039
- };
4040
- function record$2(value) {
4041
- return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
4042
- }
4043
- async function response$1(pending) {
4044
- const result = await pending;
4045
- const body = await result.json();
4046
- if (!result.ok) {
4047
- const error = record$2(body);
4048
- throw new RepositoryActionClientError(typeof error?.message === "string" ? error.message : "Repository action failed.", typeof error?.error === "string" ? error.error : void 0, typeof error?.commit === "string" ? error.commit : void 0);
4049
- }
4050
- return body;
4051
- }
4052
- function preview(value) {
4053
- const input = record$2(value);
4054
- if (input === void 0 || typeof input.root !== "string" || typeof input.branch !== "string" || typeof input.head !== "string" || typeof input.fingerprint !== "string" || !Array.isArray(input.files) || typeof input.patch !== "string" || typeof input.truncated !== "boolean" || typeof input.hasStaged !== "boolean" || typeof input.hasUnstaged !== "boolean" || typeof input.hasUntracked !== "boolean" || input.upstream !== void 0 && typeof input.upstream !== "string" || !Array.isArray(input.unpushedCommits) || typeof input.unpushedTruncated !== "boolean") throw new Error("Invalid repository action preview.");
4055
- for (const file of input.files) {
4056
- const item = record$2(file);
4057
- if (item === void 0 || typeof item.path !== "string" || typeof item.staged !== "boolean" || typeof item.unstaged !== "boolean" || typeof item.untracked !== "boolean") throw new Error("Invalid repository action file.");
4058
- }
4059
- for (const commit of input.unpushedCommits) {
4060
- const item = record$2(commit);
4061
- if (item === void 0 || typeof item.hash !== "string" || typeof item.subject !== "string") throw new Error("Invalid repository action commit.");
4062
- }
4063
- return input;
4064
- }
4065
- function result(value) {
4066
- const input = record$2(value);
4067
- if (input === void 0 || typeof input.commit !== "string" || typeof input.pushed !== "boolean" || input.pullRequestUrl !== void 0 && typeof input.pullRequestUrl !== "string") throw new Error("Invalid repository action result.");
4068
- return input;
4069
- }
4070
- function endpoint(path, sessionId) {
4071
- return `${CLAUDE_REPOSITORY_ACTION_PATH}${path}?sessionId=${encodeURIComponent(sessionId)}`;
4072
- }
4073
- async function loadRepositoryActionPreview(sessionId, signal) {
4074
- return preview(await response$1(fetch(endpoint("/preview", sessionId), {
4075
- method: "GET",
4076
- credentials: "same-origin",
4077
- headers: { accept: "application/json" },
4078
- ...signal === void 0 ? {} : { signal }
4079
- })));
4080
- }
4081
- async function generateCommitMessage(sessionId, fingerprint, signal) {
4082
- const value = record$2(await response$1(fetch(endpoint("/message", sessionId), {
4083
- method: "POST",
4084
- credentials: "same-origin",
4085
- headers: {
4086
- accept: "application/json",
4087
- "content-type": "application/json"
4088
- },
4089
- body: JSON.stringify({ fingerprint }),
4090
- ...signal === void 0 ? {} : { signal }
4091
- })));
4092
- if (typeof value?.message !== "string") throw new Error("Invalid generated commit message.");
4093
- return value.message;
4094
- }
4095
- function executeRepositoryAction(sessionId, request) {
4096
- return response$1(fetch(endpoint("", sessionId), {
4097
- method: "POST",
4098
- credentials: "same-origin",
4099
- headers: {
4100
- accept: "application/json",
4101
- "content-type": "application/json"
4102
- },
4103
- body: JSON.stringify(request)
4104
- })).then(result);
4105
- }
4106
- //#endregion
4107
4721
  //#region src/client/ClaudeDiffPanel.tsx
4108
4722
  function pathFromHeader(line) {
4109
4723
  return /^diff --git a\/(.+) b\/(.+)$/u.exec(line)?.[2];
@@ -4290,7 +4904,7 @@ window.__ModuleLoader__.load({
4290
4904
  });
4291
4905
  }
4292
4906
  function actionLabel(action, t) {
4293
- return (action === "commit" ? t("diffCommit") : action === "commit-push" ? t("diffCommitPush") : action === "push" ? t("diffPush") : t("diffCreatePr")).replace(/[….]+$/u, "");
4907
+ return (action === "commit" ? t("diffCommit") : action === "commit-push" ? t("diffCommitPush") : action === "push" ? t("diffPush") : action === "merge-pr" ? t("diffMergePr") : t("diffCreatePr")).replace(/[….]+$/u, "");
4294
4908
  }
4295
4909
  function repositoryActionAvailability(repository) {
4296
4910
  const ready = repository?.status === "ready" && repository.detached !== true;
@@ -4302,7 +4916,8 @@ window.__ModuleLoader__.load({
4302
4916
  "commit": committable,
4303
4917
  "commit-push": committable && hasRemote,
4304
4918
  "push": pushable,
4305
- "create-pr": (committable || pushable) && hasRemote && !hasOpenPullRequest
4919
+ "create-pr": (committable || pushable) && hasRemote && !hasOpenPullRequest,
4920
+ "merge-pr": ready && hasOpenPullRequest && repository?.pullRequest?.draft !== true
4306
4921
  };
4307
4922
  }
4308
4923
  function RestorePanelIcon() {
@@ -5019,16 +5634,16 @@ window.__ModuleLoader__.load({
5019
5634
  "saving-worktree",
5020
5635
  "switching-branch"
5021
5636
  ]);
5022
- function record$1(value) {
5637
+ function record(value) {
5023
5638
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
5024
5639
  }
5025
5640
  function setupResult(value) {
5026
- const item = record$1(value);
5641
+ const item = record(value);
5027
5642
  if (item === void 0 || item.mode !== "checkout" && item.mode !== "worktree" || typeof item.root !== "string" || typeof item.path !== "string" || typeof item.branch !== "string" || item.leaseId !== void 0 && typeof item.leaseId !== "string") return void 0;
5028
5643
  return item;
5029
5644
  }
5030
5645
  function parseRepositorySetupEvent(line, onProgress) {
5031
- const event = record$1(JSON.parse(line));
5646
+ const event = record(JSON.parse(line));
5032
5647
  if (event?.type === "progress" && typeof event.stage === "string" && HOST_STAGES.has(event.stage)) {
5033
5648
  onProgress(event.stage);
5034
5649
  return;
@@ -5572,170 +6187,6 @@ window.__ModuleLoader__.load({
5572
6187
  }), portal);
5573
6188
  }
5574
6189
  //#endregion
5575
- //#region src/client/projection.ts
5576
- const EMPTY_CLAUDE_PROJECTION = {
5577
- schemaVersion: 1,
5578
- revision: 0,
5579
- owned: false,
5580
- commands: [],
5581
- activities: []
5582
- };
5583
- const POLL_INTERVAL_MS = 2e3;
5584
- const MAX_ACTIVITIES = 1e4;
5585
- const MAX_COMMANDS = 2e3;
5586
- const MAX_REPOSITORY_TEXT_CHARS = 1024;
5587
- const MAX_DIFF_CHARS = 262144;
5588
- const MAX_REVIEW_COMMENTS = 50;
5589
- const MAX_REVIEW_COMMENT_CHARS = 2e3;
5590
- function record(value) {
5591
- return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
5592
- }
5593
- function nonNegativeInteger(value) {
5594
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
5595
- }
5596
- function optionalBoundedString(value) {
5597
- return value === void 0 || typeof value === "string" && value.length <= MAX_REPOSITORY_TEXT_CHARS;
5598
- }
5599
- function validateRepository(value) {
5600
- const repository = record(value);
5601
- if (repository === void 0 || ![
5602
- "ready",
5603
- "not-repository",
5604
- "unavailable"
5605
- ].includes(String(repository.status)) || typeof repository.cwd !== "string" || repository.cwd.length > MAX_REPOSITORY_TEXT_CHARS || !optionalBoundedString(repository.root) || !optionalBoundedString(repository.branch) || !optionalBoundedString(repository.remote) || repository.detached !== void 0 && typeof repository.detached !== "boolean" || repository.worktree !== void 0 && typeof repository.worktree !== "boolean" || repository.dirty !== void 0 && typeof repository.dirty !== "boolean" || repository.upstream !== void 0 && typeof repository.upstream !== "boolean" || repository.ahead !== void 0 && !nonNegativeInteger(repository.ahead) || repository.behind !== void 0 && !nonNegativeInteger(repository.behind)) return false;
5606
- if (repository.diff !== void 0) {
5607
- const diff = record(repository.diff);
5608
- if (diff === void 0 || !nonNegativeInteger(diff.additions) || !nonNegativeInteger(diff.deletions) || !nonNegativeInteger(diff.files) || typeof diff.truncated !== "boolean" || diff.patch !== void 0 && (typeof diff.patch !== "string" || diff.patch.length > MAX_DIFF_CHARS)) return false;
5609
- }
5610
- if (repository.pullRequest === void 0) return true;
5611
- const pullRequest = record(repository.pullRequest);
5612
- if (pullRequest === void 0 || !Number.isSafeInteger(pullRequest.number) || Number(pullRequest.number) <= 0 || typeof pullRequest.title !== "string" || pullRequest.title.length > MAX_REPOSITORY_TEXT_CHARS || typeof pullRequest.url !== "string" || pullRequest.url.length > MAX_REPOSITORY_TEXT_CHARS || ![
5613
- "open",
5614
- "closed",
5615
- "merged"
5616
- ].includes(String(pullRequest.state)) || typeof pullRequest.draft !== "boolean" || ![
5617
- "approved",
5618
- "changes-requested",
5619
- "review-required",
5620
- "none"
5621
- ].includes(String(pullRequest.review)) || ![
5622
- "passing",
5623
- "pending",
5624
- "failing",
5625
- "none"
5626
- ].includes(String(pullRequest.checks)) || !optionalBoundedString(pullRequest.mergeState) || !optionalBoundedString(pullRequest.author) || !optionalBoundedString(pullRequest.baseBranch) || pullRequest.createdAt !== void 0 && (typeof pullRequest.createdAt !== "string" || !Number.isFinite(Date.parse(pullRequest.createdAt))) || pullRequest.mergedAt !== void 0 && (typeof pullRequest.mergedAt !== "string" || !Number.isFinite(Date.parse(pullRequest.mergedAt)))) return false;
5627
- try {
5628
- const url = new URL(pullRequest.url);
5629
- return url.protocol === "https:" && url.hostname === "github.com";
5630
- } catch {
5631
- return false;
5632
- }
5633
- }
5634
- /** Validate the public route envelope before publishing it to UI components. */
5635
- function parseClaudeClientProjection(value) {
5636
- const input = record(value);
5637
- if (input === void 0 || input.schemaVersion !== 1 || !nonNegativeInteger(input.revision) || typeof input.owned !== "boolean" || !Array.isArray(input.commands) || input.commands.length > MAX_COMMANDS || !Array.isArray(input.activities) || input.activities.length > MAX_ACTIVITIES) throw new Error("invalid Claude sidecar projection");
5638
- for (const item of input.commands) {
5639
- const command = record(item);
5640
- if (command === void 0 || typeof command.publicName !== "string" || typeof command.claudeName !== "string" || typeof command.description !== "string" || command.hint !== void 0 && typeof command.hint !== "string" || typeof command.prefixed !== "boolean") throw new Error("invalid Claude command projection");
5641
- }
5642
- for (const item of input.activities) {
5643
- const activity = record(item);
5644
- if (activity === void 0 || !nonNegativeInteger(activity.turn) || !nonNegativeInteger(activity.step) || !nonNegativeInteger(activity.ordinal) || typeof activity.kind !== "string") throw new Error("invalid Claude sidecar activity");
5645
- }
5646
- if (input.contextUsage !== void 0 && record(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
5647
- const tasks = input.tasks === void 0 ? void 0 : record(input.tasks);
5648
- if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
5649
- if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
5650
- if (input.reviewComments !== void 0) {
5651
- if (!Array.isArray(input.reviewComments) || input.reviewComments.length > MAX_REVIEW_COMMENTS) throw new Error("invalid Claude review comment projection");
5652
- for (const item of input.reviewComments) {
5653
- const comment = record(item);
5654
- if (comment === void 0 || typeof comment.id !== "string" || comment.id.length === 0 || comment.id.length > 128 || typeof comment.path !== "string" || comment.path.length === 0 || comment.path.length > MAX_REPOSITORY_TEXT_CHARS || !nonNegativeInteger(comment.line) || comment.side !== "old" && comment.side !== "new" || typeof comment.text !== "string" || comment.text.length > MAX_REVIEW_COMMENT_CHARS) throw new Error("invalid Claude review comment projection");
5655
- }
5656
- }
5657
- return input;
5658
- }
5659
- /** Create one lazy source: active subscribers trigger an immediate load and bounded polling. */
5660
- function createClaudeProjectionSource(sessionId, fetchProjection = fetch, pollIntervalMs = POLL_INTERVAL_MS) {
5661
- let snapshot = EMPTY_CLAUDE_PROJECTION;
5662
- let timer;
5663
- let controller;
5664
- let disposed = false;
5665
- const listeners = /* @__PURE__ */ new Set();
5666
- const schedule = () => {
5667
- if (disposed || listeners.size === 0) return;
5668
- timer = setTimeout(() => {
5669
- refresh();
5670
- }, pollIntervalMs);
5671
- };
5672
- const refresh = async () => {
5673
- if (disposed || listeners.size === 0) return;
5674
- controller?.abort();
5675
- controller = new AbortController();
5676
- try {
5677
- const response = await fetchProjection(`${CLAUDE_PROJECTION_PATH}/${encodeURIComponent(sessionId)}`, {
5678
- headers: { accept: "application/json" },
5679
- signal: controller.signal
5680
- });
5681
- if (!response.ok) throw new Error(`Claude projection request failed (${response.status})`);
5682
- const next = parseClaudeClientProjection(await response.json());
5683
- const commandCatalogChanged = JSON.stringify(next.commands) !== JSON.stringify(snapshot.commands);
5684
- const repositoryChanged = JSON.stringify(next.repository) !== JSON.stringify(snapshot.repository);
5685
- const reviewCommentsChanged = JSON.stringify(next.reviewComments) !== JSON.stringify(snapshot.reviewComments);
5686
- if (next.revision !== snapshot.revision || next.owned !== snapshot.owned || commandCatalogChanged || repositoryChanged || reviewCommentsChanged) {
5687
- snapshot = next;
5688
- for (const listener of [...listeners]) listener();
5689
- }
5690
- } catch (error) {
5691
- if (error instanceof DOMException && error.name === "AbortError") return;
5692
- } finally {
5693
- controller = void 0;
5694
- schedule();
5695
- }
5696
- };
5697
- return {
5698
- getSnapshot: () => snapshot,
5699
- subscribe(listener) {
5700
- if (disposed) return () => {};
5701
- const wasIdle = listeners.size === 0;
5702
- listeners.add(listener);
5703
- if (wasIdle) refresh();
5704
- return () => {
5705
- listeners.delete(listener);
5706
- if (listeners.size !== 0) return;
5707
- if (timer !== void 0) clearTimeout(timer);
5708
- timer = void 0;
5709
- controller?.abort();
5710
- controller = void 0;
5711
- };
5712
- },
5713
- dispose() {
5714
- disposed = true;
5715
- listeners.clear();
5716
- if (timer !== void 0) clearTimeout(timer);
5717
- timer = void 0;
5718
- controller?.abort();
5719
- controller = void 0;
5720
- }
5721
- };
5722
- }
5723
- var ClaudeProjectionStore = class {
5724
- #sources = /* @__PURE__ */ new Map();
5725
- source(sessionId) {
5726
- let source = this.#sources.get(sessionId);
5727
- if (source === void 0) {
5728
- source = createClaudeProjectionSource(sessionId);
5729
- this.#sources.set(sessionId, source);
5730
- }
5731
- return source;
5732
- }
5733
- dispose() {
5734
- for (const source of this.#sources.values()) source.dispose();
5735
- this.#sources.clear();
5736
- }
5737
- };
5738
- //#endregion
5739
6190
  //#region src/client/claude-command-source.ts
5740
6191
  const SOURCE_NAME = "Claude Code";
5741
6192
  function commandsFor(store, session) {
@@ -6173,6 +6624,13 @@ window.__ModuleLoader__.load({
6173
6624
  diffCommitCompleted: "已创建 commit {commit}",
6174
6625
  diffCommitPreserved: "本地 commit {commit} 已保留。",
6175
6626
  diffOpenPr: "打开 Pull Request",
6627
+ diffMergePr: "Merge",
6628
+ repositoryMergeMenu: "打开 PR 合并选项",
6629
+ diffMerge_merge: "合并提交 (merge)",
6630
+ diffMerge_squash: "Squash 合并",
6631
+ diffMerge_rebase: "Rebase 合并",
6632
+ diffMergeDescription: "使用所选方式合并当前分支的 Pull Request。",
6633
+ diffMergeCompleted: "已合并 PR #{number}",
6176
6634
  reviewCommentAdd: "添加行评论",
6177
6635
  reviewCommentPlaceholder: "请求更改",
6178
6636
  reviewCommentSubmit: "注释",
@@ -6375,6 +6833,13 @@ window.__ModuleLoader__.load({
6375
6833
  diffCommitCompleted: "Created commit {commit}",
6376
6834
  diffCommitPreserved: "Local commit {commit} was preserved.",
6377
6835
  diffOpenPr: "Open pull request",
6836
+ diffMergePr: "Merge",
6837
+ repositoryMergeMenu: "Open merge options",
6838
+ diffMerge_merge: "Create a merge commit",
6839
+ diffMerge_squash: "Squash and merge",
6840
+ diffMerge_rebase: "Rebase and merge",
6841
+ diffMergeDescription: "Merge the pull request for this branch with the selected method.",
6842
+ diffMergeCompleted: "Merged PR #{number}",
6378
6843
  reviewCommentAdd: "Add line comment",
6379
6844
  reviewCommentPlaceholder: "Request changes",
6380
6845
  reviewCommentSubmit: "Comment",