dsh-easygit-plugin 0.2.2 → 0.2.3

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/README.md CHANGED
@@ -121,7 +121,7 @@ Please report vulnerabilities privately by following [SECURITY.md](SECURITY.md).
121
121
 
122
122
  ## Compatibility
123
123
 
124
- Last verified on **2026-08-20** with DeepSeek Harness `0.1.0-rc.8` and dsh-easygit-plugin `0.2.1`. Verification covered `npm run check` (68 tests), 24 reproducible build artifacts, a dry-run npm package, a temporary DSH Web-profile composition, and end-to-end Git operations against a temporary local copy of the FastAPI repository. The end-to-end coverage includes repository inspection, diffs, commits, branches, stashes, fetch/pull/push, successful and conflicted Rebases, recovery behavior, and proposal safety checks.
124
+ Last verified on **2026-08-20** with DeepSeek Harness `0.1.0-rc.8` and dsh-easygit-plugin `0.2.3`. Verification covered `npm run check` (68 tests), 24 reproducible build artifacts, a dry-run npm package, a temporary DSH Web-profile composition, and end-to-end Git operations against a temporary local copy of the FastAPI repository. The end-to-end coverage includes repository inspection, diffs, commits, branches, stashes, fetch/pull/push, successful and conflicted Rebases, recovery behavior, and proposal safety checks.
125
125
 
126
126
  ## Development
127
127
 
package/README.zh-CN.md CHANGED
@@ -121,7 +121,7 @@ Web profile 会在输入框旁添加 Git 操作入口,并在原生详情区域
121
121
 
122
122
  ## 兼容性
123
123
 
124
- 最后于 **2026-08-20** 使用 DeepSeek Harness `0.1.0-rc.8` 和 dsh-easygit-plugin `0.2.1` 完成验证。验证范围包括 `npm run check`(68 项测试)、24 个可重复构建产物、npm 发布包 dry-run、临时 DSH Web profile 组合,以及基于 FastAPI 仓库临时本地副本的端到端 Git 操作。端到端范围包括仓库读取、Diff、提交、分支、贮藏、fetch/pull/push、成功与冲突 Rebase、修正建议和提议安全校验。
124
+ 最后于 **2026-08-20** 使用 DeepSeek Harness `0.1.0-rc.8` 和 dsh-easygit-plugin `0.2.3` 完成验证。验证范围包括 `npm run check`(68 项测试)、24 个可重复构建产物、npm 发布包 dry-run、临时 DSH Web profile 组合,以及基于 FastAPI 仓库临时本地副本的端到端 Git 操作。端到端范围包括仓库读取、Diff、提交、分支、贮藏、fetch/pull/push、成功与冲突 Rebase、修正建议和提议安全校验。
125
125
 
126
126
  ## 开发
127
127
 
Binary file
package/lib/client.js CHANGED
@@ -644,6 +644,306 @@ function injectStyles() {
644
644
  .gg-change-layout { display: grid; grid-template-columns: minmax(175px, 38%) minmax(0, 1fr); align-items: stretch; }
645
645
  .gg-diff { min-height: 0; }
646
646
  }
647
+
648
+ /* EasyGit visual foundation: dense developer tooling, aligned with the host UI. */
649
+ .gg-workbench {
650
+ --gg-bg: var(--dsw-alias-bg-base, #f7f7f8);
651
+ --gg-surface: var(--dsw-alias-bg-layer-1, #fff);
652
+ --gg-surface-raised: var(--dsw-alias-bg-layer-2, #f1f2f3);
653
+ --gg-surface-inset: var(--dsw-alias-markdown-code-block, var(--gg-surface-raised));
654
+ --gg-border: var(--dsw-alias-border-l2, rgba(15, 17, 21, .12));
655
+ --gg-border-strong: var(--dsw-alias-border-l3, rgba(15, 17, 21, .18));
656
+ --gg-text: var(--dsw-alias-label-primary, #0f1115);
657
+ --gg-text-secondary: var(--dsw-alias-label-secondary, #353638);
658
+ --gg-text-muted: var(--dsw-alias-label-tertiary, #666a70);
659
+ --gg-text-caption: var(--dsw-alias-label-caption, #81858c);
660
+ --gg-accent: var(--dsw-alias-state-business-primary, #3964fe);
661
+ --gg-accent-strong: var(--dsw-alias-state-business-primary, #3964fe);
662
+ --gg-accent-soft: color-mix(in srgb, var(--gg-accent) 14%, transparent);
663
+ --gg-success: var(--dsw-alias-state-success-primary, #169c46);
664
+ --gg-success-label: color-mix(in srgb, var(--gg-success) 64%, var(--gg-text));
665
+ --gg-warning: var(--dsw-alias-state-warn-primary, #b66a00);
666
+ --gg-warning-label: var(--dsw-alias-state-warn-label, #9d5d00);
667
+ --gg-danger: var(--dsw-alias-state-error-primary, #d13f3f);
668
+ --gg-danger-label: color-mix(in srgb, var(--gg-danger) 82%, var(--gg-text));
669
+ --gg-text-subtle: color-mix(in srgb, var(--gg-text-muted) 72%, var(--gg-text));
670
+ --gg-radius: 8px;
671
+ --gg-radius-control: 6px;
672
+ --gg-focus: 0 0 0 2px color-mix(in srgb, var(--gg-accent) 28%, transparent);
673
+ container-name: easygit-workbench;
674
+ container-type: inline-size;
675
+ border-left-color: var(--gg-border-strong);
676
+ color: var(--gg-text);
677
+ background: var(--gg-bg);
678
+ box-shadow: var(--dsw-shadow-lv1, -12px 0 32px rgba(0, 0, 0, .12));
679
+ font-family: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif);
680
+ font-size: 13px;
681
+ line-height: 1.5;
682
+ color-scheme: inherit;
683
+ }
684
+ .gg-workbench *, .gg-dock * { box-sizing: border-box; }
685
+ .gg-workbench code, .gg-workbench pre, .gg-dock code, .gg-dock pre,
686
+ .gg-command-code, .gg-review, .gg-diff-code, .gg-stepcode {
687
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
688
+ }
689
+ .gg-workbench ::selection, .gg-dock ::selection { color: var(--gg-text, #0f1115); background: color-mix(in srgb, var(--gg-accent, #3964fe) 28%, transparent); }
690
+ .gg-workbench ::-webkit-scrollbar { width: 9px; height: 9px; }
691
+ .gg-workbench ::-webkit-scrollbar-track { background: transparent; }
692
+ .gg-workbench ::-webkit-scrollbar-thumb { border: 3px solid transparent; border-radius: 999px; background: var(--dsw-alias-scrollbar-bg-l2, var(--gg-border-strong)); background-clip: padding-box; }
693
+ .gg-workbench ::-webkit-scrollbar-thumb:hover { background: var(--dsw-alias-scrollbar-hover-l2, var(--gg-text-caption)); background-clip: padding-box; }
694
+
695
+ .gg-workbench-head {
696
+ min-height: 74px;
697
+ padding: 14px 16px;
698
+ border-bottom-color: var(--gg-border);
699
+ background: var(--gg-bg);
700
+ }
701
+ .gg-workbench-title { color: var(--gg-text); font-size: 16px; line-height: 22px; font-weight: 650; letter-spacing: -.015em; }
702
+ .gg-workbench-close {
703
+ width: 32px;
704
+ height: 32px;
705
+ border-radius: var(--gg-radius-control);
706
+ color: var(--gg-text-muted);
707
+ font-size: 21px;
708
+ line-height: 1;
709
+ transition: color 120ms ease, background-color 120ms ease, transform 120ms ease;
710
+ }
711
+ .gg-workbench-close:hover:not(:disabled) { color: var(--gg-text); background: var(--gg-surface-raised); }
712
+ .gg-workbench-close:active:not(:disabled) { transform: translateY(1px); }
713
+ .gg-workbench-body { padding: 0 12px 12px; }
714
+ .gg-workbench-resize::after { left: 5px; width: 1px; background: var(--gg-border-strong); }
715
+ .gg-workbench-resize:hover::after, .gg-workbench-resize:focus-visible::after, .gg-workbench-resize.dragging::after {
716
+ background: var(--gg-accent);
717
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--gg-accent) 18%, transparent);
718
+ }
719
+ .gg-workbench-resize:focus-visible { outline-color: var(--gg-accent); }
720
+
721
+ .gg-tabs {
722
+ position: sticky;
723
+ top: 0;
724
+ z-index: 2;
725
+ gap: 2px;
726
+ overflow-x: auto;
727
+ margin: 0 -12px;
728
+ padding: 8px 12px 0;
729
+ border-bottom-color: var(--gg-border);
730
+ background: var(--gg-bg);
731
+ scrollbar-width: none;
732
+ }
733
+ .gg-tabs::-webkit-scrollbar { display: none; }
734
+ .gg-tab {
735
+ min-height: 34px;
736
+ border: 0;
737
+ border-bottom: 2px solid transparent;
738
+ border-radius: 0;
739
+ padding: 6px 9px 7px;
740
+ color: var(--gg-text-muted);
741
+ font-size: 12.5px;
742
+ font-weight: 500;
743
+ transition: color 120ms ease, background-color 120ms ease, border-color 120ms ease;
744
+ }
745
+ .gg-tab:hover:not(:disabled) { color: var(--gg-text-secondary); background: var(--dsw-alias-interactive-bg-hover, var(--gg-accent-soft)); }
746
+ .gg-tab.active { border-color: var(--gg-accent); color: var(--gg-text); background: transparent; font-weight: 650; }
747
+ .gg-tab:focus-visible { outline: 2px solid var(--gg-accent); outline-offset: -3px; }
748
+ .gg-tab:active:not(:disabled) { transform: translateY(1px); }
749
+ .gg-tab-content { gap: 12px; padding-top: 12px; }
750
+ .gg-tab-panel { min-height: 0; }
751
+ .gg-tab-toolbar { min-height: 34px; gap: 8px; }
752
+ .gg-tab-toolbar > .gg-idletext:first-child, .gg-repository-identity { margin-right: auto; }
753
+ .gg-section-heading { margin-right: auto; color: var(--gg-text); font-size: 14px; line-height: 22px; font-weight: 680; letter-spacing: -.01em; }
754
+ .gg-section-count { display: inline-grid; min-width: 21px; height: 21px; margin-left: 7px; place-items: center; border-radius: 999px; padding: 0 6px; color: var(--gg-text-secondary); background: var(--gg-surface-raised); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 11px; line-height: 21px; font-weight: 650; }
755
+ .gg-repository-identity { display: flex; min-width: 0; align-items: center; gap: 8px; padding: 2px 0; }
756
+ .gg-repository-name { min-width: 0; overflow: hidden; color: var(--gg-text); font-size: 16px; line-height: 24px; font-weight: 680; letter-spacing: -.015em; text-overflow: ellipsis; white-space: nowrap; }
757
+ .gg-repository-arrow { flex: none; color: var(--gg-text-caption); font-size: 13px; }
758
+ .gg-repository-branch { min-width: 0; overflow: hidden; border-radius: 5px; padding: 2px 6px; color: var(--gg-accent); background: var(--gg-accent-soft); font-size: 13px; line-height: 20px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
759
+
760
+ .gg-btn {
761
+ min-height: 30px;
762
+ border-color: var(--gg-border-strong);
763
+ border-radius: var(--gg-radius-control);
764
+ padding: 5px 10px;
765
+ color: var(--gg-text-secondary);
766
+ background: var(--gg-surface);
767
+ font-family: inherit;
768
+ font-size: 12px;
769
+ line-height: 18px;
770
+ font-weight: 550;
771
+ white-space: nowrap;
772
+ transition: color 120ms ease, border-color 120ms ease, background-color 120ms ease, transform 120ms ease;
773
+ }
774
+ .gg-btn:hover:not(:disabled) { border-color: var(--gg-border-strong); color: var(--gg-text); background: var(--dsw-alias-interactive-bg-hover, var(--gg-surface-raised)); }
775
+ .gg-btn:focus-visible { outline: none; box-shadow: var(--gg-focus); }
776
+ .gg-btn:active:not(:disabled) { transform: translateY(1px); }
777
+ .gg-btn:disabled { opacity: .42; }
778
+ .gg-btn.primary {
779
+ border-color: var(--dsw-alias-button-primary-fill, var(--gg-accent));
780
+ color: var(--dsw-alias-label-primary-foreground, #fff);
781
+ background: var(--dsw-alias-button-primary-fill, var(--gg-accent));
782
+ }
783
+ .gg-btn.primary:hover:not(:disabled) { border-color: var(--dsw-alias-button-primary-hover, var(--gg-accent-strong)); color: var(--dsw-alias-label-primary-foreground, #fff); background: var(--dsw-alias-button-primary-hover, var(--gg-accent-strong)); }
784
+ .gg-btn.danger { border-color: var(--gg-danger); color: var(--dsw-alias-label-primary-foreground, #fff); background: var(--gg-danger); }
785
+ .gg-btn.danger:hover:not(:disabled) { border-color: var(--gg-danger); color: var(--dsw-alias-label-primary-foreground, #fff); background: color-mix(in srgb, var(--gg-danger) 86%, var(--gg-text)); }
786
+ .gg-review-mode { min-height: 28px; padding: 4px 8px; font-size: 11.5px; }
787
+ .gg-review-mode.active { border-color: var(--gg-accent); color: var(--gg-accent-strong); background: var(--gg-accent-soft); }
788
+
789
+ .gg-input, .gg-sync-row select, .gg-sync-actions > select {
790
+ min-height: 34px;
791
+ border: 1px solid var(--gg-border-strong);
792
+ border-radius: var(--gg-radius-control);
793
+ padding: 6px 9px;
794
+ color: var(--gg-text);
795
+ background: var(--gg-surface-inset);
796
+ font-family: inherit;
797
+ font-size: 12px;
798
+ line-height: 20px;
799
+ transition: border-color 120ms ease, box-shadow 120ms ease, background-color 120ms ease;
800
+ }
801
+ .gg-input::placeholder { color: var(--gg-text-muted); opacity: .9; }
802
+ .gg-input:hover:not(:disabled), .gg-sync-row select:hover:not(:disabled), .gg-sync-actions > select:hover:not(:disabled) { border-color: var(--gg-text-caption); }
803
+ .gg-input:focus, .gg-sync-row select:focus, .gg-sync-actions > select:focus {
804
+ outline: none;
805
+ border-color: var(--gg-accent);
806
+ box-shadow: var(--gg-focus);
807
+ background: var(--gg-bg);
808
+ }
809
+ .gg-field { display: flex; min-width: 0; flex-direction: column; gap: 5px; }
810
+ .gg-field-label { color: var(--gg-text-secondary); font-size: 11.5px; line-height: 17px; font-weight: 620; }
811
+ .gg-field-help { color: var(--gg-text-subtle); font-size: 11px; line-height: 16px; }
812
+ .gg-branch-form .gg-btn.primary { align-self: end; }
813
+ .gg-loading { display: grid; min-height: 180px; place-items: center; border: 1px solid var(--gg-border); border-radius: var(--gg-radius); background: var(--gg-surface); }
814
+ .gg-loading-inner { display: flex; width: min(260px, 72%); flex-direction: column; gap: 9px; }
815
+ .gg-loading-label { margin-bottom: 2px; color: var(--gg-text-subtle); font-size: 12px; text-align: center; }
816
+ .gg-loading-bar { height: 8px; border-radius: 999px; background: var(--gg-surface-raised); transform-origin: left center; }
817
+ .gg-loading-bar:nth-child(2) { width: 100%; }
818
+ .gg-loading-bar:nth-child(3) { width: 78%; }
819
+ .gg-loading-bar:nth-child(4) { width: 56%; }
820
+ @media (prefers-reduced-motion: no-preference) {
821
+ .gg-loading-bar { animation: gg-loading-pulse 1.4s ease-in-out infinite alternate; }
822
+ .gg-loading-bar:nth-child(3) { animation-delay: 100ms; }
823
+ .gg-loading-bar:nth-child(4) { animation-delay: 200ms; }
824
+ }
825
+ @keyframes gg-loading-pulse { from { opacity: .45; transform: scaleX(.94); } to { opacity: 1; transform: scaleX(1); } }
826
+ .gg-check { min-height: 30px; gap: 8px; color: var(--gg-text-secondary); }
827
+ .gg-check input { width: 15px; height: 15px; accent-color: var(--gg-accent); }
828
+
829
+ .gg-idletext, .gg-intent, .gg-sync-note { color: var(--gg-text-subtle); opacity: 1; }
830
+ .gg-workbench-error, .gg-fail, .gg-riskline { color: var(--gg-danger-label); }
831
+ .gg-ok { color: var(--gg-success-label); }
832
+ .gg-badge { padding: 2px 8px; line-height: 18px; }
833
+ .gg-badge.safe { color: var(--gg-success); background: color-mix(in srgb, var(--gg-success) 12%, transparent); }
834
+ .gg-badge.normal { color: var(--gg-warning-label); background: color-mix(in srgb, var(--gg-warning) 12%, transparent); }
835
+ .gg-badge.hard { color: var(--gg-danger); background: color-mix(in srgb, var(--gg-danger) 12%, transparent); }
836
+
837
+ .gg-file-group, .gg-branch-list, .gg-commit-list, .gg-stash-list,
838
+ .gg-commit-form, .gg-branch-form, .gg-sync-actions, .gg-diff, .gg-commit-detail {
839
+ border-color: var(--gg-border);
840
+ border-radius: var(--gg-radius);
841
+ background: var(--gg-surface);
842
+ }
843
+ .gg-file-group, .gg-branch-list, .gg-commit-form, .gg-branch-form, .gg-sync-actions, .gg-diff { padding: 9px; }
844
+ .gg-file-group > strong, .gg-sync-card strong, .gg-sync-actions > strong { color: var(--gg-text-secondary); font-size: 13.5px; line-height: 21px; font-weight: 680; }
845
+ .gg-file-group > strong { display: flex; align-items: center; }
846
+ .gg-folder-toggle { min-height: 30px; border-radius: 5px; color: var(--gg-text-secondary); }
847
+ .gg-folder-toggle:hover { color: var(--gg-text); background: var(--dsw-alias-interactive-bg-hover, var(--gg-accent-soft)); }
848
+ .gg-folder-toggle:focus-visible, .gg-file-path:focus-visible { outline: 2px solid var(--gg-accent); outline-offset: 1px; }
849
+ .gg-folder-arrow { color: var(--gg-text-muted); }
850
+ .gg-file, .gg-branch-row { min-height: 34px; border-bottom-color: var(--dsw-alias-border-l1, var(--gg-border)); }
851
+ .gg-file.active { border-radius: 5px; background: var(--gg-accent-soft); }
852
+ .gg-file-path code { color: inherit; font-size: 12.25px; line-height: 19px; }
853
+ .gg-file.added code { color: var(--gg-success-label); }
854
+ .gg-file.deleted code { color: var(--gg-danger-label); }
855
+ .gg-file.modified code { color: var(--gg-warning); }
856
+ .gg-branch-row.current { border-radius: 6px; padding-right: 6px; padding-left: 6px; background: var(--gg-accent-soft); }
857
+ .gg-branch-row.current > code:first-child { color: var(--gg-accent); font-size: 13px; font-weight: 700; }
858
+ .gg-reference-hash { color: var(--gg-text-caption); }
859
+
860
+ .gg-sync-grid { gap: 8px; }
861
+ .gg-sync-card { min-height: 68px; border-color: var(--gg-border); border-radius: var(--gg-radius); padding: 10px; background: var(--gg-surface); }
862
+ .gg-sync-value { color: var(--gg-text); font-size: 14px; line-height: 21px; font-weight: 620; }
863
+ .gg-sync-row { align-items: end; }
864
+ .gg-sync-warning, .gg-analysis, .gg-failure-card, .gg-branch-confirm, .gg-diagnostics {
865
+ border-radius: var(--gg-radius);
866
+ }
867
+ .gg-sync-warning { border-color: color-mix(in srgb, var(--gg-warning) 34%, transparent); color: var(--gg-warning-label); background: color-mix(in srgb, var(--gg-warning) 8%, transparent); }
868
+ .gg-analysis { border-color: color-mix(in srgb, var(--gg-warning) 34%, transparent); background: color-mix(in srgb, var(--gg-warning) 7%, transparent); }
869
+ .gg-failure-card, .gg-branch-confirm, .gg-diagnostics { border-color: color-mix(in srgb, var(--gg-danger) 38%, transparent); background: color-mix(in srgb, var(--gg-danger) 7%, transparent); }
870
+
871
+ .gg-review, .gg-diff-code, .gg-pre, .gg-commit-message { border-radius: 6px; background: var(--gg-surface-inset); }
872
+ .gg-diff > .gg-intent { color: var(--gg-text); font-size: 13.5px; line-height: 21px; font-weight: 650; }
873
+ .gg-review { line-height: 1.6; }
874
+ .gg-review-number { color: var(--gg-text-caption); background: color-mix(in srgb, var(--gg-text) 3%, transparent); }
875
+ .gg-review-code, .gg-diff-context { color: var(--gg-text-secondary); }
876
+ .gg-review-line.added, .gg-diff-added { color: var(--gg-success-label); background: color-mix(in srgb, var(--gg-success) 18%, transparent); }
877
+ .gg-review-line.deleted, .gg-diff-deleted { color: var(--gg-danger-label); background: color-mix(in srgb, var(--gg-danger) 18%, transparent); }
878
+ .gg-review-skip, .gg-diff-modified { color: var(--gg-warning-label); background: color-mix(in srgb, var(--gg-warning) 14%, transparent); }
879
+ .gg-review-annotation, .gg-diff-meta { color: var(--gg-text-muted); background: color-mix(in srgb, var(--gg-text) 5%, transparent); }
880
+
881
+ .gg-command-log { min-height: 144px; max-height: 260px; border-top-color: var(--gg-border); background: var(--gg-surface-inset); }
882
+ .gg-command-log-head { padding: 8px 12px 4px; color: var(--gg-text-secondary); font-size: 11.5px; letter-spacing: .01em; }
883
+ .gg-command-log-body { padding: 0 12px 9px; }
884
+ .gg-command-entry { padding: 5px 0; border-bottom: 1px solid var(--dsw-alias-border-l1, var(--gg-border)); }
885
+ .gg-command-entry:last-child { border-bottom: 0; }
886
+ .gg-command-label { color: var(--gg-warning); }
887
+ .gg-command-status.running { color: var(--gg-warning); }
888
+ .gg-command-status.succeeded { color: var(--gg-success-label); }
889
+ .gg-command-status.failed { color: var(--gg-danger-label); }
890
+ .gg-command-code { color: var(--gg-text-secondary); }
891
+
892
+ .gg-head { color: var(--gg-text); font-size: 14px; line-height: 22px; font-weight: 680; }
893
+ .gg-stepcode { color: var(--gg-text-secondary); background: var(--gg-surface-raised); }
894
+ .gg-failure-label { color: var(--gg-danger-label); }
895
+ .gg-failure-value, .gg-diagnostics { color: var(--gg-text-secondary); }
896
+ .gg-commit-row:hover, .gg-commit-row.active { background: var(--gg-accent-soft); }
897
+ .gg-commit-row:focus-visible { outline-color: var(--gg-accent); }
898
+ .gg-commit-subject { color: var(--gg-text); font-size: 13.25px; line-height: 19px; font-weight: 620; }
899
+ .gg-commit-meta, .gg-commit-detail-meta dt, .gg-commit-summary, .gg-stash-meta { color: var(--gg-text-muted); }
900
+ .gg-commit-hash, .gg-commit-detail-hash, .gg-stash-hash { color: var(--gg-text-caption); }
901
+ .gg-commit-detail-title { color: var(--gg-text); font-size: 15px; line-height: 22px; font-weight: 680; }
902
+ .gg-commit-message, .gg-commit-file-path { color: var(--gg-text-secondary); }
903
+ .gg-commit-files { border-color: var(--gg-border); border-radius: 6px; }
904
+ .gg-commit-file, .gg-stash-row { border-bottom-color: var(--dsw-alias-border-l1, var(--gg-border)); }
905
+ .gg-commit-file.added, .gg-additions { color: var(--gg-success-label); }
906
+ .gg-commit-file.deleted, .gg-deletions { color: var(--gg-danger-label); }
907
+ .gg-commit-file.modified { color: var(--gg-warning); }
908
+ .gg-stash-selector { color: var(--gg-accent); font-size: 12.5px; font-weight: 650; }
909
+ .gg-stash-subject { color: var(--gg-text); font-size: 13px; line-height: 20px; font-weight: 580; }
910
+ .gg-ref.branch, .gg-ref.current { color: var(--gg-accent); background: var(--gg-accent-soft); }
911
+ .gg-ref.remote { color: var(--gg-warning-label); background: color-mix(in srgb, var(--gg-warning) 12%, transparent); }
912
+ .gg-ref.tag { color: color-mix(in srgb, #9d5bd2 72%, var(--gg-text)); background: color-mix(in srgb, #9d5bd2 12%, transparent); }
913
+
914
+ .gg-dock-full { border-color: var(--gg-border, rgba(127, 127, 127, .35)); border-radius: var(--gg-radius, 8px); background: var(--gg-surface, rgba(127, 127, 127, .06)); }
915
+ .gg-workbench-action:active:not(:disabled) { transform: translateY(1px); }
916
+
917
+ /* Container width, not viewport width, decides when the two-pane change view is safe. */
918
+ .gg-change-layout { display: flex; }
919
+ @container easygit-workbench (min-width: 560px) {
920
+ .gg-change-layout { display: grid; grid-template-columns: minmax(210px, 36%) minmax(0, 1fr); align-items: stretch; }
921
+ .gg-diff { min-height: 0; }
922
+ }
923
+ @container easygit-workbench (max-width: 380px) {
924
+ .gg-workbench-head { min-height: 74px; padding: 11px 12px; }
925
+ .gg-workbench-body { padding-right: 8px; padding-left: 8px; }
926
+ .gg-tabs { margin-right: -8px; margin-left: -8px; padding-right: 8px; padding-left: 8px; }
927
+ .gg-tab { padding-right: 8px; padding-left: 8px; }
928
+ .gg-sync-grid { grid-template-columns: 1fr; }
929
+ }
930
+ @container easygit-workbench (max-width: 520px) {
931
+ .gg-tab-toolbar .gg-repository-identity, .gg-tab-toolbar .gg-section-heading { width: 100%; flex-basis: 100%; }
932
+ .gg-repository-name { font-size: 15px; }
933
+ .gg-branch-form { display: grid; grid-template-columns: 1fr; }
934
+ .gg-branch-form .gg-btn.primary { width: 100%; }
935
+ .gg-sync-row { grid-template-columns: 1fr; }
936
+ }
937
+
938
+ @media (prefers-reduced-motion: reduce) {
939
+ .gg-workbench *, .gg-workbench *::before, .gg-workbench *::after,
940
+ .gg-dock *, .gg-dock *::before, .gg-dock *::after {
941
+ scroll-behavior: auto !important;
942
+ transition-duration: .01ms !important;
943
+ animation-duration: .01ms !important;
944
+ animation-iteration-count: 1 !important;
945
+ }
946
+ }
647
947
  `;
648
948
  document.head.appendChild(tag);
649
949
  return () => {
@@ -819,6 +1119,34 @@ function renderRawDiffSurface(diff) {
819
1119
  function renderReviewSurface(diff) {
820
1120
  return React.createElement("div", { className: "gg-review-content" }, renderReview(diff));
821
1121
  }
1122
+ function renderRepositoryIdentity(topLevel, branch) {
1123
+ const name = repositoryName(topLevel);
1124
+ const currentBranch = String(branch || "\u5206\u79BB HEAD");
1125
+ return React.createElement(
1126
+ "div",
1127
+ {
1128
+ className: "gg-repository-identity",
1129
+ "aria-label": name + "\uFF0C\u5F53\u524D\u5206\u652F " + currentBranch
1130
+ },
1131
+ React.createElement("span", { className: "gg-repository-name", title: name }, name),
1132
+ React.createElement("span", { className: "gg-repository-arrow", "aria-hidden": "true" }, "\u2192"),
1133
+ React.createElement("code", { className: "gg-repository-branch", title: currentBranch }, currentBranch)
1134
+ );
1135
+ }
1136
+ function renderLoadingState(label) {
1137
+ return React.createElement(
1138
+ "div",
1139
+ { className: "gg-loading", role: "status", "aria-live": "polite" },
1140
+ React.createElement(
1141
+ "div",
1142
+ { className: "gg-loading-inner" },
1143
+ React.createElement("span", { className: "gg-loading-label" }, label),
1144
+ React.createElement("span", { className: "gg-loading-bar", "aria-hidden": "true" }),
1145
+ React.createElement("span", { className: "gg-loading-bar", "aria-hidden": "true" }),
1146
+ React.createElement("span", { className: "gg-loading-bar", "aria-hidden": "true" })
1147
+ )
1148
+ );
1149
+ }
822
1150
  function GitChangesTab(props) {
823
1151
  const { sessionId, intervalFn, revision, onChanged, onCommand, onFailure } = props;
824
1152
  const [summary, setSummary] = React.useState(null);
@@ -1000,7 +1328,7 @@ function GitChangesTab(props) {
1000
1328
  React.createElement(
1001
1329
  "div",
1002
1330
  { className: "gg-tab-toolbar" },
1003
- React.createElement("span", { className: "gg-idletext" }, summary ? repositoryName(summary.topLevel) + " \u2192 " + String(summary.branch || summary.head || "\u5206\u79BB HEAD") : "\u6B63\u5728\u8BFB\u53D6\u4ED3\u5E93\u2026"),
1331
+ summary ? renderRepositoryIdentity(summary.topLevel, summary.branch || summary.head) : React.createElement("span", { className: "gg-section-heading" }, "\u6B63\u5728\u8BFB\u53D6\u4ED3\u5E93\u2026"),
1004
1332
  React.createElement("button", {
1005
1333
  className: "gg-btn",
1006
1334
  disabled: busy || refreshFeedback.state === "loading",
@@ -1008,12 +1336,12 @@ function GitChangesTab(props) {
1008
1336
  void load(true);
1009
1337
  }
1010
1338
  }, refreshButtonLabel(refreshFeedback.state)),
1011
- React.createElement("button", { className: "gg-btn", disabled: busy, onClick: () => runMutation("stage-all") }, "\u5168\u90E8\u6682\u5B58"),
1012
- React.createElement("button", { className: "gg-btn", disabled: busy, onClick: () => runMutation("unstage-all") }, "\u5168\u90E8\u53D6\u6D88\u6682\u5B58")
1339
+ React.createElement("button", { className: "gg-btn", disabled: busy || !summary, onClick: () => runMutation("stage-all") }, "\u5168\u90E8\u6682\u5B58"),
1340
+ React.createElement("button", { className: "gg-btn", disabled: busy || !summary, onClick: () => runMutation("unstage-all") }, "\u5168\u90E8\u53D6\u6D88\u6682\u5B58")
1013
1341
  ),
1014
1342
  message ? React.createElement("div", { className: "gg-workbench-error" }, message) : null,
1015
1343
  diagnostics ? React.createElement("pre", { className: "gg-diagnostics" }, diagnostics) : null,
1016
- React.createElement(
1344
+ summary ? React.createElement(
1017
1345
  "div",
1018
1346
  { className: "gg-change-layout" },
1019
1347
  React.createElement(
@@ -1022,25 +1350,31 @@ function GitChangesTab(props) {
1022
1350
  React.createElement(
1023
1351
  "div",
1024
1352
  { className: "gg-file-group" },
1025
- React.createElement("strong", null, "\u672A\u6682\u5B58 (" + unstagedFiles.length + ")"),
1353
+ React.createElement("strong", null, "\u672A\u6682\u5B58", React.createElement("span", { className: "gg-section-count" }, String(unstagedFiles.length))),
1026
1354
  unstagedFiles.length ? renderFileTree(unstagedFiles, false, "unstaged") : React.createElement("div", { className: "gg-idletext" }, "\u6CA1\u6709\u672A\u6682\u5B58\u7684\u53D8\u66F4\u3002")
1027
1355
  ),
1028
1356
  React.createElement(
1029
1357
  "div",
1030
1358
  { className: "gg-file-group" },
1031
- React.createElement("strong", null, "\u5DF2\u6682\u5B58 (" + stagedFiles.length + ")"),
1359
+ React.createElement("strong", null, "\u5DF2\u6682\u5B58", React.createElement("span", { className: "gg-section-count" }, String(stagedFiles.length))),
1032
1360
  stagedFiles.length ? renderFileTree(stagedFiles, true, "staged") : React.createElement("div", { className: "gg-idletext" }, "\u6CA1\u6709\u5DF2\u6682\u5B58\u7684\u53D8\u66F4\u3002")
1033
1361
  ),
1034
1362
  React.createElement(
1035
1363
  "div",
1036
1364
  { className: "gg-commit-form" },
1037
- React.createElement("input", {
1038
- className: "gg-input",
1039
- value: commitMessage,
1040
- placeholder: "\u63D0\u4EA4\u8BF4\u660E",
1041
- disabled: busy,
1042
- onChange: (event) => setCommitMessage(String(event.target.value || ""))
1043
- }),
1365
+ React.createElement(
1366
+ "label",
1367
+ { className: "gg-field", htmlFor: "gg-commit-message" },
1368
+ React.createElement("span", { className: "gg-field-label" }, "\u63D0\u4EA4\u8BF4\u660E"),
1369
+ React.createElement("input", {
1370
+ id: "gg-commit-message",
1371
+ className: "gg-input",
1372
+ value: commitMessage,
1373
+ placeholder: "\u4F8B\u5982\uFF1Afix: \u4FEE\u590D\u767B\u5F55\u72B6\u6001",
1374
+ disabled: busy,
1375
+ onChange: (event) => setCommitMessage(String(event.target.value || ""))
1376
+ })
1377
+ ),
1044
1378
  React.createElement("button", {
1045
1379
  className: "gg-btn primary",
1046
1380
  disabled: busy || !commitMessage.trim() || stagedFiles.length === 0,
@@ -1066,7 +1400,7 @@ function GitChangesTab(props) {
1066
1400
  renderRawDiffSurface(selected ? diff : "\u5C1A\u672A\u9009\u62E9\u6587\u4EF6\u3002")
1067
1401
  )
1068
1402
  )
1069
- )
1403
+ ) : renderLoadingState("\u6B63\u5728\u8BFB\u53D6\u4ED3\u5E93\u72B6\u6001")
1070
1404
  );
1071
1405
  }
1072
1406
  function GitBranchesTab(props) {
@@ -1201,6 +1535,7 @@ function GitBranchesTab(props) {
1201
1535
  React.createElement(
1202
1536
  "div",
1203
1537
  { className: "gg-tab-toolbar" },
1538
+ React.createElement("span", { className: "gg-section-heading" }, "\u5206\u652F\u4E0E\u5F15\u7528"),
1204
1539
  React.createElement("button", {
1205
1540
  className: "gg-btn",
1206
1541
  disabled: busy || refreshFeedback.state === "loading",
@@ -1226,21 +1561,26 @@ function GitBranchesTab(props) {
1226
1561
  referenceTab === "local" ? React.createElement(
1227
1562
  "div",
1228
1563
  { className: "gg-local-branches" },
1229
- React.createElement("input", {
1230
- className: "gg-input",
1231
- type: "search",
1232
- value: branchQuery,
1233
- placeholder: "\u641C\u7D22\u672C\u5730\u5206\u652F",
1234
- "aria-label": "\u641C\u7D22\u672C\u5730\u5206\u652F",
1235
- onChange: (event) => setBranchQuery(String(event.target.value || ""))
1236
- }),
1564
+ React.createElement(
1565
+ "label",
1566
+ { className: "gg-field", htmlFor: "gg-branch-search" },
1567
+ React.createElement("span", { className: "gg-field-label" }, "\u641C\u7D22\u5206\u652F"),
1568
+ React.createElement("input", {
1569
+ id: "gg-branch-search",
1570
+ className: "gg-input",
1571
+ type: "search",
1572
+ value: branchQuery,
1573
+ placeholder: "\u8F93\u5165\u5206\u652F\u540D\u79F0",
1574
+ onChange: (event) => setBranchQuery(String(event.target.value || ""))
1575
+ })
1576
+ ),
1237
1577
  React.createElement("div", { className: "gg-branch-list" }, visibleBranches.length ? visibleBranches.map((branch, index) => {
1238
1578
  const branchName = String(branch.name || "");
1239
1579
  const confirming = confirmDelete === branchName;
1240
1580
  const forcing = forceDelete === branchName;
1241
1581
  return React.createElement(
1242
1582
  "div",
1243
- { className: "gg-branch-row" + (confirming || forcing ? " confirming" : ""), key: branchName || String(index) },
1583
+ { className: "gg-branch-row" + (branch.current ? " current" : "") + (confirming || forcing ? " confirming" : ""), key: branchName || String(index) },
1244
1584
  React.createElement("code", null, (branch.current ? "* " : "") + branchName),
1245
1585
  branch.upstream ? React.createElement("span", { className: "gg-idletext" }, String(branch.upstream)) : null,
1246
1586
  branch.current ? null : React.createElement("button", { className: "gg-btn", disabled: busy, onClick: () => {
@@ -1290,8 +1630,18 @@ function GitBranchesTab(props) {
1290
1630
  referenceTab === "local" ? React.createElement(
1291
1631
  "div",
1292
1632
  { className: "gg-branch-form" },
1293
- React.createElement("input", { className: "gg-input", value: name, placeholder: "\u65B0\u5206\u652F\u540D\u79F0", disabled: busy, onChange: (event) => setName(String(event.target.value || "")) }),
1294
- React.createElement("input", { className: "gg-input", value: base, placeholder: "\u57FA\u7840\u5206\u652F", disabled: busy, onChange: (event) => setBase(String(event.target.value || "")) }),
1633
+ React.createElement(
1634
+ "label",
1635
+ { className: "gg-field", htmlFor: "gg-new-branch-name" },
1636
+ React.createElement("span", { className: "gg-field-label" }, "\u65B0\u5206\u652F\u540D\u79F0"),
1637
+ React.createElement("input", { id: "gg-new-branch-name", className: "gg-input", value: name, placeholder: "\u4F8B\u5982\uFF1Afeature/login", disabled: busy, onChange: (event) => setName(String(event.target.value || "")) })
1638
+ ),
1639
+ React.createElement(
1640
+ "label",
1641
+ { className: "gg-field", htmlFor: "gg-new-branch-base" },
1642
+ React.createElement("span", { className: "gg-field-label" }, "\u57FA\u7840\u5206\u652F"),
1643
+ React.createElement("input", { id: "gg-new-branch-base", className: "gg-input", value: base, placeholder: "\u4F8B\u5982\uFF1Amain", disabled: busy, onChange: (event) => setBase(String(event.target.value || "")) })
1644
+ ),
1295
1645
  React.createElement("button", {
1296
1646
  className: "gg-btn primary",
1297
1647
  disabled: busy || !name.trim() || !base.trim(),
@@ -1332,7 +1682,7 @@ function CommitGraph(props) {
1332
1682
  "aria-hidden": "true"
1333
1683
  },
1334
1684
  paths,
1335
- merge ? React.createElement("circle", { cx: laneX(row.lane), cy: 11, r: 7, fill: "#202224", stroke: nodeColor, strokeWidth: 2 }) : null,
1685
+ merge ? React.createElement("circle", { cx: laneX(row.lane), cy: 11, r: 7, fill: "var(--gg-surface)", stroke: nodeColor, strokeWidth: 2 }) : null,
1336
1686
  React.createElement("circle", { cx: laneX(row.lane), cy: 11, r: merge ? 3 : 5, fill: nodeColor })
1337
1687
  );
1338
1688
  }
@@ -1548,13 +1898,18 @@ function GitCommitsTab(props) {
1548
1898
  return React.createElement(
1549
1899
  "section",
1550
1900
  { className: "gg-tab-content" },
1551
- React.createElement("div", { className: "gg-tab-toolbar" }, React.createElement("button", {
1552
- className: "gg-btn",
1553
- disabled: refreshFeedback.state === "loading",
1554
- onClick: () => {
1555
- void load(true);
1556
- }
1557
- }, refreshButtonLabel(refreshFeedback.state))),
1901
+ React.createElement(
1902
+ "div",
1903
+ { className: "gg-tab-toolbar" },
1904
+ React.createElement("span", { className: "gg-section-heading" }, "\u63D0\u4EA4\u8BB0\u5F55", React.createElement("span", { className: "gg-section-count" }, String(commits.length))),
1905
+ React.createElement("button", {
1906
+ className: "gg-btn",
1907
+ disabled: refreshFeedback.state === "loading",
1908
+ onClick: () => {
1909
+ void load(true);
1910
+ }
1911
+ }, refreshButtonLabel(refreshFeedback.state))
1912
+ ),
1558
1913
  message ? React.createElement("div", { className: "gg-workbench-error" }, message) : null,
1559
1914
  React.createElement(
1560
1915
  "div",
@@ -1638,7 +1993,7 @@ function GitStashesTab(props) {
1638
1993
  React.createElement(
1639
1994
  "div",
1640
1995
  { className: "gg-tab-toolbar" },
1641
- React.createElement("span", { className: "gg-idletext" }, "\u8D2E\u85CF (" + stashes.length + ")"),
1996
+ React.createElement("span", { className: "gg-section-heading" }, "\u8D2E\u85CF", React.createElement("span", { className: "gg-section-count" }, String(stashes.length))),
1642
1997
  React.createElement("button", { className: "gg-btn", type: "button", disabled: loading, onClick: load }, loading ? "\u6B63\u5728\u5237\u65B0\u2026" : "\u5237\u65B0")
1643
1998
  ),
1644
1999
  message ? React.createElement("div", { className: "gg-workbench-error" }, message) : null,
@@ -1756,7 +2111,7 @@ function GitSyncTab(props) {
1756
2111
  React.createElement(
1757
2112
  "div",
1758
2113
  { className: "gg-tab-toolbar" },
1759
- React.createElement("span", { className: "gg-idletext" }, state ? repositoryName(state.topLevel) + " \u2192 " + (state.branch || "\u5206\u79BB HEAD") : "\u6B63\u5728\u8BFB\u53D6\u4ED3\u5E93\u2026"),
2114
+ state ? renderRepositoryIdentity(state.topLevel, state.branch) : React.createElement("span", { className: "gg-section-heading" }, "\u6B63\u5728\u8BFB\u53D6\u4ED3\u5E93\u2026"),
1760
2115
  React.createElement("button", {
1761
2116
  className: "gg-btn",
1762
2117
  type: "button",
@@ -1784,12 +2139,18 @@ function GitSyncTab(props) {
1784
2139
  React.createElement(
1785
2140
  "div",
1786
2141
  { className: "gg-sync-row" },
1787
- React.createElement("select", {
1788
- className: "gg-input",
1789
- value: remote,
1790
- disabled: busy || !hasRemote,
1791
- onChange: (event) => setRemote(String(event.target.value || ""))
1792
- }, state ? state.remotes.map((entry) => React.createElement("option", { value: entry, key: entry }, entry)) : null),
2142
+ React.createElement(
2143
+ "label",
2144
+ { className: "gg-field", htmlFor: "gg-sync-remote" },
2145
+ React.createElement("span", { className: "gg-field-label" }, "\u8FDC\u7A0B\u4ED3\u5E93"),
2146
+ React.createElement("select", {
2147
+ id: "gg-sync-remote",
2148
+ className: "gg-input",
2149
+ value: remote,
2150
+ disabled: busy || !hasRemote,
2151
+ onChange: (event) => setRemote(String(event.target.value || ""))
2152
+ }, state ? state.remotes.map((entry) => React.createElement("option", { value: entry, key: entry }, entry)) : null)
2153
+ ),
1793
2154
  React.createElement("button", { className: "gg-btn", type: "button", disabled: busy || !remote, onClick: () => {
1794
2155
  void run("fetch", { remote });
1795
2156
  } }, "Fetch")
@@ -1823,12 +2184,18 @@ function GitSyncTab(props) {
1823
2184
  { className: "gg-sync-actions" },
1824
2185
  React.createElement("strong", null, "Rebase\uFF08\u9AD8\u98CE\u9669\uFF09"),
1825
2186
  state?.rebaseInProgress ? React.createElement("div", { className: "gg-sync-warning" }, state.conflictCount > 0 ? "\u8BF7\u5148\u5728\u201C\u53D8\u66F4\u201D\u9875\u89E3\u51B3\u5E76\u6682\u5B58\u5168\u90E8\u51B2\u7A81\uFF0C\u7136\u540E\u8FD4\u56DE\u8FD9\u91CC\u7EE7\u7EED Rebase\u3002" : "\u51B2\u7A81\u5DF2\u7ECF\u89E3\u51B3\u5E76\u6682\u5B58\uFF0C\u53EF\u4EE5\u7EE7\u7EED Rebase\uFF1B\u4E5F\u53EF\u4EE5\u4E2D\u6B62\u5E76\u6062\u590D\u5230\u5F00\u59CB\u524D\u3002") : null,
1826
- !state?.rebaseInProgress ? React.createElement("select", {
1827
- className: "gg-input",
1828
- value: rebaseTarget,
1829
- disabled: busy || targets.length === 0,
1830
- onChange: (event) => setRebaseTarget(String(event.target.value || ""))
1831
- }, targets.map((entry) => React.createElement("option", { value: entry, key: entry }, entry))) : null,
2187
+ !state?.rebaseInProgress ? React.createElement(
2188
+ "label",
2189
+ { className: "gg-field", htmlFor: "gg-rebase-target" },
2190
+ React.createElement("span", { className: "gg-field-label" }, "\u76EE\u6807\u5F15\u7528"),
2191
+ React.createElement("select", {
2192
+ id: "gg-rebase-target",
2193
+ className: "gg-input",
2194
+ value: rebaseTarget,
2195
+ disabled: busy || targets.length === 0,
2196
+ onChange: (event) => setRebaseTarget(String(event.target.value || ""))
2197
+ }, targets.map((entry) => React.createElement("option", { value: entry, key: entry }, entry)))
2198
+ ) : null,
1832
2199
  React.createElement(
1833
2200
  "label",
1834
2201
  { className: "gg-check" },
@@ -2110,6 +2477,21 @@ function GitWorkbenchPanel(props) {
2110
2477
  { id: "sync", label: "\u540C\u6B65" },
2111
2478
  { id: "proposal", label: "\u5EFA\u8BAE" }
2112
2479
  ];
2480
+ const onTabKeyDown = (event, index) => {
2481
+ let nextIndex = index;
2482
+ if (event.key === "ArrowRight") nextIndex = (index + 1) % tabs.length;
2483
+ else if (event.key === "ArrowLeft") nextIndex = (index - 1 + tabs.length) % tabs.length;
2484
+ else if (event.key === "Home") nextIndex = 0;
2485
+ else if (event.key === "End") nextIndex = tabs.length - 1;
2486
+ else return;
2487
+ event.preventDefault();
2488
+ const next = tabs[nextIndex];
2489
+ setTab(next.id);
2490
+ window.requestAnimationFrame(() => {
2491
+ const element = document.getElementById("gg-tab-" + next.id);
2492
+ if (element) element.focus();
2493
+ });
2494
+ };
2113
2495
  const content = tab === "changes" ? React.createElement(GitChangesTab, { sessionId: props.sessionId, intervalFn: props.intervalFn, revision, onChanged: refresh, onCommand: reportCommand, onFailure: handleFailure }) : tab === "branches" ? React.createElement(GitBranchesTab, { sessionId: props.sessionId, revision, onChanged: refresh, onCommand: reportCommand, onFailure: handleFailure }) : tab === "commits" ? React.createElement(GitCommitsTab, { sessionId: props.sessionId, revision }) : tab === "stashes" ? React.createElement(GitStashesTab, { sessionId: props.sessionId, revision }) : tab === "sync" ? React.createElement(GitSyncTab, { sessionId: props.sessionId, intervalFn: props.intervalFn, revision, onChanged: refresh, onCommand: reportCommand, onFailure: handleFailure }) : React.createElement(GitDock, { sessionId: props.sessionId, intervalFn: props.intervalFn, timeoutFn: props.timeoutFn, onFailure: handleFailure });
2114
2496
  const analysisBanner = shouldShowAnalysisBanner(tab, pendingAnalysis) && pendingAnalysis ? React.createElement(
2115
2497
  "div",
@@ -2145,9 +2527,20 @@ function GitWorkbenchPanel(props) {
2145
2527
  },
2146
2528
  React.createElement("div", {
2147
2529
  className: "gg-workbench-resize" + (isResizing ? " dragging" : ""),
2148
- "aria-hidden": "true",
2530
+ role: "separator",
2531
+ tabIndex: 0,
2532
+ "aria-label": "\u8C03\u6574 Git \u5DE5\u4F5C\u53F0\u5BBD\u5EA6",
2533
+ "aria-orientation": "vertical",
2534
+ "aria-valuemin": Math.round(WORKBENCH_MIN_RATIO * 100),
2535
+ "aria-valuemax": Math.round(WORKBENCH_MAX_RATIO * 100),
2536
+ "aria-valuenow": Math.round(ratio * 100),
2149
2537
  title: "\u5DE6\u53F3\u62D6\u52A8\u8C03\u6574\u5DE5\u4F5C\u53F0\u5BBD\u5EA6",
2150
- onPointerDown: onResizePointerDown
2538
+ onPointerDown: onResizePointerDown,
2539
+ onKeyDown: (event) => {
2540
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
2541
+ event.preventDefault();
2542
+ setWorkbenchRatio(ratio + (event.key === "ArrowLeft" ? 0.02 : -0.02), true);
2543
+ }
2151
2544
  }),
2152
2545
  React.createElement(
2153
2546
  "div",
@@ -2164,16 +2557,24 @@ function GitWorkbenchPanel(props) {
2164
2557
  React.createElement(
2165
2558
  "div",
2166
2559
  { className: "gg-workbench-body" },
2167
- React.createElement("div", { className: "gg-tabs", role: "tablist", "aria-label": "Git \u5DE5\u4F5C\u53F0\u533A\u57DF" }, tabs.map((entry) => React.createElement("button", {
2560
+ React.createElement("div", { className: "gg-tabs", role: "tablist", "aria-label": "Git \u5DE5\u4F5C\u53F0\u533A\u57DF" }, tabs.map((entry, index) => React.createElement("button", {
2168
2561
  className: "gg-tab" + (tab === entry.id ? " active" : ""),
2169
2562
  type: "button",
2170
2563
  role: "tab",
2564
+ id: "gg-tab-" + entry.id,
2565
+ "aria-controls": "gg-panel-" + entry.id,
2171
2566
  "aria-selected": tab === entry.id,
2567
+ tabIndex: tab === entry.id ? 0 : -1,
2172
2568
  onClick: () => setTab(entry.id),
2569
+ onKeyDown: (event) => onTabKeyDown(event, index),
2173
2570
  key: entry.id
2174
2571
  }, entry.label))),
2175
- analysisBanner,
2176
- content
2572
+ React.createElement("div", {
2573
+ className: "gg-tab-panel",
2574
+ id: "gg-panel-" + tab,
2575
+ role: "tabpanel",
2576
+ "aria-labelledby": "gg-tab-" + tab
2577
+ }, analysisBanner, content)
2177
2578
  ),
2178
2579
  React.createElement(
2179
2580
  "section",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-easygit-plugin",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "面向 DeepSeek Harness Web 的可视化 Git 工作台,支持查看仓库状态与提交记录、快捷执行常用 Git 操作,以及安全运行自然语言生成的分步骤命令提议。",
5
5
  "license": "MIT",
6
6
  "main": "lib/index.js",