zen-gitsync 2.13.28 → 2.13.30
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 -2
- 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/AppVersionBadge-CFkZrkhd.js +2 -0
- package/src/ui/public/assets/{AppVersionBadge-CTUXSSX1.css → AppVersionBadge-KZ64lrZQ.css} +1 -1
- package/src/ui/public/assets/BranchSelector-BzaBCj1X.js +1 -0
- package/src/ui/public/assets/CommandConsole-DKwcJRbO.js +17 -0
- package/src/ui/public/assets/CommitForm-w_CCHowb.js +6 -0
- package/src/ui/public/assets/CustomCommandManager-C81Su49z.js +1 -0
- package/src/ui/public/assets/EditorView-Do6ivdLH.js +0 -0
- package/src/ui/public/assets/FileDiffViewer-CXMo-Rez.js +13 -0
- package/src/ui/public/assets/{FlowExecutionViewer-DAsEnHsE.js → FlowExecutionViewer-Bhcnqca8.js} +1 -1
- package/src/ui/public/assets/FlowOrchestrationWorkspace-Cb6C2RyD.js +21 -0
- package/src/ui/public/assets/GitStatus-D90r1nV4.js +6 -0
- package/src/ui/public/assets/ImagePreview-kHYBPYW5.js +1 -0
- package/src/ui/public/assets/LogList-D6nSWEwN.js +7 -0
- package/src/ui/public/assets/ProjectStartupButton-BliaT11B.js +1 -0
- package/src/ui/public/assets/RemoteRepoCard-CUs9RQZg.js +1 -0
- package/src/ui/public/assets/ResetToRemoteButton-BBsIG2FU.js +1 -0
- package/src/ui/public/assets/SourceMapView-Cvp-7LtP.js +3 -0
- package/src/ui/public/assets/TemplateManager-Clov9VqY.js +1 -0
- package/src/ui/public/assets/UserInputNode-yVqO69ll.js +1 -0
- package/src/ui/public/assets/WorkbenchView-BDYbbkM1.js +12 -0
- package/src/ui/public/assets/WorkbenchView-zUE7sv6z.css +1 -0
- package/src/ui/public/assets/{_plugin-vue_export-helper-CHzCpi8c.js → _plugin-vue_export-helper-CpTW8798.js} +3 -3
- package/src/ui/public/assets/element-plus-CRTdimvR.js +24 -0
- package/src/ui/public/assets/{flow-mindmap-mZisamFd.js → flow-mindmap-oBAz3_QK.js} +4 -4
- package/src/ui/public/assets/index-B666KMk3.js +7 -0
- package/src/ui/public/assets/vendor-BxotT5qN.js +93 -0
- package/src/ui/public/assets/vue-flow-Bx03URoq.js +39 -0
- package/src/ui/public/favicon.svg +75 -75
- package/src/ui/public/index.html +22 -22
- package/src/ui/public/logo.svg +74 -74
- package/src/ui/server/index.js +1 -0
- package/src/ui/server/routes/npm.js +161 -8
- package/src/ui/server/routes/workbench.js +17 -3
- package/src/ui/server/utils/instanceRegistry.js +11 -0
- package/src/ui/server/utils/startServerOnAvailablePort.js +13 -0
- package/src/ui/public/assets/AppVersionBadge-C63UkgfW.js +0 -2
- package/src/ui/public/assets/BranchSelector-Dx2OFvQn.js +0 -1
- package/src/ui/public/assets/CommandConsole-CWGa4uzV.js +0 -17
- package/src/ui/public/assets/CommitForm-DDx1W2nU.js +0 -6
- package/src/ui/public/assets/CustomCommandManager-COAy_rkz.js +0 -1
- package/src/ui/public/assets/EditorView-BI31hRI_.js +0 -0
- package/src/ui/public/assets/FileDiffViewer-B2BI1bGl.js +0 -13
- package/src/ui/public/assets/FlowOrchestrationWorkspace-DBgGQhNc.js +0 -21
- package/src/ui/public/assets/GitStatus-DJKc0Trp.js +0 -6
- package/src/ui/public/assets/ImagePreview-BrXFnZf_.js +0 -1
- package/src/ui/public/assets/LogList-DA4kCWzm.js +0 -7
- package/src/ui/public/assets/ProjectStartupButton-BkB5UNRF.js +0 -1
- package/src/ui/public/assets/RemoteRepoCard-DPfD9ETA.js +0 -1
- package/src/ui/public/assets/ResetToRemoteButton-nUKiK2JR.js +0 -1
- package/src/ui/public/assets/SourceMapView-B49a7U0e.js +0 -3
- package/src/ui/public/assets/TemplateManager-BTDGivoE.js +0 -1
- package/src/ui/public/assets/UserInputNode-BkdGs5AU.js +0 -1
- package/src/ui/public/assets/WorkbenchView-CX-g5psr.js +0 -12
- package/src/ui/public/assets/WorkbenchView-KpSRlP_a.css +0 -1
- package/src/ui/public/assets/__vite-optional-peer-dep_katex_markstream-vue-Bg9-FXxr.js +0 -1
- package/src/ui/public/assets/__vite-optional-peer-dep_mermaid_markstream-vue-cPZl55sA.js +0 -1
- package/src/ui/public/assets/__vite-optional-peer-dep_stream-markdown_markstream-vue-Dhgp-lRL.js +0 -1
- package/src/ui/public/assets/__vite-optional-peer-dep_stream-monaco_markstream-vue-Cr1d6De7.js +0 -1
- package/src/ui/public/assets/d2_markstream-vue-xMoF3M5G.js +0 -1
- package/src/ui/public/assets/element-plus-rcpA4EGF.js +0 -26
- package/src/ui/public/assets/index-BTHO-83r.js +0 -7
- package/src/ui/public/assets/mhchem_markstream-vue-tp86PqxG.js +0 -1
- package/src/ui/public/assets/vendor-DoD2dmIW.js +0 -226
- package/src/ui/public/assets/vue-flow-CfamgGcL.js +0 -39
|
@@ -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,30 +1,30 @@
|
|
|
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-B666KMk3.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
|
-
<link rel="modulepreload" crossorigin href="/assets/element-plus-
|
|
17
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
18
|
-
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-
|
|
16
|
+
<link rel="modulepreload" crossorigin href="/assets/element-plus-CRTdimvR.js">
|
|
17
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-BxotT5qN.js">
|
|
18
|
+
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-CpTW8798.js">
|
|
19
19
|
<link rel="modulepreload" crossorigin href="/assets/socket-io-z4n873W1.js">
|
|
20
|
-
<link rel="modulepreload" crossorigin href="/assets/vue-flow-
|
|
20
|
+
<link rel="modulepreload" crossorigin href="/assets/vue-flow-Bx03URoq.js">
|
|
21
21
|
<link rel="stylesheet" crossorigin href="/assets/monaco-UXx6YYK1.css">
|
|
22
22
|
<link rel="stylesheet" crossorigin href="/assets/element-plus-CYGtZ7Nz.css">
|
|
23
23
|
<link rel="stylesheet" crossorigin href="/assets/vendor-DNI_idR2.css">
|
|
24
24
|
<link rel="stylesheet" crossorigin href="/assets/vue-flow-CavUTEzp.css">
|
|
25
25
|
<link rel="stylesheet" crossorigin href="/assets/index-BYAxMGne.css">
|
|
26
|
-
</head>
|
|
27
|
-
<body>
|
|
28
|
-
<div id="app"></div>
|
|
29
|
-
</body>
|
|
30
|
-
</html>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<div id="app"></div>
|
|
29
|
+
</body>
|
|
30
|
+
</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
|
@@ -16,9 +16,11 @@ 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 os from 'os';
|
|
19
20
|
import { exec, spawn } from 'child_process';
|
|
20
21
|
import https from 'https';
|
|
21
22
|
import { fileURLToPath } from 'url';
|
|
23
|
+
import { getRegistryPath } from '../utils/instanceRegistry.js';
|
|
22
24
|
|
|
23
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
24
26
|
const __dirname = path.dirname(__filename);
|
|
@@ -29,9 +31,36 @@ export function registerNpmRoutes({
|
|
|
29
31
|
}) {
|
|
30
32
|
// 标记是否有升级任务在跑(防并发)
|
|
31
33
|
let activeUpgrade = false;
|
|
34
|
+
// 标记是否有重启任务在跑(防并发)
|
|
35
|
+
let activeRestart = false;
|
|
36
|
+
// 自拉起重启相关常量
|
|
37
|
+
const RESTART_TIMEOUT_MS = 8000; // 子进程必须在此时间内注册到 instanceRegistry
|
|
38
|
+
const REGISTRY_POLL_MS = 250; // 轮询注册表文件间隔
|
|
39
|
+
const EXIT_DELAY_MS = 100; // 子进程就绪后给前端的最后缓冲时间
|
|
32
40
|
|
|
33
41
|
// ========== 应用自升级相关 API ==========
|
|
34
42
|
|
|
43
|
+
// 解析"自拉起"要 spawn 的入口绝对路径。
|
|
44
|
+
// 优先 process.argv[1](开发态 server.js / 生产态 src/gitCommit.js 都是绝对路径),
|
|
45
|
+
// 但 launch.json 的 backend 是 `node -e "...process.argv = [...]; require('./server.js')"`,
|
|
46
|
+
// 这种篡改出来的 argv[1] 是相对路径 "server.js",不能直接 spawn。
|
|
47
|
+
// 回退: 用 __dirname 推导 src/ui/server/index.js 的同级 server.js(仓库根)
|
|
48
|
+
function resolveRestartEntry() {
|
|
49
|
+
const arg = process.argv[1]
|
|
50
|
+
if (arg && path.isAbsolute(arg) && fsSync.existsSync(arg)) {
|
|
51
|
+
return { entry: arg, args: process.argv.slice(2) }
|
|
52
|
+
}
|
|
53
|
+
// 回退到仓库根的 server.js(开发态入口),保留原 PORT 等环境变量
|
|
54
|
+
const fallback = path.resolve(__dirname, '../../../..', 'server.js')
|
|
55
|
+
if (fsSync.existsSync(fallback)) {
|
|
56
|
+
// 透传用户原始 argv[2..](--no-open 等);如果原 argv[1] 是 "server.js" 这类相对路径,
|
|
57
|
+
// 用户大概率没传任何 args,所以空数组也合理
|
|
58
|
+
const originalArgs = (arg && !path.isAbsolute(arg)) ? process.argv.slice(2) : []
|
|
59
|
+
return { entry: fallback, args: originalArgs }
|
|
60
|
+
}
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
|
|
35
64
|
// 当前安装的版本(从外层 package.json 读取)
|
|
36
65
|
function getCurrentVersion() {
|
|
37
66
|
try {
|
|
@@ -191,15 +220,139 @@ export function registerNpmRoutes({
|
|
|
191
220
|
})
|
|
192
221
|
|
|
193
222
|
|
|
194
|
-
//
|
|
223
|
+
// 同步读取 instanceRegistry 文件并返回 Map<pid, entry>
|
|
224
|
+
// npm.js 在自拉起重启场景下需要轮询此文件判断子进程是否已绑定端口
|
|
225
|
+
function readRegistrySync(p) {
|
|
226
|
+
const m = new Map();
|
|
227
|
+
try {
|
|
228
|
+
const raw = fsSync.readFileSync(p, 'utf-8');
|
|
229
|
+
const obj = JSON.parse(raw);
|
|
230
|
+
const instances = (obj && obj.instances) || {};
|
|
231
|
+
for (const [pidStr, entry] of Object.entries(instances)) {
|
|
232
|
+
const pid = Number(pidStr);
|
|
233
|
+
if (Number.isFinite(pid) && entry && typeof entry === 'object') {
|
|
234
|
+
m.set(pid, entry);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch (_) {
|
|
238
|
+
// 文件不存在或 JSON 损坏 → 返回空 Map,调用方按"还没注册"处理
|
|
239
|
+
}
|
|
240
|
+
return m;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// POST /api/app-restart - 自拉起重启:spawn 当前进程入口 + 轮询 instanceRegistry
|
|
244
|
+
// 拿到子进程端口后通过 NDJSON 流告知前端;旧进程再退出
|
|
195
245
|
app.post('/api/app-restart', (_req, res) => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
246
|
+
if (activeRestart) {
|
|
247
|
+
res.status(409).json({ success: false, error: '已有重启任务在进行中' });
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
activeRestart = true;
|
|
251
|
+
|
|
252
|
+
res.setHeader('Content-Type', 'application/x-ndjson; charset=utf-8');
|
|
253
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
254
|
+
res.setHeader('Connection', 'keep-alive');
|
|
255
|
+
res.flushHeaders?.();
|
|
256
|
+
|
|
257
|
+
const send = (obj) => { try { res.write(JSON.stringify(obj) + '\n') } catch (_) {} };
|
|
258
|
+
const finish = () => { try { res.end() } catch (_) {} };
|
|
259
|
+
const release = () => { activeRestart = false };
|
|
260
|
+
|
|
261
|
+
// 1. 记录当前所有 instance,后续用"出现的新 pid"判定子进程
|
|
262
|
+
const registryPath = getRegistryPath();
|
|
263
|
+
const before = readRegistrySync(registryPath);
|
|
264
|
+
const start = Date.now();
|
|
265
|
+
const spawnAt = Date.now();
|
|
266
|
+
|
|
267
|
+
// 2. 准备子进程 ready 信号文件 —— startServerOnAvailablePort 在 listen 成功后会写入
|
|
268
|
+
// (instanceRegistry 在 EPERM 环境下不可用,这是回退通道)
|
|
269
|
+
const notifyPath = path.join(
|
|
270
|
+
os.tmpdir(),
|
|
271
|
+
`zen-gitsync-restart-${process.pid}-${Date.now()}.port`
|
|
272
|
+
);
|
|
273
|
+
try { fsSync.unlinkSync(notifyPath) } catch (_) {} // 清掉旧同名文件
|
|
274
|
+
|
|
275
|
+
const entryInfo = resolveRestartEntry();
|
|
276
|
+
if (!entryInfo) {
|
|
277
|
+
send({ type: 'error', message: '无法解析重启入口(process.argv[1] 既不是绝对路径,仓库根也没有 server.js)' });
|
|
278
|
+
finish();
|
|
279
|
+
release();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
let child;
|
|
284
|
+
try {
|
|
285
|
+
// spawn 当前进程当时是怎么被 node 启的同一个入口(开发态 server.js / 生产态 gitCommit.js)
|
|
286
|
+
// detached: true + stdio: 'ignore' + child.unref() → Windows 上父进程 exit 不会带走子进程
|
|
287
|
+
child = spawn(process.execPath, [entryInfo.entry, ...entryInfo.args], {
|
|
288
|
+
detached: true,
|
|
289
|
+
stdio: 'ignore',
|
|
290
|
+
windowsHide: true,
|
|
291
|
+
env: { ...process.env, ZEN_RESTART_NOTIFY_PATH: notifyPath }
|
|
292
|
+
});
|
|
293
|
+
child.unref();
|
|
294
|
+
} catch (err) {
|
|
295
|
+
send({ type: 'error', message: `拉起子进程失败: ${err?.message || err}` });
|
|
296
|
+
try { fsSync.unlinkSync(notifyPath) } catch (_) {}
|
|
297
|
+
finish();
|
|
298
|
+
release();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
send({ type: 'stdout', message: `[restart] 已在 PID ${child.pid} 拉起子进程 (${entryInfo.entry}),等待端口就绪…\n` });
|
|
303
|
+
|
|
304
|
+
const poll = setInterval(() => {
|
|
305
|
+
if (Date.now() - start > RESTART_TIMEOUT_MS) {
|
|
306
|
+
clearInterval(poll);
|
|
307
|
+
try { child.kill('SIGTERM') } catch (_) {}
|
|
308
|
+
send({ type: 'error', message: `子进程 ${RESTART_TIMEOUT_MS / 1000}s 内未就绪(未读到 ${notifyPath}),已 kill` });
|
|
309
|
+
send({ type: 'timeout' });
|
|
310
|
+
finish();
|
|
311
|
+
try { fsSync.unlinkSync(notifyPath) } catch (_) {}
|
|
312
|
+
// 关键:超时分支旧进程不退出,用户仍可继续手动刷新页面
|
|
313
|
+
release();
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// 优先判定:子进程是否写了 notify 文件(最可靠,不走 instanceRegistry)
|
|
318
|
+
let notifiedPort = null;
|
|
319
|
+
try {
|
|
320
|
+
const raw = fsSync.readFileSync(notifyPath, 'utf8').trim();
|
|
321
|
+
const p = Number(raw);
|
|
322
|
+
if (Number.isInteger(p) && p > 0 && p < 65536) notifiedPort = p;
|
|
323
|
+
} catch (_) {}
|
|
324
|
+
|
|
325
|
+
// 兜底:instanceRegistry 里出现的新 pid + port(用于没有 savePort 的环境)
|
|
326
|
+
let registryPort = null;
|
|
327
|
+
if (!notifiedPort) {
|
|
328
|
+
const after = readRegistrySync(registryPath);
|
|
329
|
+
for (const [pid, entry] of after) {
|
|
330
|
+
if (
|
|
331
|
+
!before.has(pid) &&
|
|
332
|
+
Number.isInteger(entry.port) && entry.port > 0 &&
|
|
333
|
+
(entry.lastHeartbeat ?? entry.startedAt ?? 0) >= spawnAt
|
|
334
|
+
) {
|
|
335
|
+
registryPort = entry.port;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const newPort = notifiedPort ?? registryPort;
|
|
342
|
+
if (newPort) {
|
|
343
|
+
clearInterval(poll);
|
|
344
|
+
// 给 EXIT_DELAY_MS 让新进程稳定,再通知前端 + 旧进程退出
|
|
345
|
+
setTimeout(() => {
|
|
346
|
+
send({ type: 'ready', port: newPort });
|
|
347
|
+
finish();
|
|
348
|
+
try { fsSync.unlinkSync(notifyPath) } catch (_) {}
|
|
349
|
+
console.log('[app-restart] 子进程已就绪,退出当前进程');
|
|
350
|
+
process.exit(0);
|
|
351
|
+
}, EXIT_DELAY_MS);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}, REGISTRY_POLL_MS);
|
|
355
|
+
});
|
|
203
356
|
|
|
204
357
|
|
|
205
358
|
// 读取 package.json 文件内容
|
|
@@ -2724,7 +2724,7 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2724
2724
|
|
|
2725
2725
|
// ── 续接简单任务对话 ────────────────────────────────────────────
|
|
2726
2726
|
// POST /api/workbench/jobs/:id/continue
|
|
2727
|
-
// 入参 body: { userMessage: string }
|
|
2727
|
+
// 入参 body: { userMessage: string, attachments?: Attachment[] }
|
|
2728
2728
|
// 行为:
|
|
2729
2729
|
// - 仅用于 type==='simple' 的任务,基于上一轮 job 捕获到的 claudeSessionId,
|
|
2730
2730
|
// 用 claude --resume <id> 续接历史对话,**新一轮 = 新 job**
|
|
@@ -2732,6 +2732,11 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2732
2732
|
// 区分;前端按 subId 前缀聚合渲染对话流
|
|
2733
2733
|
// - 上一轮还在 pending/running 时拒绝(避免 session 并发跑乱)
|
|
2734
2734
|
// - 上一轮未捕获到 session_id(claude 在 init 前就 crash)时拒绝
|
|
2735
|
+
// - 附件处理(2026-06 改):
|
|
2736
|
+
// · 默认复用 task.attachments(claude --resume 上下文里已经看过这些图,
|
|
2737
|
+
// 不重复推,节省 token)
|
|
2738
|
+
// · 前端可显式传 attachments 数组做"追加"(用户续聊时新增的图片)
|
|
2739
|
+
// · 透传到 virtualSub.attachments,继续走 runSingleSubtask 的拼装逻辑
|
|
2735
2740
|
app.post('/api/workbench/jobs/:id/continue', async (req, res) => {
|
|
2736
2741
|
try {
|
|
2737
2742
|
const userMessage = String(req.body?.userMessage || '').trim();
|
|
@@ -2769,6 +2774,15 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2769
2774
|
}
|
|
2770
2775
|
}
|
|
2771
2776
|
const nextRound = maxRound + 1;
|
|
2777
|
+
// 续接轮的 attachments:
|
|
2778
|
+
// - 前端显式传 attachments:用前端值(复用 task.attachments + 续聊时新增的)
|
|
2779
|
+
// - 前端没传:回退到 task.attachments(向后兼容)
|
|
2780
|
+
// 注意:本轮 attachments 不写盘,只用于拼 prompt,claude --resume 上下文已看过
|
|
2781
|
+
// 大部分图(默认复用的那些),真正"新加"的图是这次对话的关键信息。
|
|
2782
|
+
const bodyAtts = req.body?.attachments;
|
|
2783
|
+
const carryAtts = Array.isArray(bodyAtts) && bodyAtts.length > 0
|
|
2784
|
+
? bodyAtts
|
|
2785
|
+
: (Array.isArray(task.attachments) ? task.attachments : []);
|
|
2772
2786
|
const virtualSub = {
|
|
2773
2787
|
id: `${task.id}__simple__r${nextRound}`,
|
|
2774
2788
|
title: `续接 #${nextRound}`,
|
|
@@ -2776,8 +2790,8 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2776
2790
|
status: 'todo',
|
|
2777
2791
|
// 用户输入的续接消息直接作为本轮 prompt(走 promptOverride,不再拼模板)
|
|
2778
2792
|
promptOverride: userMessage,
|
|
2779
|
-
//
|
|
2780
|
-
attachments:
|
|
2793
|
+
// 透传:复用 task 上已有附件 + 本轮新增(如果有)
|
|
2794
|
+
attachments: carryAtts
|
|
2781
2795
|
};
|
|
2782
2796
|
const repoPath = typeof getCurrentProjectPath === 'function' ? getCurrentProjectPath() : '';
|
|
2783
2797
|
res.json({ success: true, message: '已加入续接队列' });
|
|
@@ -17,10 +17,21 @@
|
|
|
17
17
|
// 多进程并发写采用 atomic temp+rename + 进程内串行化 Promise 链
|
|
18
18
|
// stale 判定:PID 不存在 或 lastHeartbeat 超过阈值
|
|
19
19
|
|
|
20
|
+
import nodePath from 'node:path';
|
|
21
|
+
import nodeOs from 'node:os';
|
|
22
|
+
|
|
20
23
|
const STALE_MS = 30_000; // 心跳超时阈值(毫秒)
|
|
21
24
|
const WATCH_DEBOUNCE_MS = 100; // fs.watch 防抖时间
|
|
22
25
|
const REGISTRY_VERSION = 1;
|
|
23
26
|
|
|
27
|
+
/**
|
|
28
|
+
* 默认注册表文件路径(与 createInstanceRegistry({ registryPath }) 的约定一致)
|
|
29
|
+
* 用于:npm.js 的 /api/app-restart 自拉起时,父进程轮询此路径判断子进程是否就绪。
|
|
30
|
+
*/
|
|
31
|
+
export function getRegistryPath() {
|
|
32
|
+
return nodePath.join(nodeOs.homedir(), '.zen-gitsync-instances.json');
|
|
33
|
+
}
|
|
34
|
+
|
|
24
35
|
function isProcessAlive(pid) {
|
|
25
36
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
26
37
|
try {
|