zen-gitsync 2.12.8 → 2.13.1

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.
@@ -1347,4 +1347,4 @@ https://github.com/highlightjs/highlight.js/issues/2277`),i=e,r=t),n===void 0&&(
1347
1347
  h${-(x.value.width-2*e.maskBorderRadius)}
1348
1348
  a${e.maskBorderRadius},${e.maskBorderRadius} 0 0 1 -${e.maskBorderRadius},-${e.maskBorderRadius}
1349
1349
  v${-(x.value.height-2*e.maskBorderRadius)}
1350
- a${e.maskBorderRadius},${e.maskBorderRadius} 0 0 1 ${e.maskBorderRadius},-${e.maskBorderRadius}z`);Ln(t=>{if(p.value){let n=e9(p.value),r=S9t().wheelDelta(t=>Dg(t)*(e.zoomStep/10)).on(`zoom`,e.pannable?t=>{if(t.sourceEvent.type!==`mousemove`||!u.value||!d.value)return;let n=C.value*Math.max(1,o.value.zoom)*(e.inversePan?-1:1),r={x:o.value.x-t.sourceEvent.movementX*n,y:o.value.y-t.sourceEvent.movementY*n},i=[[0,0],[c.value.width,c.value.height]],a=Z9.translate(r.x,r.y).scale(o.value.zoom),l=d.value.constrain()(a,i,s.value);d.value.transform(u.value,l)}:()=>{}).on(`zoom.wheel`,e.zoomable?t=>{if(t.sourceEvent.type!==`wheel`||!u.value||!d.value)return;let n=t.sourceEvent.ctrlKey&&zg()?10:1,r=-t.sourceEvent.deltaY*(t.sourceEvent.deltaMode===1?.05:t.sourceEvent.deltaMode?1:.002)*e.zoomStep,i=o.value.zoom*2**(r*n);d.value.scaleTo(u.value,i)}:()=>{});n.call(r),t(()=>{n.on(`zoom`,null)})}},{flush:`post`});function E(e){let[n,r]=t9(e);t(`click`,{event:e,position:{x:n,y:r}})}function ee(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeClick(r),t(`nodeClick`,r)}function D(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeDoubleClick(r),t(`nodeDblclick`,r)}function O(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeMouseEnter(r),t(`nodeMouseenter`,r)}function te(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeMouseMove(r),t(`nodeMousemove`,r)}function ne(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeMouseLeave(r),t(`nodeMouseleave`,r)}return(e,t)=>(M(),ii(j(cBe),{position:e.position,class:k([`vue-flow__minimap`,{pannable:e.pannable,zoomable:e.zoomable}])},{default:jn(()=>[(M(),N(`svg`,{ref_key:`el`,ref:p,width:m.value,height:h.value,viewBox:[w.value.x,w.value.y,w.value.width,w.value.height].join(` `),role:`img`,"aria-labelledby":`vue-flow__minimap-${j(i)}`,onClick:E},[e.ariaLabel?(M(),N(`title`,{key:0,id:`vue-flow__minimap-${j(i)}`},je(e.ariaLabel),9,D9t)):I(``,!0),(M(!0),N(Xr,null,Sr(j(f),t=>(M(),ii(T9t,{id:t.id,key:t.id,f:``,position:t.computedPosition,dimensions:t.dimensions,selected:t.selected,dragging:t.dragging,style:ve(t.style),class:k(y.value(t)),color:_.value(t),"border-radius":e.nodeBorderRadius,"stroke-color":v.value(t),"stroke-width":e.nodeStrokeWidth,"shape-rendering":j(g),type:t.type,hidden:t.hidden,onClick:e=>ee(e,t),onDblclick:e=>D(e,t),onMouseenter:e=>O(e,t),onMousemove:e=>te(e,t),onMouseleave:e=>ne(e,t)},null,8,[`id`,`position`,`dimensions`,`selected`,`dragging`,`style`,`class`,`color`,`border-radius`,`stroke-color`,`stroke-width`,`shape-rendering`,`type`,`hidden`,`onClick`,`onDblclick`,`onMouseenter`,`onMousemove`,`onMouseleave`]))),128)),P(`path`,{class:`vue-flow__minimap-mask`,d:T.value,fill:e.maskColor,stroke:e.maskStrokeColor,"stroke-width":e.maskStrokeWidth,"fill-rule":`evenodd`},null,8,O9t)],8,E9t))]),_:1},8,[`position`,`class`]))}});export{exe as $,jn as $n,Lpe as $t,Wke as A,P as An,vpe as At,aTe as B,wi as Bn,Epe as Bt,xje as C,Gi as Cn,ppe as Ct,_je as D,Zee as Dn,il as Dt,vje as E,Xr as En,mpe as Et,Nf as F,ui as Fn,Spe as Ft,pCe as G,_r as Gn,cl as Gt,Vwe as H,En as Hn,kpe as Ht,qTe as I,li as In,Cpe as It,LSe as J,Sr as Jn,Ppe as Jt,YSe as K,M as Kn,Mpe as Kt,JTe as L,F as Ln,wpe as Lt,BEe as M,I as Mn,ype as Mt,PEe as N,N as Nn,bpe as Nt,gje as O,Wn as On,hpe as Ot,bEe as P,Cr as Pn,xpe as Pt,cxe as Q,Rn as Qn,zpe as Qt,MTe as R,Xee as Rn,Tpe as Rt,Sje as S,ra as Sn,upe as St,yje as T,ca as Tn,nl as Tt,Hwe as U,gr as Un,sl as Ut,iTe as V,Fn as Vn,Ope as Vt,SCe as W,pr as Wn,jpe as Wt,cSe as X,yr as Xn,ll as Xt,sSe as Y,wr as Yn,Fpe as Yt,lSe as Z,br as Zn,Ipe as Zt,sBe as _,tie as _n,fhe as _t,i7 as a,Gpe as an,j as ar,vd as at,OMe as b,Lne as bn,Zc as bt,C6 as c,Jpe as cn,je as cr,md as ct,tGe as d,Qpe as dn,Age as dt,Rpe as en,Mn as er,Ibe as et,VBe as f,ul as fn,Cge as ft,rg as g,eie as gn,dhe as gt,sg as h,Wre as hn,ou as ht,y7 as i,Upe as in,cn as ir,aye as it,tm as j,ii as jn,_pe as jt,jm as k,L as kn,gpe as kt,aKe as l,Ype as ln,eve as lt,gBe as m,eme as mn,lu as mt,j2t as n,Vpe as nn,Jt as nr,iye as nt,iQt as o,Kpe as on,k as or,Eve as ot,c_ as p,$pe as pn,mu as pt,HSe as q,Pn as qn,Npe as qt,i6t as r,Hpe as rn,A as rr,oye as rt,S6 as s,qpe as sn,ve as sr,hd as st,k9t as t,Bpe as tn,rn as tr,lye as tt,vGe as u,Xpe as un,Au as ut,$g as v,Ai as vn,ame as vt,bje as w,la as wn,tl as wt,Mm as x,vre as xn,el as xt,o_ as y,kre as yn,ml as yt,oTe as z,er as zn,Dpe as zt};
1350
+ a${e.maskBorderRadius},${e.maskBorderRadius} 0 0 1 ${e.maskBorderRadius},-${e.maskBorderRadius}z`);Ln(t=>{if(p.value){let n=e9(p.value),r=S9t().wheelDelta(t=>Dg(t)*(e.zoomStep/10)).on(`zoom`,e.pannable?t=>{if(t.sourceEvent.type!==`mousemove`||!u.value||!d.value)return;let n=C.value*Math.max(1,o.value.zoom)*(e.inversePan?-1:1),r={x:o.value.x-t.sourceEvent.movementX*n,y:o.value.y-t.sourceEvent.movementY*n},i=[[0,0],[c.value.width,c.value.height]],a=Z9.translate(r.x,r.y).scale(o.value.zoom),l=d.value.constrain()(a,i,s.value);d.value.transform(u.value,l)}:()=>{}).on(`zoom.wheel`,e.zoomable?t=>{if(t.sourceEvent.type!==`wheel`||!u.value||!d.value)return;let n=t.sourceEvent.ctrlKey&&zg()?10:1,r=-t.sourceEvent.deltaY*(t.sourceEvent.deltaMode===1?.05:t.sourceEvent.deltaMode?1:.002)*e.zoomStep,i=o.value.zoom*2**(r*n);d.value.scaleTo(u.value,i)}:()=>{});n.call(r),t(()=>{n.on(`zoom`,null)})}},{flush:`post`});function E(e){let[n,r]=t9(e);t(`click`,{event:e,position:{x:n,y:r}})}function ee(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeClick(r),t(`nodeClick`,r)}function D(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeDoubleClick(r),t(`nodeDblclick`,r)}function O(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeMouseEnter(r),t(`nodeMouseenter`,r)}function te(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeMouseMove(r),t(`nodeMousemove`,r)}function ne(e,n){let r={event:e,node:n,connectedEdges:wg([n],a.value)};l.miniMapNodeMouseLeave(r),t(`nodeMouseleave`,r)}return(e,t)=>(M(),ii(j(cBe),{position:e.position,class:k([`vue-flow__minimap`,{pannable:e.pannable,zoomable:e.zoomable}])},{default:jn(()=>[(M(),N(`svg`,{ref_key:`el`,ref:p,width:m.value,height:h.value,viewBox:[w.value.x,w.value.y,w.value.width,w.value.height].join(` `),role:`img`,"aria-labelledby":`vue-flow__minimap-${j(i)}`,onClick:E},[e.ariaLabel?(M(),N(`title`,{key:0,id:`vue-flow__minimap-${j(i)}`},je(e.ariaLabel),9,D9t)):I(``,!0),(M(!0),N(Xr,null,Sr(j(f),t=>(M(),ii(T9t,{id:t.id,key:t.id,f:``,position:t.computedPosition,dimensions:t.dimensions,selected:t.selected,dragging:t.dragging,style:ve(t.style),class:k(y.value(t)),color:_.value(t),"border-radius":e.nodeBorderRadius,"stroke-color":v.value(t),"stroke-width":e.nodeStrokeWidth,"shape-rendering":j(g),type:t.type,hidden:t.hidden,onClick:e=>ee(e,t),onDblclick:e=>D(e,t),onMouseenter:e=>O(e,t),onMousemove:e=>te(e,t),onMouseleave:e=>ne(e,t)},null,8,[`id`,`position`,`dimensions`,`selected`,`dragging`,`style`,`class`,`color`,`border-radius`,`stroke-color`,`stroke-width`,`shape-rendering`,`type`,`hidden`,`onClick`,`onDblclick`,`onMouseenter`,`onMousemove`,`onMouseleave`]))),128)),P(`path`,{class:`vue-flow__minimap-mask`,d:T.value,fill:e.maskColor,stroke:e.maskStrokeColor,"stroke-width":e.maskStrokeWidth,"fill-rule":`evenodd`},null,8,O9t)],8,E9t))]),_:1},8,[`position`,`class`]))}});export{exe as $,Rn as $n,zpe as $t,Wke as A,L as An,gpe as At,aTe as B,er as Bn,Dpe as Bt,xje as C,ra as Cn,ppe as Ct,_je as D,Xr as Dn,mpe as Dt,vje as E,ca as En,nl as Et,Nf as F,Cr as Fn,xpe as Ft,pCe as G,pr as Gn,jpe as Gt,Vwe as H,Fn as Hn,Ope as Ht,qTe as I,ui as In,Spe as It,LSe as J,Pn as Jn,Npe as Jt,YSe as K,_r as Kn,cl as Kt,JTe as L,li as Ln,Cpe as Lt,BEe as M,ii as Mn,_pe as Mt,PEe as N,I as Nn,ype as Nt,gje as O,Zee as On,il as Ot,bEe as P,N as Pn,bpe as Pt,cxe as Q,br as Qn,Ipe as Qt,MTe as R,F as Rn,wpe as Rt,Sje as S,vre as Sn,upe as St,yje as T,la as Tn,rl as Tt,Hwe as U,En as Un,kpe as Ut,iTe as V,wi as Vn,Epe as Vt,SCe as W,gr as Wn,sl as Wt,cSe as X,wr as Xn,Fpe as Xt,sSe as Y,Sr as Yn,Ppe as Yt,lSe as Z,yr as Zn,ll as Zt,sBe as _,eie as _n,fhe as _t,i7 as a,Upe as an,cn as ar,vd as at,OMe as b,kre as bn,Zc as bt,C6 as c,qpe as cn,ve as cr,md as ct,tGe as d,Xpe as dn,Age as dt,Lpe as en,jn as er,Ibe as et,VBe as f,Qpe as fn,Cge as ft,rg as g,Wre as gn,dhe as gt,sg as h,eme as hn,ou as ht,y7 as i,Hpe as in,A as ir,aye as it,tm as j,P as jn,vpe as jt,jm as k,Wn as kn,hpe as kt,aKe as l,Jpe as ln,je as lr,eve as lt,gBe as m,$pe as mn,lu as mt,j2t as n,Bpe as nn,rn as nr,iye as nt,iQt as o,Gpe as on,j as or,Eve as ot,c_ as p,ul as pn,mu as pt,HSe as q,M as qn,Mpe as qt,i6t as r,Vpe as rn,Jt as rr,oye as rt,S6 as s,Kpe as sn,k as sr,hd as st,k9t as t,Rpe as tn,Mn as tr,lye as tt,vGe as u,Ype as un,Au as ut,$g as v,tie as vn,ame as vt,bje as w,Gi as wn,tl as wt,Mm as x,Lne as xn,el as xt,o_ as y,Ai as yn,ml as yt,oTe as z,Xee as zn,Tpe as zt};
@@ -10,12 +10,12 @@
10
10
  <link rel="preconnect" href="https://fonts.googleapis.com" />
11
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
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-DPihtJfT.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-DNP2rwmI.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CMxvf4Kt.js">
15
- <link rel="modulepreload" crossorigin href="/assets/vendor-A4IPqbyo.js">
16
- <link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-opDPZuCO.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/vendor-BfQR1Ql2.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-CIzOKVnN.js">
17
17
  <link rel="stylesheet" crossorigin href="/assets/vendor-DpYOE9sy.css">
18
- <link rel="stylesheet" crossorigin href="/assets/index-tejX3YgJ.css">
18
+ <link rel="stylesheet" crossorigin href="/assets/index-DEEcURiV.css">
19
19
  </head>
20
20
  <body>
21
21
  <div id="app"></div>
@@ -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 {