zen-gitsync 2.13.14 → 2.13.16
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 +2 -0
- package/package.json +6 -3
- package/scripts/README_COLOR_CONVERTER.md +196 -196
- package/scripts/README_FONTSIZE_CONVERTER.md +278 -278
- package/scripts/README_SPACING_CONVERTER.md +126 -126
- package/scripts/README_STYLE_VARS.md +180 -180
- package/src/ui/public/assets/{EditorView-S6HDGyLD.js → EditorView-CRpjzBS1.js} +0 -0
- package/src/ui/public/assets/{SourceMapView-C10WxgGh.js → SourceMapView-ByHkwMwM.js} +1 -1
- package/src/ui/public/assets/WorkbenchView-Dhle7BQe.css +1 -0
- package/src/ui/public/assets/WorkbenchView-cBXTpeWC.js +9 -0
- package/src/ui/public/assets/{_plugin-vue_export-helper-8__zdPsB.js → _plugin-vue_export-helper-CT67BnrS.js} +2 -2
- package/src/ui/public/assets/{index-D-XpqSmG.js → index-C19XAWFW.js} +15 -14
- package/src/ui/public/assets/index-C3VghkAQ.css +1 -0
- package/src/ui/public/favicon.svg +75 -75
- package/src/ui/public/index.html +20 -20
- package/src/ui/public/logo.svg +74 -74
- package/src/ui/server/index.js +2 -1
- package/src/ui/server/routes/exec.js +10 -9
- package/src/ui/server/routes/status.js +16 -17
- package/src/ui/server/routes/terminal.js +12 -13
- package/src/ui/server/routes/workbench.js +433 -33
- package/src/ui/server/utils/shellQuote.js +68 -0
- package/src/ui/server/utils/shellQuote.test.js +110 -0
- package/src/utils/index.js +60 -29
- package/src/utils/parseCwdArg.test.js +86 -0
- package/src/ui/public/assets/WorkbenchView-7COIW5s0.js +0 -9
- package/src/ui/public/assets/WorkbenchView-zVvptY6a.css +0 -1
- package/src/ui/public/assets/index-CHX2_Fog.css +0 -1
|
@@ -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>
|
package/src/ui/public/index.html
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
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-
|
|
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-C19XAWFW.js"></script>
|
|
14
14
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CMxvf4Kt.js">
|
|
15
15
|
<link rel="modulepreload" crossorigin href="/assets/vendor-D72Z0Jmi.js">
|
|
16
|
-
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-
|
|
16
|
+
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-CT67BnrS.js">
|
|
17
17
|
<link rel="stylesheet" crossorigin href="/assets/vendor-F3eVqHe1.css">
|
|
18
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
-
</head>
|
|
20
|
-
<body>
|
|
21
|
-
<div id="app"></div>
|
|
22
|
-
</body>
|
|
23
|
-
</html>
|
|
18
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C3VghkAQ.css">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<div id="app"></div>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
package/src/ui/public/logo.svg
CHANGED
|
@@ -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>
|
package/src/ui/server/index.js
CHANGED
|
@@ -134,7 +134,8 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
134
134
|
execGitCommand,
|
|
135
135
|
addCommandToHistory,
|
|
136
136
|
getCurrentProjectPath: () => currentProjectPath,
|
|
137
|
-
|
|
137
|
+
// 用 pre-increment 从 1 起,避免首进程拿到 id=0(0 在 `if (processId)` 这类真值检查里会被吞)
|
|
138
|
+
nextProcessId: () => ++processIdCounter,
|
|
138
139
|
runningProcesses
|
|
139
140
|
});
|
|
140
141
|
|
|
@@ -123,20 +123,21 @@ export function registerExecRoutes({
|
|
|
123
123
|
// npm、node、git 等现代工具都输出 UTF-8
|
|
124
124
|
const isWindows = process.platform === 'win32';
|
|
125
125
|
const cmdBuiltins = ['dir', 'type', 'set', 'path', 'cd', 'md', 'rd', 'del', 'copy', 'move', 'ren'];
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
// echo 命令特殊处理:如果包含变量替换(如 {{xxx}}),说明内容可能已经是 UTF-8,不转换
|
|
128
|
-
const
|
|
128
|
+
const trimmed = command.trim().toLowerCase();
|
|
129
|
+
const firstToken = trimmed.split(/\s+/, 1)[0] || '';
|
|
130
|
+
const isEchoCommand = firstToken === 'echo';
|
|
129
131
|
const hasVariableSubstitution = isEchoCommand && (
|
|
130
|
-
command.includes('{{') ||
|
|
131
|
-
command.includes('${') ||
|
|
132
|
+
command.includes('{{') ||
|
|
133
|
+
command.includes('${') ||
|
|
132
134
|
command.includes('%') // Windows 环境变量
|
|
133
135
|
);
|
|
134
|
-
|
|
136
|
+
|
|
137
|
+
// 必须按 token 边界判断,避免 'dir' 误匹配 'directory'、'path' 误匹配 'path-to'
|
|
135
138
|
const needsGbkConversion = isWindows && (
|
|
136
|
-
cmdBuiltins.
|
|
137
|
-
|
|
138
|
-
command.trim().toLowerCase() === builtin
|
|
139
|
-
) || (isEchoCommand && !hasVariableSubstitution) // echo 只在没有变量替换时才转换
|
|
139
|
+
cmdBuiltins.includes(firstToken) ||
|
|
140
|
+
(isEchoCommand && !hasVariableSubstitution) // echo 只在没有变量替换时才转换
|
|
140
141
|
);
|
|
141
142
|
|
|
142
143
|
console.log(`[流式输出] 命令: ${command.substring(0, 50)}, 需要GBK转换: ${needsGbkConversion}`);
|
|
@@ -33,32 +33,31 @@ export function registerStatusRoutes({
|
|
|
33
33
|
app.get('/api/status_porcelain', async (req, res) => {
|
|
34
34
|
try {
|
|
35
35
|
const { stdout } = await execGitCommand('git status --porcelain --untracked-files=all');
|
|
36
|
-
// 检测是否处于 MERGING 状态(MERGE_HEAD
|
|
36
|
+
// 检测是否处于 MERGING 状态(MERGE_HEAD 存在)
|
|
37
37
|
let isMergeInProgress = false;
|
|
38
38
|
let mergeMessage = '';
|
|
39
39
|
try {
|
|
40
40
|
const { stdout: mergeHead } = await execGitCommand('git rev-parse -q --verify MERGE_HEAD');
|
|
41
41
|
isMergeInProgress = mergeHead.trim().length > 0;
|
|
42
|
-
if (isMergeInProgress) {
|
|
43
|
-
// 读取 Git 自动生成的合并提交信息
|
|
44
|
-
try {
|
|
45
|
-
const { stdout: gitDir } = await execGitCommand('git rev-parse --git-dir');
|
|
46
|
-
const mergeMsgPath = path.resolve(gitDir.trim(), 'MERGE_MSG');
|
|
47
|
-
const raw = await fs.readFile(mergeMsgPath, 'utf-8');
|
|
48
|
-
// 过滤掉以 # 开头的注释行,取第一个非空行
|
|
49
|
-
mergeMessage = raw
|
|
50
|
-
.split('\n')
|
|
51
|
-
.filter(line => line.trim() && !line.startsWith('#'))
|
|
52
|
-
.join('\n')
|
|
53
|
-
.trim();
|
|
54
|
-
} catch (_) {
|
|
55
|
-
// MERGE_MSG 不存在时忽略
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
42
|
} catch (_) {
|
|
59
43
|
// MERGE_HEAD 不存在时命令会报错,属正常情况
|
|
60
44
|
isMergeInProgress = false;
|
|
61
45
|
}
|
|
46
|
+
if (isMergeInProgress) {
|
|
47
|
+
try {
|
|
48
|
+
const { stdout: gitDir } = await execGitCommand('git rev-parse --git-dir');
|
|
49
|
+
const mergeMsgPath = path.resolve(gitDir.trim(), 'MERGE_MSG');
|
|
50
|
+
const raw = await fs.readFile(mergeMsgPath, 'utf-8');
|
|
51
|
+
// 过滤掉以 # 开头的注释行,拼接所有非空非注释行(保留多段信息如合并分支列表)
|
|
52
|
+
mergeMessage = raw
|
|
53
|
+
.split('\n')
|
|
54
|
+
.filter(line => line.trim() && !line.startsWith('#'))
|
|
55
|
+
.join('\n')
|
|
56
|
+
.trim();
|
|
57
|
+
} catch (_) {
|
|
58
|
+
// MERGE_MSG 不存在/无权限时忽略
|
|
59
|
+
}
|
|
60
|
+
}
|
|
62
61
|
res.json({ status: stdout, isMergeInProgress, mergeMessage });
|
|
63
62
|
} catch (error) {
|
|
64
63
|
res.status(500).json({ error: error.message });
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
//
|
|
15
15
|
import { spawn, exec } from 'child_process';
|
|
16
|
+
import { psEscape, appleEscape, shQuote } from '../utils/shellQuote.js';
|
|
16
17
|
|
|
17
18
|
export function registerTerminalRoutes({
|
|
18
19
|
app,
|
|
@@ -25,7 +26,6 @@ export function registerTerminalRoutes({
|
|
|
25
26
|
|
|
26
27
|
if (process.platform === 'win32') {
|
|
27
28
|
const cmdToRun = String(command || '').trim();
|
|
28
|
-
const safeWorkingDir = String(targetDir).replace(/"/g, '""');
|
|
29
29
|
|
|
30
30
|
const splitArgs = (input) => {
|
|
31
31
|
const s = String(input || '');
|
|
@@ -59,6 +59,7 @@ export function registerTerminalRoutes({
|
|
|
59
59
|
const tokens = splitArgs(cmdToRun);
|
|
60
60
|
const isStartCommand = tokens.length > 0 && String(tokens[0]).toLowerCase() === 'start';
|
|
61
61
|
|
|
62
|
+
// PowerShell 转义全部走 shellQuote.psEscape ($ ` " 都会被处理)
|
|
62
63
|
let psScript;
|
|
63
64
|
if (isStartCommand) {
|
|
64
65
|
const args = tokens.slice(1);
|
|
@@ -69,19 +70,14 @@ export function registerTerminalRoutes({
|
|
|
69
70
|
const exe = candidateExe && !isUrl(candidateExe) ? String(candidateExe) : null;
|
|
70
71
|
|
|
71
72
|
if (!exe && candidateUrl) {
|
|
72
|
-
|
|
73
|
-
psScript = `$p = Start-Process -FilePath "${safeUrl}" -WorkingDirectory "${safeWorkingDir}" -PassThru; Write-Output $p.Id`;
|
|
73
|
+
psScript = `$p = Start-Process -FilePath "${psEscape(candidateUrl)}" -WorkingDirectory "${psEscape(targetDir)}" -PassThru; Write-Output $p.Id`;
|
|
74
74
|
} else if (exe && candidateUrl) {
|
|
75
|
-
|
|
76
|
-
const safeUrl = String(candidateUrl).replace(/"/g, '""');
|
|
77
|
-
psScript = `$p = Start-Process -FilePath "${safeExe}" -ArgumentList "${safeUrl}" -WorkingDirectory "${safeWorkingDir}" -PassThru; Write-Output $p.Id`;
|
|
75
|
+
psScript = `$p = Start-Process -FilePath "${psEscape(exe)}" -ArgumentList "${psEscape(candidateUrl)}" -WorkingDirectory "${psEscape(targetDir)}" -PassThru; Write-Output $p.Id`;
|
|
78
76
|
} else {
|
|
79
|
-
|
|
80
|
-
psScript = `$p = Start-Process -FilePath "cmd.exe" -ArgumentList "/C", "${safeCmd}" -WorkingDirectory "${safeWorkingDir}" -WindowStyle Hidden -PassThru; Write-Output $p.Id`;
|
|
77
|
+
psScript = `$p = Start-Process -FilePath "cmd.exe" -ArgumentList "/C", "${psEscape(cmdToRun)}" -WorkingDirectory "${psEscape(targetDir)}" -WindowStyle Hidden -PassThru; Write-Output $p.Id`;
|
|
81
78
|
}
|
|
82
79
|
} else {
|
|
83
|
-
|
|
84
|
-
psScript = `$p = Start-Process -FilePath "cmd.exe" -ArgumentList "/K", "${safeCmd}" -WorkingDirectory "${safeWorkingDir}" -PassThru; Write-Output $p.Id`;
|
|
80
|
+
psScript = `$p = Start-Process -FilePath "cmd.exe" -ArgumentList "/K", "${psEscape(cmdToRun)}" -WorkingDirectory "${psEscape(targetDir)}" -PassThru; Write-Output $p.Id`;
|
|
85
81
|
}
|
|
86
82
|
|
|
87
83
|
return await new Promise((resolve, reject) => {
|
|
@@ -118,8 +114,10 @@ export function registerTerminalRoutes({
|
|
|
118
114
|
}
|
|
119
115
|
|
|
120
116
|
if (process.platform === 'darwin') {
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
// AppleScript 转义统一走 shellQuote.appleEscape (\ " 都会被处理)
|
|
118
|
+
const script = `tell application "Terminal" to do script "cd ${appleEscape(targetDir)} && ${appleEscape(command.trim())}"`;
|
|
119
|
+
// 外层用单引号包,把脚本里可能出现的单引号转义为 '\''
|
|
120
|
+
exec(`osascript -e ${shQuote(script)}`, (error) => {
|
|
123
121
|
if (error) {
|
|
124
122
|
console.error('打开终端失败:', error);
|
|
125
123
|
}
|
|
@@ -127,7 +125,8 @@ export function registerTerminalRoutes({
|
|
|
127
125
|
return { pid: null };
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
|
|
128
|
+
// Linux: 用 sh 单引号包命令行,单引号内不解释 $ ` " \ ,只把单引号自身 '\''
|
|
129
|
+
const terminalCommand = `gnome-terminal -- bash -c ${shQuote(`cd ${targetDir} && ${command.trim()}; exec bash`)} || xterm -e ${shQuote(`cd ${targetDir} && ${command.trim()}; bash`)}`;
|
|
131
130
|
exec(terminalCommand, (error) => {
|
|
132
131
|
if (error) {
|
|
133
132
|
console.error('打开终端失败:', error);
|