zen-gitsync 2.12.9 → 2.13.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/package.json +1 -1
- 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-9Q0gSlr6.js +0 -0
- package/src/ui/public/assets/SourceMapView-Dxmg8KPB.js +3 -0
- package/src/ui/public/assets/WorkbenchView-CYC_l23l.js +2 -0
- package/src/ui/public/assets/WorkbenchView-DauLIzog.css +1 -0
- package/src/ui/public/assets/{_plugin-vue_export-helper-DMUTnP0C.js → _plugin-vue_export-helper-K0RsuraF.js} +3 -3
- package/src/ui/public/assets/{css.worker-Wv5dxAWO.js → css.worker-CvXBzhp8.js} +1 -1
- package/src/ui/public/assets/{html.worker-CQP8QQsS.js → html.worker-BO6WuOEO.js} +1 -1
- package/src/ui/public/assets/index-CGnU7zDA.js +66 -0
- package/src/ui/public/assets/index-DEEcURiV.css +1 -0
- package/src/ui/public/assets/{json.worker-DzV-CpCQ.js → json.worker-BkJRGcCJ.js} +1 -1
- package/src/ui/public/assets/{ts.worker-Dth06zuC.js → ts.worker-B0J26iPs.js} +15 -15
- package/src/ui/public/assets/vendor-DpYOE9sy.css +1 -0
- package/src/ui/public/assets/{vendor-C1sPhIEb.js → vendor-vsQ98rZk.js} +214 -207
- package/src/ui/public/favicon.svg +75 -75
- package/src/ui/public/index.html +23 -23
- package/src/ui/public/logo.svg +74 -74
- package/src/ui/server/routes/npm.js +170 -1
- package/src/ui/server/routes/workbench.js +1702 -1068
- package/src/ui/public/assets/EditorView-C4DezJRA.js +0 -0
- package/src/ui/public/assets/SourceMapView-B521sL_k.js +0 -3
- package/src/ui/public/assets/WorkbenchView-75x9qygA.js +0 -1
- package/src/ui/public/assets/WorkbenchView-Dc9vThI8.css +0 -1
- package/src/ui/public/assets/index-BCIFnj7e.css +0 -1
- package/src/ui/public/assets/index-cS1g7H--.js +0 -65
- package/src/ui/public/assets/vendor-B2yudN8R.css +0 -1
- /package/src/ui/public/assets/{editor.worker-Bd9IXS8d.js → editor.worker-Cn2oRESe.js} +0 -0
- /package/src/ui/public/assets/{rolldown-runtime-BM3Ffeng.js → rolldown-runtime-CMxvf4Kt.js} +0 -0
|
@@ -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-
|
|
14
|
-
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-
|
|
15
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/vendor-
|
|
18
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
-
</head>
|
|
20
|
-
<body>
|
|
21
|
-
<div id="app"></div>
|
|
22
|
-
</body>
|
|
23
|
-
</html>
|
|
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-CGnU7zDA.js"></script>
|
|
14
|
+
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CMxvf4Kt.js">
|
|
15
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-vsQ98rZk.js">
|
|
16
|
+
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-K0RsuraF.js">
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/vendor-DpYOE9sy.css">
|
|
18
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DEEcURiV.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>
|
|
@@ -16,12 +16,181 @@ import express from 'express';
|
|
|
16
16
|
import fs from 'fs/promises';
|
|
17
17
|
import fsSync from 'fs';
|
|
18
18
|
import path from 'path';
|
|
19
|
-
import { exec } from 'child_process';
|
|
19
|
+
import { exec, spawn } from 'child_process';
|
|
20
|
+
import https from 'https';
|
|
21
|
+
import { fileURLToPath } from 'url';
|
|
22
|
+
|
|
23
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
24
|
+
const __dirname = path.dirname(__filename);
|
|
20
25
|
|
|
21
26
|
export function registerNpmRoutes({
|
|
22
27
|
app,
|
|
23
28
|
getCurrentProjectPath
|
|
24
29
|
}) {
|
|
30
|
+
// 标记是否有升级任务在跑(防并发)
|
|
31
|
+
let activeUpgrade = false;
|
|
32
|
+
|
|
33
|
+
// ========== 应用自升级相关 API ==========
|
|
34
|
+
|
|
35
|
+
// 当前安装的版本(从外层 package.json 读取)
|
|
36
|
+
function getCurrentVersion() {
|
|
37
|
+
try {
|
|
38
|
+
// src/ui/server/routes/npm.js -> ../../../../package.json
|
|
39
|
+
const pkgPath = path.resolve(__dirname, '../../../..', 'package.json')
|
|
40
|
+
if (fsSync.existsSync(pkgPath)) {
|
|
41
|
+
const pkg = JSON.parse(fsSync.readFileSync(pkgPath, 'utf8'))
|
|
42
|
+
return pkg.version || '0.0.0'
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error('读取本地 package.json 版本失败:', err)
|
|
46
|
+
}
|
|
47
|
+
return '0.0.0'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 简单的 semver 比较:a > b 返回 1, a < b 返回 -1, 相等返回 0
|
|
51
|
+
function compareSemver(a, b) {
|
|
52
|
+
const pa = a.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0)
|
|
53
|
+
const pb = b.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0)
|
|
54
|
+
for (let i = 0; i < 3; i++) {
|
|
55
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return 1
|
|
56
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return -1
|
|
57
|
+
}
|
|
58
|
+
return 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 缓存 npm registry latest 结果 10 分钟
|
|
62
|
+
let latestVersionCache = { value: null, at: 0 }
|
|
63
|
+
const LATEST_TTL_MS = 10 * 60 * 1000
|
|
64
|
+
|
|
65
|
+
function fetchLatestFromRegistry() {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const req = https.get(
|
|
68
|
+
'https://registry.npmjs.org/zen-gitsync/latest',
|
|
69
|
+
{ timeout: 5000, headers: { 'User-Agent': 'zen-gitsync-app' } },
|
|
70
|
+
(res) => {
|
|
71
|
+
let data = ''
|
|
72
|
+
res.on('data', chunk => { data += chunk })
|
|
73
|
+
res.on('end', () => {
|
|
74
|
+
if (res.statusCode !== 200) {
|
|
75
|
+
return reject(new Error(`registry 返回状态 ${res.statusCode}`))
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const pkg = JSON.parse(data)
|
|
79
|
+
resolve(pkg.version || null)
|
|
80
|
+
} catch (e) {
|
|
81
|
+
reject(new Error('解析 registry 响应失败'))
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
req.on('timeout', () => {
|
|
87
|
+
req.destroy(new Error('registry 请求超时'))
|
|
88
|
+
})
|
|
89
|
+
req.on('error', err => reject(err))
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function getLatestVersion() {
|
|
94
|
+
const now = Date.now()
|
|
95
|
+
if (latestVersionCache.value && now - latestVersionCache.at < LATEST_TTL_MS) {
|
|
96
|
+
return latestVersionCache.value
|
|
97
|
+
}
|
|
98
|
+
const v = await fetchLatestFromRegistry()
|
|
99
|
+
latestVersionCache = { value: v, at: now }
|
|
100
|
+
return v
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// GET /api/app-version
|
|
104
|
+
app.get('/api/app-version', async (_req, res) => {
|
|
105
|
+
const current = getCurrentVersion()
|
|
106
|
+
try {
|
|
107
|
+
const latest = await getLatestVersion()
|
|
108
|
+
const hasUpdate = !!latest && compareSemver(latest, current) > 0
|
|
109
|
+
res.json({ success: true, current, latest, hasUpdate })
|
|
110
|
+
} catch (err) {
|
|
111
|
+
// 拉取失败时仍返回当前版本,前端据此决定是否显示升级按钮
|
|
112
|
+
res.json({
|
|
113
|
+
success: false,
|
|
114
|
+
current,
|
|
115
|
+
latest: null,
|
|
116
|
+
hasUpdate: false,
|
|
117
|
+
error: err.message
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
// POST /api/app-upgrade - 流式 NDJSON: { type: 'stdout'|'stderr'|'done'|'error', ... }
|
|
123
|
+
app.post('/api/app-upgrade', (req, res) => {
|
|
124
|
+
// 防并发:同一时刻只允许一个升级任务
|
|
125
|
+
if (activeUpgrade) {
|
|
126
|
+
res.status(409).json({ success: false, error: '已有升级任务在进行中' })
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
res.setHeader('Content-Type', 'application/x-ndjson; charset=utf-8')
|
|
131
|
+
res.setHeader('Cache-Control', 'no-cache')
|
|
132
|
+
res.setHeader('Connection', 'keep-alive')
|
|
133
|
+
res.flushHeaders?.()
|
|
134
|
+
|
|
135
|
+
const send = (obj) => {
|
|
136
|
+
res.write(JSON.stringify(obj) + '\n')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Windows 上 npm install -g 通常不需要管理员;*nix 需要 sudo。
|
|
140
|
+
// 用 sudo -n(非交互式)检测是否可免密,失败时让用户用 sudo 重启 GUI
|
|
141
|
+
const isWin = process.platform === 'win32'
|
|
142
|
+
const npmCmd = isWin ? 'npm.cmd' : 'npm'
|
|
143
|
+
const args = ['install', '-g', 'zen-gitsync', '--registry', 'https://registry.npmjs.org/']
|
|
144
|
+
const cmd = isWin ? npmCmd : 'sudo'
|
|
145
|
+
const finalArgs = isWin ? args : ['-n', npmCmd, ...args]
|
|
146
|
+
|
|
147
|
+
activeUpgrade = send
|
|
148
|
+
const cleanup = () => { activeUpgrade = null }
|
|
149
|
+
|
|
150
|
+
let child
|
|
151
|
+
try {
|
|
152
|
+
child = spawn(cmd, finalArgs, {
|
|
153
|
+
env: { ...process.env, FORCE_COLOR: '0' },
|
|
154
|
+
windowsHide: true,
|
|
155
|
+
// Windows 下调用 .cmd 必须 shell:true
|
|
156
|
+
shell: isWin
|
|
157
|
+
})
|
|
158
|
+
} catch (err) {
|
|
159
|
+
send({ type: 'error', message: `启动升级进程失败: ${err.message}` })
|
|
160
|
+
send({ type: 'done', code: -1 })
|
|
161
|
+
res.end()
|
|
162
|
+
cleanup()
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
send({ type: 'stdout', message: `$ ${cmd} ${finalArgs.join(' ')}\n` })
|
|
167
|
+
|
|
168
|
+
child.stdout.on('data', (buf) => send({ type: 'stdout', message: buf.toString() }))
|
|
169
|
+
child.stderr.on('data', (buf) => send({ type: 'stderr', message: buf.toString() }))
|
|
170
|
+
|
|
171
|
+
child.on('error', (err) => {
|
|
172
|
+
send({ type: 'error', message: `升级进程错误: ${err.message}` })
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
child.on('close', (code) => {
|
|
176
|
+
if (code === 0) {
|
|
177
|
+
send({ type: 'stdout', message: '\n✅ 升级完成,新版本已全局安装。\n' })
|
|
178
|
+
// 清理缓存,强制下次重新拉 latest
|
|
179
|
+
latestVersionCache = { value: null, at: 0 }
|
|
180
|
+
} else {
|
|
181
|
+
let hint = ''
|
|
182
|
+
if (!isWin) {
|
|
183
|
+
hint = '(提示:在 macOS/Linux 上全局安装需要 sudo,请用管理员权限重启 GUI 后再试)'
|
|
184
|
+
}
|
|
185
|
+
send({ type: 'error', message: `\n升级失败,退出码 ${code}${hint ? ' ' + hint : ''}\n` })
|
|
186
|
+
}
|
|
187
|
+
send({ type: 'done', code })
|
|
188
|
+
res.end()
|
|
189
|
+
cleanup()
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
|
|
25
194
|
// 读取 package.json 文件内容
|
|
26
195
|
app.post('/api/read-package-json', express.json(), async (req, res) => {
|
|
27
196
|
try {
|