zen-gitsync 2.13.23 → 2.13.24

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.
Files changed (41) hide show
  1. package/package.json +1 -1
  2. package/scripts/README_COLOR_CONVERTER.md +196 -196
  3. package/scripts/README_FONTSIZE_CONVERTER.md +278 -278
  4. package/scripts/README_SPACING_CONVERTER.md +126 -126
  5. package/scripts/README_STYLE_VARS.md +180 -180
  6. package/src/gitCommit.js +2 -2
  7. package/src/ui/public/assets/{AppVersionBadge-BUS8w2f8.js → AppVersionBadge-CaVphp8E.js} +1 -1
  8. package/src/ui/public/assets/{BranchSelector-Dm7nENer.js → BranchSelector-B91Ylbas.js} +1 -1
  9. package/src/ui/public/assets/{CommandConsole-C1W9ZQkE.js → CommandConsole-bK4iwZvI.js} +2 -2
  10. package/src/ui/public/assets/{CommitForm-C76W1ZZH.js → CommitForm-zOCxmZ84.js} +1 -1
  11. package/src/ui/public/assets/{CustomCommandManager-JKx8JYqn.js → CustomCommandManager-C1lRrp5z.js} +1 -1
  12. package/src/ui/public/assets/{EditorView-CriUYDvi.js → EditorView-DYo2oYtk.js} +0 -0
  13. package/src/ui/public/assets/{FileDiffViewer-DNWsiIGt.js → FileDiffViewer-Ce17WOZ-.js} +1 -1
  14. package/src/ui/public/assets/{FlowExecutionViewer-CTDh2bCD.js → FlowExecutionViewer-CRK6lIul.js} +1 -1
  15. package/src/ui/public/assets/{FlowOrchestrationWorkspace-Chah2aGN.js → FlowOrchestrationWorkspace-BDw7ThWp.js} +1 -1
  16. package/src/ui/public/assets/{GitStatus-DP-DQsiS.js → GitStatus-DN4_m6sO.js} +1 -1
  17. package/src/ui/public/assets/{LogList-Z76_5USQ.js → LogList-BshRTCrE.js} +1 -1
  18. package/src/ui/public/assets/{ProjectStartupButton-C5oF4unq.js → ProjectStartupButton-C-dXxxMO.js} +1 -1
  19. package/src/ui/public/assets/{RemoteRepoCard-B-fGjb8Y.js → RemoteRepoCard-DDZcP5-V.js} +1 -1
  20. package/src/ui/public/assets/{ResetToRemoteButton-BixSoEVs.js → ResetToRemoteButton-TXJzvBxE.js} +1 -1
  21. package/src/ui/public/assets/{SourceMapView-C9HZiJ9N.js → SourceMapView-BUkB6h41.js} +1 -1
  22. package/src/ui/public/assets/{TemplateManager-C7SuKq0f.js → TemplateManager-DFVzDiu0.js} +1 -1
  23. package/src/ui/public/assets/{UserInputNode-CYy0UpzR.js → UserInputNode-CXyV1xG4.js} +1 -1
  24. package/src/ui/public/assets/{WorkbenchView-A9Oik707.js → WorkbenchView-CEYhsa4O.js} +1 -1
  25. package/src/ui/public/assets/{index-DPSGvy34.js → index-BGmxuKoN.js} +2 -2
  26. package/src/ui/public/favicon.svg +75 -75
  27. package/src/ui/public/index.html +18 -18
  28. package/src/ui/public/logo.svg +74 -74
  29. package/src/ui/server/index.js +3 -3
  30. package/src/ui/server/routes/branchStatus.js +4 -4
  31. package/src/ui/server/routes/config.js +8 -8
  32. package/src/ui/server/routes/exec.js +7 -1
  33. package/src/ui/server/routes/fs.js +2 -2
  34. package/src/ui/server/routes/git/diff.js +17 -16
  35. package/src/ui/server/routes/git/diffUtils.js +21 -2
  36. package/src/ui/server/routes/git/stash.js +38 -42
  37. package/src/ui/server/routes/git/tags.js +10 -10
  38. package/src/ui/server/routes/git.js +15 -26
  39. package/src/ui/server/routes/gitOps.js +91 -125
  40. package/src/ui/server/routes/status.js +3 -3
  41. package/src/utils/index.js +32 -29
@@ -1,75 +1,75 @@
1
- <svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <radialGradient id="bgGrad" cx="38%" cy="32%" r="70%">
4
- <stop offset="0%" stop-color="#1e1b4b"/>
5
- <stop offset="100%" stop-color="#0d0b1e"/>
6
- </radialGradient>
7
- <linearGradient id="mainGrad" x1="0%" y1="0%" x2="0%" y2="100%">
8
- <stop offset="0%" stop-color="#c4b5fd"/>
9
- <stop offset="100%" stop-color="#7c3aed"/>
10
- </linearGradient>
11
- <linearGradient id="featGrad" x1="0%" y1="0%" x2="100%" y2="100%">
12
- <stop offset="0%" stop-color="#7dd3fc"/>
13
- <stop offset="100%" stop-color="#0284c7"/>
14
- </linearGradient>
15
- <filter id="glow" x="-40%" y="-40%" width="180%" height="180%">
16
- <feGaussianBlur in="SourceGraphic" stdDeviation="2.5" result="blur"/>
17
- <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
18
- </filter>
19
- <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
20
- <feGaussianBlur in="SourceGraphic" stdDeviation="1.5" result="blur"/>
21
- <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
22
- </filter>
23
- </defs>
24
-
25
- <!-- 背景圆 -->
26
- <circle cx="100" cy="100" r="96" fill="url(#bgGrad)"/>
27
-
28
- <!-- 同步外弧(上半,代表 sync 循环) -->
29
- <path d="M 100,20 A 80,80 0 1,1 36,153"
30
- stroke="rgba(167,139,250,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
31
- <!-- 同步外弧(下半) -->
32
- <path d="M 36,153 A 80,80 0 0,1 164,153"
33
- stroke="rgba(56,189,248,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
34
- <!-- 同步箭头(上) -->
35
- <path d="M 91,17 L 100,20 L 96,29"
36
- stroke="rgba(167,139,250,0.55)" stroke-width="2.5" fill="none"
37
- stroke-linecap="round" stroke-linejoin="round"/>
38
- <!-- 同步箭头(下) -->
39
- <path d="M 163,145 L 164,154 L 155,151"
40
- stroke="rgba(56,189,248,0.55)" stroke-width="2.5" fill="none"
41
- stroke-linecap="round" stroke-linejoin="round"/>
42
-
43
- <!-- 主分支竖线 -->
44
- <line x1="76" y1="44" x2="76" y2="156"
45
- stroke="url(#mainGrad)" stroke-width="5.5" stroke-linecap="round"
46
- filter="url(#softGlow)"/>
47
-
48
- <!-- 特性分支曲线(分出) -->
49
- <path d="M 76,80 C 98,80 130,96 130,120 L 130,140"
50
- stroke="url(#featGrad)" stroke-width="4.5" fill="none"
51
- stroke-linecap="round" filter="url(#softGlow)"/>
52
- <!-- 特性分支合并回主分支 -->
53
- <path d="M 130,140 C 130,156 105,159 76,155"
54
- stroke="url(#featGrad)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
55
-
56
- <!-- 主分支节点 -->
57
- <circle cx="76" cy="48" r="11" fill="#13103a" stroke="#c4b5fd" stroke-width="3" filter="url(#glow)"/>
58
- <circle cx="76" cy="48" r="5" fill="#ddd6fe"/>
59
-
60
- <circle cx="76" cy="84" r="11" fill="#13103a" stroke="#a78bfa" stroke-width="3"/>
61
- <circle cx="76" cy="84" r="5" fill="#c4b5fd"/>
62
-
63
- <circle cx="76" cy="120" r="11" fill="#13103a" stroke="#8b5cf6" stroke-width="3"/>
64
- <circle cx="76" cy="120" r="5" fill="#a78bfa"/>
65
-
66
- <circle cx="76" cy="155" r="11" fill="#13103a" stroke="#7c3aed" stroke-width="3" filter="url(#glow)"/>
67
- <circle cx="76" cy="155" r="5" fill="#8b5cf6"/>
68
-
69
- <!-- 特性分支节点 -->
70
- <circle cx="130" cy="115" r="11" fill="#13103a" stroke="#38bdf8" stroke-width="3" filter="url(#glow)"/>
71
- <circle cx="130" cy="115" r="5" fill="#7dd3fc"/>
72
-
73
- <circle cx="130" cy="143" r="11" fill="#13103a" stroke="#0ea5e9" stroke-width="3" filter="url(#glow)"/>
74
- <circle cx="130" cy="143" r="5" fill="#38bdf8"/>
75
- </svg>
1
+ <svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <radialGradient id="bgGrad" cx="38%" cy="32%" r="70%">
4
+ <stop offset="0%" stop-color="#1e1b4b"/>
5
+ <stop offset="100%" stop-color="#0d0b1e"/>
6
+ </radialGradient>
7
+ <linearGradient id="mainGrad" x1="0%" y1="0%" x2="0%" y2="100%">
8
+ <stop offset="0%" stop-color="#c4b5fd"/>
9
+ <stop offset="100%" stop-color="#7c3aed"/>
10
+ </linearGradient>
11
+ <linearGradient id="featGrad" x1="0%" y1="0%" x2="100%" y2="100%">
12
+ <stop offset="0%" stop-color="#7dd3fc"/>
13
+ <stop offset="100%" stop-color="#0284c7"/>
14
+ </linearGradient>
15
+ <filter id="glow" x="-40%" y="-40%" width="180%" height="180%">
16
+ <feGaussianBlur in="SourceGraphic" stdDeviation="2.5" result="blur"/>
17
+ <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
18
+ </filter>
19
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
20
+ <feGaussianBlur in="SourceGraphic" stdDeviation="1.5" result="blur"/>
21
+ <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- 背景圆 -->
26
+ <circle cx="100" cy="100" r="96" fill="url(#bgGrad)"/>
27
+
28
+ <!-- 同步外弧(上半,代表 sync 循环) -->
29
+ <path d="M 100,20 A 80,80 0 1,1 36,153"
30
+ stroke="rgba(167,139,250,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
31
+ <!-- 同步外弧(下半) -->
32
+ <path d="M 36,153 A 80,80 0 0,1 164,153"
33
+ stroke="rgba(56,189,248,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
34
+ <!-- 同步箭头(上) -->
35
+ <path d="M 91,17 L 100,20 L 96,29"
36
+ stroke="rgba(167,139,250,0.55)" stroke-width="2.5" fill="none"
37
+ stroke-linecap="round" stroke-linejoin="round"/>
38
+ <!-- 同步箭头(下) -->
39
+ <path d="M 163,145 L 164,154 L 155,151"
40
+ stroke="rgba(56,189,248,0.55)" stroke-width="2.5" fill="none"
41
+ stroke-linecap="round" stroke-linejoin="round"/>
42
+
43
+ <!-- 主分支竖线 -->
44
+ <line x1="76" y1="44" x2="76" y2="156"
45
+ stroke="url(#mainGrad)" stroke-width="5.5" stroke-linecap="round"
46
+ filter="url(#softGlow)"/>
47
+
48
+ <!-- 特性分支曲线(分出) -->
49
+ <path d="M 76,80 C 98,80 130,96 130,120 L 130,140"
50
+ stroke="url(#featGrad)" stroke-width="4.5" fill="none"
51
+ stroke-linecap="round" filter="url(#softGlow)"/>
52
+ <!-- 特性分支合并回主分支 -->
53
+ <path d="M 130,140 C 130,156 105,159 76,155"
54
+ stroke="url(#featGrad)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
55
+
56
+ <!-- 主分支节点 -->
57
+ <circle cx="76" cy="48" r="11" fill="#13103a" stroke="#c4b5fd" stroke-width="3" filter="url(#glow)"/>
58
+ <circle cx="76" cy="48" r="5" fill="#ddd6fe"/>
59
+
60
+ <circle cx="76" cy="84" r="11" fill="#13103a" stroke="#a78bfa" stroke-width="3"/>
61
+ <circle cx="76" cy="84" r="5" fill="#c4b5fd"/>
62
+
63
+ <circle cx="76" cy="120" r="11" fill="#13103a" stroke="#8b5cf6" stroke-width="3"/>
64
+ <circle cx="76" cy="120" r="5" fill="#a78bfa"/>
65
+
66
+ <circle cx="76" cy="155" r="11" fill="#13103a" stroke="#7c3aed" stroke-width="3" filter="url(#glow)"/>
67
+ <circle cx="76" cy="155" r="5" fill="#8b5cf6"/>
68
+
69
+ <!-- 特性分支节点 -->
70
+ <circle cx="130" cy="115" r="11" fill="#13103a" stroke="#38bdf8" stroke-width="3" filter="url(#glow)"/>
71
+ <circle cx="130" cy="115" r="5" fill="#7dd3fc"/>
72
+
73
+ <circle cx="130" cy="143" r="11" fill="#13103a" stroke="#0ea5e9" stroke-width="3" filter="url(#glow)"/>
74
+ <circle cx="130" cy="143" r="5" fill="#38bdf8"/>
75
+ </svg>
@@ -1,16 +1,16 @@
1
- <!doctype html>
2
- <html lang="zh-CN" translate="no">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="google" content="notranslate" />
6
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
- <title>Zen GitSync</title>
9
- <!-- Premium fonts: Plus Jakarta Sans (UI) + JetBrains Mono (code) -->
10
- <link rel="preconnect" href="https://fonts.googleapis.com" />
11
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
- <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
13
- <script type="module" crossorigin src="/assets/index-DPSGvy34.js"></script>
1
+ <!doctype html>
2
+ <html lang="zh-CN" translate="no">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="google" content="notranslate" />
6
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <title>Zen GitSync</title>
9
+ <!-- Premium fonts: Plus Jakarta Sans (UI) + JetBrains Mono (code) -->
10
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
+ <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
13
+ <script type="module" crossorigin src="/assets/index-BGmxuKoN.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CMxvf4Kt.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/monaco-DC7mqInI.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/element-plus-CJjFCgLP.js">
@@ -21,8 +21,8 @@
21
21
  <link rel="stylesheet" crossorigin href="/assets/element-plus-D36sOm0a.css">
22
22
  <link rel="stylesheet" crossorigin href="/assets/vendor-DNI_idR2.css">
23
23
  <link rel="stylesheet" crossorigin href="/assets/index-CDa9xf0V.css">
24
- </head>
25
- <body>
26
- <div id="app"></div>
27
- </body>
28
- </html>
24
+ </head>
25
+ <body>
26
+ <div id="app"></div>
27
+ </body>
28
+ </html>
@@ -1,75 +1,75 @@
1
- <svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <radialGradient id="bgGrad" cx="38%" cy="32%" r="70%">
4
- <stop offset="0%" stop-color="#1e1b4b"/>
5
- <stop offset="100%" stop-color="#0d0b1e"/>
6
- </radialGradient>
7
- <linearGradient id="mainGrad" x1="0%" y1="0%" x2="0%" y2="100%">
8
- <stop offset="0%" stop-color="#c4b5fd"/>
9
- <stop offset="100%" stop-color="#7c3aed"/>
10
- </linearGradient>
11
- <linearGradient id="featGrad" x1="0%" y1="0%" x2="100%" y2="100%">
12
- <stop offset="0%" stop-color="#7dd3fc"/>
13
- <stop offset="100%" stop-color="#0284c7"/>
14
- </linearGradient>
15
- <filter id="glow" x="-40%" y="-40%" width="180%" height="180%">
16
- <feGaussianBlur in="SourceGraphic" stdDeviation="2.5" result="blur"/>
17
- <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
18
- </filter>
19
- <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
20
- <feGaussianBlur in="SourceGraphic" stdDeviation="1.5" result="blur"/>
21
- <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
22
- </filter>
23
- </defs>
24
-
25
- <!-- 背景�?-->
26
- <circle cx="100" cy="100" r="96" fill="url(#bgGrad)"/>
27
-
28
- <!-- 同步外弧(上半,代表 sync 循环�?-->
29
- <path d="M 100,20 A 80,80 0 1,1 36,153"
30
- stroke="rgba(167,139,250,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
31
- <!-- 同步外弧(下半) -->
32
- <path d="M 36,153 A 80,80 0 0,1 164,153"
33
- stroke="rgba(56,189,248,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
34
- <!-- 同步箭头(上�?-->
35
- <path d="M 91,17 L 100,20 L 96,29"
36
- stroke="rgba(167,139,250,0.55)" stroke-width="2.5" fill="none"
37
- stroke-linecap="round" stroke-linejoin="round"/>
38
- <!-- 同步箭头(下�?-->
39
- <path d="M 163,145 L 164,154 L 155,151"
40
- stroke="rgba(56,189,248,0.55)" stroke-width="2.5" fill="none"
41
- stroke-linecap="round" stroke-linejoin="round"/>
42
-
43
- <!-- 主分支竖�?-->
44
- <line x1="76" y1="44" x2="76" y2="156"
45
- stroke="url(#mainGrad)" stroke-width="5.5" stroke-linecap="round"
46
- filter="url(#softGlow)"/>
47
-
48
- <!-- 特性分支曲线(分出�?-->
49
- <path d="M 76,80 C 98,80 130,96 130,120 L 130,140"
50
- stroke="url(#featGrad)" stroke-width="4.5" fill="none"
51
- stroke-linecap="round" filter="url(#softGlow)"/>
52
- <!-- 特性分支合并回主分�?-->
53
- <path d="M 130,140 C 130,156 105,159 76,155"
54
- stroke="url(#featGrad)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
55
-
56
- <!-- 主分支节�?-->
57
- <circle cx="76" cy="48" r="11" fill="#13103a" stroke="#c4b5fd" stroke-width="3" filter="url(#glow)"/>
58
- <circle cx="76" cy="48" r="5" fill="#ddd6fe"/>
59
-
60
- <circle cx="76" cy="84" r="11" fill="#13103a" stroke="#a78bfa" stroke-width="3"/>
61
- <circle cx="76" cy="84" r="5" fill="#c4b5fd"/>
62
-
63
- <circle cx="76" cy="120" r="11" fill="#13103a" stroke="#8b5cf6" stroke-width="3"/>
64
- <circle cx="76" cy="120" r="5" fill="#a78bfa"/>
65
-
66
- <circle cx="76" cy="155" r="11" fill="#13103a" stroke="#7c3aed" stroke-width="3" filter="url(#glow)"/>
67
- <circle cx="76" cy="155" r="5" fill="#8b5cf6"/>
68
-
69
- <!-- 特性分支节�?-->
70
- <circle cx="130" cy="115" r="11" fill="#13103a" stroke="#38bdf8" stroke-width="3" filter="url(#glow)"/>
71
- <circle cx="130" cy="115" r="5" fill="#7dd3fc"/>
72
-
73
- <circle cx="130" cy="143" r="11" fill="#13103a" stroke="#0ea5e9" stroke-width="3" filter="url(#glow)"/>
74
- <circle cx="130" cy="143" r="5" fill="#38bdf8"/>
1
+ <svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <radialGradient id="bgGrad" cx="38%" cy="32%" r="70%">
4
+ <stop offset="0%" stop-color="#1e1b4b"/>
5
+ <stop offset="100%" stop-color="#0d0b1e"/>
6
+ </radialGradient>
7
+ <linearGradient id="mainGrad" x1="0%" y1="0%" x2="0%" y2="100%">
8
+ <stop offset="0%" stop-color="#c4b5fd"/>
9
+ <stop offset="100%" stop-color="#7c3aed"/>
10
+ </linearGradient>
11
+ <linearGradient id="featGrad" x1="0%" y1="0%" x2="100%" y2="100%">
12
+ <stop offset="0%" stop-color="#7dd3fc"/>
13
+ <stop offset="100%" stop-color="#0284c7"/>
14
+ </linearGradient>
15
+ <filter id="glow" x="-40%" y="-40%" width="180%" height="180%">
16
+ <feGaussianBlur in="SourceGraphic" stdDeviation="2.5" result="blur"/>
17
+ <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
18
+ </filter>
19
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
20
+ <feGaussianBlur in="SourceGraphic" stdDeviation="1.5" result="blur"/>
21
+ <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- 背景�?-->
26
+ <circle cx="100" cy="100" r="96" fill="url(#bgGrad)"/>
27
+
28
+ <!-- 同步外弧(上半,代表 sync 循环�?-->
29
+ <path d="M 100,20 A 80,80 0 1,1 36,153"
30
+ stroke="rgba(167,139,250,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
31
+ <!-- 同步外弧(下半) -->
32
+ <path d="M 36,153 A 80,80 0 0,1 164,153"
33
+ stroke="rgba(56,189,248,0.18)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
34
+ <!-- 同步箭头(上�?-->
35
+ <path d="M 91,17 L 100,20 L 96,29"
36
+ stroke="rgba(167,139,250,0.55)" stroke-width="2.5" fill="none"
37
+ stroke-linecap="round" stroke-linejoin="round"/>
38
+ <!-- 同步箭头(下�?-->
39
+ <path d="M 163,145 L 164,154 L 155,151"
40
+ stroke="rgba(56,189,248,0.55)" stroke-width="2.5" fill="none"
41
+ stroke-linecap="round" stroke-linejoin="round"/>
42
+
43
+ <!-- 主分支竖�?-->
44
+ <line x1="76" y1="44" x2="76" y2="156"
45
+ stroke="url(#mainGrad)" stroke-width="5.5" stroke-linecap="round"
46
+ filter="url(#softGlow)"/>
47
+
48
+ <!-- 特性分支曲线(分出�?-->
49
+ <path d="M 76,80 C 98,80 130,96 130,120 L 130,140"
50
+ stroke="url(#featGrad)" stroke-width="4.5" fill="none"
51
+ stroke-linecap="round" filter="url(#softGlow)"/>
52
+ <!-- 特性分支合并回主分�?-->
53
+ <path d="M 130,140 C 130,156 105,159 76,155"
54
+ stroke="url(#featGrad)" stroke-width="4.5" fill="none" stroke-linecap="round"/>
55
+
56
+ <!-- 主分支节�?-->
57
+ <circle cx="76" cy="48" r="11" fill="#13103a" stroke="#c4b5fd" stroke-width="3" filter="url(#glow)"/>
58
+ <circle cx="76" cy="48" r="5" fill="#ddd6fe"/>
59
+
60
+ <circle cx="76" cy="84" r="11" fill="#13103a" stroke="#a78bfa" stroke-width="3"/>
61
+ <circle cx="76" cy="84" r="5" fill="#c4b5fd"/>
62
+
63
+ <circle cx="76" cy="120" r="11" fill="#13103a" stroke="#8b5cf6" stroke-width="3"/>
64
+ <circle cx="76" cy="120" r="5" fill="#a78bfa"/>
65
+
66
+ <circle cx="76" cy="155" r="11" fill="#13103a" stroke="#7c3aed" stroke-width="3" filter="url(#glow)"/>
67
+ <circle cx="76" cy="155" r="5" fill="#8b5cf6"/>
68
+
69
+ <!-- 特性分支节�?-->
70
+ <circle cx="130" cy="115" r="11" fill="#13103a" stroke="#38bdf8" stroke-width="3" filter="url(#glow)"/>
71
+ <circle cx="130" cy="115" r="5" fill="#7dd3fc"/>
72
+
73
+ <circle cx="130" cy="143" r="11" fill="#13103a" stroke="#0ea5e9" stroke-width="3" filter="url(#glow)"/>
74
+ <circle cx="130" cy="143" r="5" fill="#38bdf8"/>
75
75
  </svg>
@@ -110,7 +110,7 @@ async function startUIServer(noOpen = false, savePort = false) {
110
110
  let dirPath = process.cwd();
111
111
  try {
112
112
  if(showConsole) console.log(`记录最近打开目录`)
113
- const { stdout } = await execGitCommand('git rev-parse --show-toplevel');
113
+ const { stdout } = await execGitCommand(['rev-parse', '--show-toplevel']);
114
114
  const root = stdout?.trim();
115
115
  if (root) dirPath = root;
116
116
  } catch (_) {
@@ -290,7 +290,7 @@ async function startUIServer(noOpen = false, savePort = false) {
290
290
  }
291
291
 
292
292
  // 只获取porcelain格式状态,不再获取完整的git status
293
- const { stdout: porcelainOutput } = await execGitCommand('git status --porcelain --untracked-files=all');
293
+ const { stdout: porcelainOutput } = await execGitCommand(['status', '--porcelain', '--untracked-files=all']);
294
294
 
295
295
  // 广播到当前项目房间的所有客户端
296
296
  io.to(projectRoomId).emit('git_status_update', {
@@ -309,7 +309,7 @@ async function startUIServer(noOpen = false, savePort = false) {
309
309
  // 检查当前目录是否是Git仓库
310
310
  let isGitRepo = false;
311
311
  try {
312
- const { stdout } = await execGitCommand('git rev-parse --is-inside-work-tree', { log: false });
312
+ const { stdout } = await execGitCommand(['rev-parse', '--is-inside-work-tree'], { log: false });
313
313
  isGitRepo = stdout.trim() === 'true';
314
314
  } catch (error) {
315
315
  isGitRepo = false;
@@ -24,7 +24,7 @@ export function registerBranchStatusRoutes({
24
24
  // 获取当前分支 - 直接读取,不缓存(git symbolic-ref 极快,<5ms)
25
25
  app.get('/api/branch', async (req, res) => {
26
26
  try {
27
- const { stdout } = await execGitCommand('git symbolic-ref --short HEAD');
27
+ const { stdout } = await execGitCommand(['symbolic-ref', '--short', 'HEAD']);
28
28
  res.json({ branch: stdout.trim() });
29
29
  } catch (error) {
30
30
  res.status(500).json({ error: error.message });
@@ -70,11 +70,11 @@ export function registerBranchStatusRoutes({
70
70
  console.log(`使用5秒缓存的分支名: ${currentBranch} -> ${upstreamBranch}`);
71
71
  } else {
72
72
  // 直接读取,不再走5分钟长缓存
73
- const { stdout: branchOut } = await execGitCommand('git symbolic-ref --short HEAD');
73
+ const { stdout: branchOut } = await execGitCommand(['symbolic-ref', '--short', 'HEAD']);
74
74
  currentBranch = branchOut.trim();
75
75
 
76
76
  const { stdout: upstreamOut } = await execGitCommand(
77
- 'git rev-parse --abbrev-ref --symbolic-full-name @{u}',
77
+ ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'],
78
78
  { ignoreError: true }
79
79
  );
80
80
  upstreamBranch = upstreamOut.trim() || null;
@@ -88,7 +88,7 @@ export function registerBranchStatusRoutes({
88
88
  }
89
89
 
90
90
  const { stdout: aheadBehindOutput } = await execGitCommand(
91
- `git rev-list --left-right --count ${currentBranch}...${upstreamBranch}`
91
+ ['rev-list', '--left-right', '--count', `${currentBranch}...${upstreamBranch}`]
92
92
  );
93
93
  const [ahead, behind] = aheadBehindOutput.trim().split('\t').map(Number);
94
94
 
@@ -101,7 +101,7 @@ async function collectDiffForAi({ execGitCommand, getCurrentProjectPath, selecte
101
101
  let fileList = []
102
102
  try {
103
103
  // 1. 拿到工作区状态,识别 untracked 文件
104
- const { stdout: statusOut } = await execGitCommand('git status --porcelain=1 --untracked-files=all', cwdOpts)
104
+ const { stdout: statusOut } = await execGitCommand(['status', '--porcelain=1', '--untracked-files=all'], cwdOpts)
105
105
  const untracked = []
106
106
  const trackedChanges = []
107
107
  for (const line of (statusOut || '').split('\n')) {
@@ -129,9 +129,8 @@ async function collectDiffForAi({ execGitCommand, getCurrentProjectPath, selecte
129
129
  const batchSize = 20
130
130
  for (let i = 0; i < untracked.length; i += batchSize) {
131
131
  const batch = untracked.slice(i, i + batchSize)
132
- const quoted = batch.map(p => `"${p.replace(/"/g, '\\"')}"`).join(' ')
133
132
  try {
134
- await execGitCommand(`git add -N --force ${quoted}`, cwdOpts)
133
+ await execGitCommand(['add', '-N', '--force', ...batch], cwdOpts)
135
134
  } catch (e) {
136
135
  // 单批失败不影响整体
137
136
  console.warn('[generate-commit] git add -N failed for batch:', e?.message)
@@ -142,12 +141,13 @@ async function collectDiffForAi({ execGitCommand, getCurrentProjectPath, selecte
142
141
  // 3. 合并 staged + unstaged diff
143
142
  // 用 --no-color 避免 ANSI 干扰, --no-ext-diff 避免外接 diff 工具
144
143
  // 选择模式下用 `-- <paths>` 限定,避免拉取无关 staged 改动
145
- const pathArgs = selectedSet
146
- ? ' -- ' + [...selectedSet].map(p => `"${p.replace(/"/g, '\\"')}"`).join(' ')
147
- : ''
144
+ const pathArgs = selectedSet ? [...selectedSet] : []
145
+ const diffBase = ['diff', '--no-color', '--no-ext-diff']
146
+ const stagedArgs = ['diff', '--staged', '--no-color', '--no-ext-diff', ...(pathArgs.length ? ['--', ...pathArgs] : [])]
147
+ const unstagedArgs = [...diffBase, ...(pathArgs.length ? ['--', ...pathArgs] : [])]
148
148
  const [stagedRes, unstagedRes] = await Promise.all([
149
- execGitCommand(`git diff --staged --no-color --no-ext-diff${pathArgs}`, cwdOpts).catch(() => ({ stdout: '' })),
150
- execGitCommand(`git diff --no-color --no-ext-diff${pathArgs}`, cwdOpts).catch(() => ({ stdout: '' }))
149
+ execGitCommand(stagedArgs, cwdOpts).catch(() => ({ stdout: '' })),
150
+ execGitCommand(unstagedArgs, cwdOpts).catch(() => ({ stdout: '' }))
151
151
  ])
152
152
  let combined = ''
153
153
  if (stagedRes?.stdout) combined += stagedRes.stdout.trim() + '\n'
@@ -16,6 +16,12 @@ import path from 'path';
16
16
  import iconv from 'iconv-lite';
17
17
  import { spawn } from 'child_process';
18
18
 
19
+ // 把 "git config --global key value" 这种空格分隔命令拆成 argv 数组,
20
+ // 注意:简单 split 不处理引号/转义;保持与之前 shell 模式一致的语义。
21
+ function splitCommandArgs(command) {
22
+ return command.trim().split(/\s+/).filter(Boolean);
23
+ }
24
+
19
25
  export function registerExecRoutes({
20
26
  app,
21
27
  execGitCommand,
@@ -33,7 +39,7 @@ export function registerExecRoutes({
33
39
  }
34
40
 
35
41
  try {
36
- const { stdout = '', stderr = '' } = await execGitCommand(command, { log: false });
42
+ const { stdout = '', stderr = '' } = await execGitCommand(splitCommandArgs(command), { log: false });
37
43
  return res.json({ success: true, stdout, stderr });
38
44
  } catch (err) {
39
45
  return res.status(400).json({ success: false, error: err?.message || String(err) });
@@ -45,7 +45,7 @@ export function registerFsRoutes({
45
45
 
46
46
  // 检查当前目录是否是Git仓库
47
47
  try {
48
- await execGitCommand('git rev-parse --is-inside-work-tree');
48
+ await execGitCommand(['rev-parse', '--is-inside-work-tree']);
49
49
  } catch (error) {
50
50
  return res.status(400).json({
51
51
  error: '当前目录不是一个Git仓库',
@@ -86,7 +86,7 @@ export function registerFsRoutes({
86
86
 
87
87
  // 检查新目录是否是Git仓库
88
88
  try {
89
- await execGitCommand('git rev-parse --is-inside-work-tree');
89
+ await execGitCommand(['rev-parse', '--is-inside-work-tree']);
90
90
 
91
91
  // 更新全局变量
92
92
  setCurrentProjectPath(newProjectPath);
@@ -34,10 +34,11 @@ export function registerGitDiffRoutes({
34
34
  return res.status(400).json({ error: '缺少文件路径参数' });
35
35
  }
36
36
 
37
- const diffCommand = `git diff -- "${filePath}"`;
37
+ const diffArgs = ['diff', '--', filePath];
38
38
 
39
- // 使用优化的检查函数
40
- const skipCheck = await checkShouldSkipDiff(filePath, diffCommand);
39
+ // 使用优化的检查函数(diffCommand 用于内部 numstat 检测的字符串转换,
40
+ // 实际走 git 时用 argv 数组,避免 Windows cmd.exe 拼引号问题)
41
+ const skipCheck = await checkShouldSkipDiff(filePath, `git diff -- "${filePath}"`);
41
42
  if (skipCheck.shouldSkip) {
42
43
  return res.json({
43
44
  diff: skipCheck.reason,
@@ -47,7 +48,7 @@ export function registerGitDiffRoutes({
47
48
  }
48
49
 
49
50
  // 执行git diff命令获取文件差异
50
- const { stdout } = await execGitCommand(diffCommand);
51
+ const { stdout } = await execGitCommand(diffArgs);
51
52
 
52
53
  // 检查实际diff大小
53
54
  const sizeCheck = checkDiffSize(stdout, 500);
@@ -72,10 +73,10 @@ export function registerGitDiffRoutes({
72
73
  return res.status(400).json({ error: '缺少文件路径参数' });
73
74
  }
74
75
 
75
- const diffCommand = `git diff --cached -- "${filePath}"`;
76
+ const diffArgs = ['diff', '--cached', '--', filePath];
76
77
 
77
78
  // 使用优化的检查函数
78
- const skipCheck = await checkShouldSkipDiff(filePath, diffCommand);
79
+ const skipCheck = await checkShouldSkipDiff(filePath, `git diff --cached -- "${filePath}"`);
79
80
  if (skipCheck.shouldSkip) {
80
81
  return res.json({
81
82
  diff: skipCheck.reason,
@@ -85,7 +86,7 @@ export function registerGitDiffRoutes({
85
86
  }
86
87
 
87
88
  // 执行git diff --cached命令获取已暂存文件差异
88
- const { stdout } = await execGitCommand(diffCommand);
89
+ const { stdout } = await execGitCommand(diffArgs);
89
90
 
90
91
  // 检查实际diff大小
91
92
  const sizeCheck = checkDiffSize(stdout, 500);
@@ -105,7 +106,7 @@ export function registerGitDiffRoutes({
105
106
  // 获取全量 diff(git diff HEAD,含已暂存与未暂存的所有变更)
106
107
  app.get('/api/diff-head', async (req, res) => {
107
108
  try {
108
- const { stdout } = await execGitCommand('git diff HEAD');
109
+ const { stdout } = await execGitCommand(['diff', 'HEAD']);
109
110
  const MAX = 500 * 1024;
110
111
  const content = stdout.length > MAX
111
112
  ? stdout.slice(0, MAX) + '\n\n[内容过大,已截断]'
@@ -172,7 +173,7 @@ export function registerGitDiffRoutes({
172
173
 
173
174
  let sizeBytes = 0;
174
175
  try {
175
- const { stdout: sizeOut } = await execGitCommand(`git cat-file -s "${spec}"`, { log: false });
176
+ const { stdout: sizeOut } = await execGitCommand(['cat-file', '-s', spec], { log: false });
176
177
  sizeBytes = parseInt(String(sizeOut).trim(), 10) || 0;
177
178
  } catch (e) {
178
179
  return res.json({ success: true, notFound: true, content: '' });
@@ -187,7 +188,7 @@ export function registerGitDiffRoutes({
187
188
  });
188
189
  }
189
190
 
190
- const { stdout } = await execGitCommand(`git show "${spec}"`, { log: false });
191
+ const { stdout } = await execGitCommand(['show', spec], { log: false });
191
192
  return res.json({ success: true, content: stdout ?? '' });
192
193
  } catch (error) {
193
194
  res.status(500).json({ success: false, error: error.message });
@@ -253,7 +254,7 @@ export function registerGitDiffRoutes({
253
254
  }
254
255
 
255
256
  // 检查文件状态:未跟踪文件需要删除,修改文件需要恢复
256
- const { stdout: statusOutput } = await execGitCommand(`git status --porcelain -- "${filePath}"`);
257
+ const { stdout: statusOutput } = await execGitCommand(['status', '--porcelain', '--', filePath]);
257
258
 
258
259
  // 未跟踪的文件 (??), 需要删除它
259
260
  if (statusOutput.startsWith('??')) {
@@ -270,12 +271,12 @@ export function registerGitDiffRoutes({
270
271
  // 已暂存的文件,先取消暂存
271
272
  else if (statusOutput.startsWith('A ') || statusOutput.startsWith('M ') || statusOutput.startsWith('D ')) {
272
273
  // 先取消暂存
273
- await execGitCommand(`git reset HEAD -- "${filePath}"`);
274
+ await execGitCommand(['reset', 'HEAD', '--', filePath]);
274
275
  }
275
276
 
276
277
  // 已修改文件,取消所有本地修改
277
278
  if (statusOutput) {
278
- await execGitCommand(`git checkout -- "${filePath}"`);
279
+ await execGitCommand(['checkout', '--', filePath]);
279
280
  return res.json({ success: true, message: '文件修改已撤回' });
280
281
  } else {
281
282
  return res.status(400).json({
@@ -307,7 +308,7 @@ export function registerGitDiffRoutes({
307
308
  for (const filePath of filePaths) {
308
309
  try {
309
310
  // 检查文件状态:未跟踪 ??、已暂存 A/M/D、已修改(空状态会返回空字符串)
310
- const { stdout: statusOutput } = await execGitCommand(`git status --porcelain -- "${filePath}"`)
311
+ const { stdout: statusOutput } = await execGitCommand(['status', '--porcelain', '--', filePath])
311
312
 
312
313
  // 未跟踪的文件 (??) → 直接删除
313
314
  if (statusOutput.startsWith('??')) {
@@ -324,12 +325,12 @@ export function registerGitDiffRoutes({
324
325
 
325
326
  // 已暂存的文件,先取消暂存(不影响工作区)
326
327
  if (statusOutput.startsWith('A ') || statusOutput.startsWith('M ') || statusOutput.startsWith('D ')) {
327
- await execGitCommand(`git reset HEAD -- "${filePath}"`)
328
+ await execGitCommand(['reset', 'HEAD', '--', filePath])
328
329
  }
329
330
 
330
331
  // 已修改文件:丢弃工作区修改
331
332
  if (statusOutput) {
332
- await execGitCommand(`git checkout -- "${filePath}"`)
333
+ await execGitCommand(['checkout', '--', filePath])
333
334
  results.push({ path: filePath, success: true, message: '文件修改已撤回' })
334
335
  successCount++
335
336
  } else {