zen-gitsync 2.16.45 → 2.16.46
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/src/ui/public/assets/{AgentView-YLlieash.js → AgentView-DjEh2Ser.js} +1 -1
- package/src/ui/public/assets/AppVersionBadge-C0W8qJMa.js +2 -0
- package/src/ui/public/assets/AppVersionBadge-D5tJzJfa.css +1 -0
- package/src/ui/public/assets/{BranchSelector-Dxp8ZcBR.js → BranchSelector-DwBoFZ_l.js} +1 -1
- package/src/ui/public/assets/{CommitForm-CApcOqdq.js → CommitForm-Bgf_Q22_.js} +1 -1
- package/src/ui/public/assets/{CommonDialog-BkP0vc6s.js → CommonDialog-DI1euXB7.js} +1 -1
- package/src/ui/public/assets/{EditorView-BWnLKzwg.js → EditorView-CiR1TmBc.js} +1 -1
- package/src/ui/public/assets/{FileDiffViewer-Dz0Pm4oj.js → FileDiffViewer-BFhFrpLQ.js} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-BI3hh4SD.js → FlowExecutionViewer-b1ljVzx5.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-BXvmQZcz.js → FlowOrchestrationWorkspace-ByaiTJJ5.js} +1 -1
- package/src/ui/public/assets/{LogList-HrkEiBSr.js → LogList-G69HICRD.js} +1 -1
- package/src/ui/public/assets/{MindmapView-BCPPuqCL.js → MindmapView-C1bYS634.js} +1 -1
- package/src/ui/public/assets/{MonitorView-Cnj7MmD9.js → MonitorView-CfSWHGdE.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-DqjqZz5g.js → ProjectStartupButton-DvjqSSVk.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-BgUYxylZ.js → RemoteRepoCard-Dz5uraya.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-CjIoOCFI.js → SourceMapView-DpucdQtC.js} +1 -1
- package/src/ui/public/assets/{SvgIcon-D09jyLT8.js → SvgIcon-m0MNciAf.js} +1 -1
- package/src/ui/public/assets/{TemplateManager-BPfPLCTs.js → TemplateManager-Dvf3Kfka.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-WKU1IkID.js → UserInputNode-BxmLv71r.js} +1 -1
- package/src/ui/public/assets/{WorkbenchView-CJS3HN_I.js → WorkbenchView-BCZkpV5D.js} +1 -1
- package/src/ui/public/assets/{_plugin-vue_export-helper-BnAB3nEU.js → _plugin-vue_export-helper-CXkiOlUy.js} +2 -2
- package/src/ui/public/assets/{configStore-CsNLFoMc.js → configStore-CxkqmN4M.js} +1 -1
- package/src/ui/public/assets/{gitStore-DriA_V_g.js → gitStore-C996_BK_.js} +1 -1
- package/src/ui/public/assets/{index-Dr8V0ZRm.js → index-Cubtsc1L.js} +4 -4
- package/src/ui/public/assets/{previewSandbox-BTAxBeYa.js → previewSandbox-UPbTQFXc.js} +0 -0
- package/src/ui/public/index.html +9 -9
- package/src/ui/server/routes/npm.js +65 -10
- package/src/ui/server/routes/npm.test.js +146 -0
- package/src/ui/public/assets/AppVersionBadge-CoLw1lcc.js +0 -2
- package/src/ui/public/assets/AppVersionBadge-Dj6H729N.css +0 -1
|
Binary file
|
package/src/ui/public/index.html
CHANGED
|
@@ -10,23 +10,23 @@
|
|
|
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-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-Cubtsc1L.js"></script>
|
|
14
14
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
|
|
15
15
|
<link rel="modulepreload" crossorigin href="/assets/element-plus-CgvKuDqm.js">
|
|
16
16
|
<link rel="modulepreload" crossorigin href="/assets/monaco-BScz9v63.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="/assets/vendor-C3wWuk8k.js">
|
|
18
|
-
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-
|
|
19
|
-
<link rel="modulepreload" crossorigin href="/assets/SvgIcon-
|
|
20
|
-
<link rel="modulepreload" crossorigin href="/assets/CommonDialog-
|
|
21
|
-
<link rel="modulepreload" crossorigin href="/assets/configStore-
|
|
18
|
+
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-CXkiOlUy.js">
|
|
19
|
+
<link rel="modulepreload" crossorigin href="/assets/SvgIcon-m0MNciAf.js">
|
|
20
|
+
<link rel="modulepreload" crossorigin href="/assets/CommonDialog-DI1euXB7.js">
|
|
21
|
+
<link rel="modulepreload" crossorigin href="/assets/configStore-CxkqmN4M.js">
|
|
22
22
|
<link rel="modulepreload" crossorigin href="/assets/socket-io-TBtw0msS.js">
|
|
23
|
-
<link rel="modulepreload" crossorigin href="/assets/gitStore-
|
|
23
|
+
<link rel="modulepreload" crossorigin href="/assets/gitStore-C996_BK_.js">
|
|
24
24
|
<link rel="modulepreload" crossorigin href="/assets/useThemeObserver-Dy51enDy.js">
|
|
25
25
|
<link rel="modulepreload" crossorigin href="/assets/flow-mindmap-Cmo6I23w.js">
|
|
26
|
-
<link rel="modulepreload" crossorigin href="/assets/previewSandbox-
|
|
27
|
-
<link rel="modulepreload" crossorigin href="/assets/FileDiffViewer-
|
|
26
|
+
<link rel="modulepreload" crossorigin href="/assets/previewSandbox-UPbTQFXc.js">
|
|
27
|
+
<link rel="modulepreload" crossorigin href="/assets/FileDiffViewer-BFhFrpLQ.js">
|
|
28
28
|
<link rel="modulepreload" crossorigin href="/assets/toolsStore-Rvql5dE6.js">
|
|
29
|
-
<link rel="modulepreload" crossorigin href="/assets/TemplateManager-
|
|
29
|
+
<link rel="modulepreload" crossorigin href="/assets/TemplateManager-Dvf3Kfka.js">
|
|
30
30
|
<link rel="modulepreload" crossorigin href="/assets/vue-flow-BCU8bNHJ.js">
|
|
31
31
|
<link rel="stylesheet" crossorigin href="/assets/element-plus-qRNmrFVy.css">
|
|
32
32
|
<link rel="stylesheet" crossorigin href="/assets/monaco-B2lPvkrc.css">
|
|
@@ -26,6 +26,54 @@ import { getRegistryPath } from '../utils/instanceRegistry.js';
|
|
|
26
26
|
const __filename = fileURLToPath(import.meta.url);
|
|
27
27
|
const __dirname = path.dirname(__filename);
|
|
28
28
|
|
|
29
|
+
// ── 环境探测(模块级纯函数,便于单测)───────────────────────────────────
|
|
30
|
+
//
|
|
31
|
+
// 判定"要不要 sudo 才能全局装包"这件事,历史上曾经写成 `process.platform === 'win32'`,
|
|
32
|
+
// 这个判断在 MSYS/Cygwin 环境下会翻车:那种 Node 是伪 Unix 构建,platform 报 'linux',
|
|
33
|
+
// 于是走进 Unix 分支、去调 sudo —— 而 MSYS 自带的 sudo 只是个只会输出
|
|
34
|
+
// "sudo: a password is required" 的桩程序,跟真实密码无关,用户无论输什么都装不上。
|
|
35
|
+
//
|
|
36
|
+
// 正确做法(对齐 npm / nvm 的处理思路):
|
|
37
|
+
// 1. 只要不是真 Unix(win32 / MSYS / Cygwin)→ 永远不需要 sudo;
|
|
38
|
+
// 2. 是真 Unix 但已经是 root(uid 0,如装了 setuid 的 node)→ 不需要 sudo;
|
|
39
|
+
// 3. 其余(真 Unix 的普通用户)→ 需要 sudo。
|
|
40
|
+
export function needsSudo({
|
|
41
|
+
platform = process.platform,
|
|
42
|
+
env = process.env,
|
|
43
|
+
getuid = process.getuid,
|
|
44
|
+
} = {}) {
|
|
45
|
+
// MSYS / Cygwin 会把这两个变量注入进程环境,是识别伪 Unix 最可靠的信号
|
|
46
|
+
const isMsysLike = !!(env.MSYSTEM || env.CYGWIN)
|
|
47
|
+
if (isMsysLike) return false
|
|
48
|
+
if (platform === 'win32') return false
|
|
49
|
+
if (typeof getuid === 'function') {
|
|
50
|
+
try {
|
|
51
|
+
if (getuid() === 0) return false
|
|
52
|
+
} catch { /* getuid 在某些环境会抛,落回"需要 sudo" */ }
|
|
53
|
+
}
|
|
54
|
+
return true
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 根据环境决定 npm 可执行文件名 / 是否需要 sudo / 是否要走 shell。
|
|
58
|
+
// npm 在 Windows 上是 .cmd 批处理,spawn 必须配合 shell:true 才能找到;
|
|
59
|
+
// MSYS 环境有 node 前缀里的 `npm`(sh shim),直接 spawn 即可。
|
|
60
|
+
export function resolveUpgradeCommand(pkgArgs, opts) {
|
|
61
|
+
const { platform = process.platform, env = process.env } = opts || {}
|
|
62
|
+
const isMsysLike = !!(env.MSYSTEM || env.CYGWIN)
|
|
63
|
+
const isWin = platform === 'win32'
|
|
64
|
+
const sudo = needsSudo({ ...opts, platform, env })
|
|
65
|
+
|
|
66
|
+
if (sudo) {
|
|
67
|
+
// -n 非交互:免密则直接过,需要密码就立刻失败,不把 GUI 挂死在密码提示上
|
|
68
|
+
return { cmd: 'sudo', args: ['-n', 'npm', ...pkgArgs], useShell: false, sudo }
|
|
69
|
+
}
|
|
70
|
+
if (isWin) {
|
|
71
|
+
return { cmd: 'npm.cmd', args: pkgArgs, useShell: true, sudo }
|
|
72
|
+
}
|
|
73
|
+
// 包含 MSYS/Cygwin:用裸 npm,绝不碰 sudo
|
|
74
|
+
return { cmd: 'npm', args: pkgArgs, useShell: false, sudo, isMsysLike }
|
|
75
|
+
}
|
|
76
|
+
|
|
29
77
|
export function registerNpmRoutes({
|
|
30
78
|
app,
|
|
31
79
|
getCurrentProjectPath
|
|
@@ -62,6 +110,8 @@ export function registerNpmRoutes({
|
|
|
62
110
|
return null
|
|
63
111
|
}
|
|
64
112
|
|
|
113
|
+
// 环境探测 / 升级命令拼装 已提到模块顶部(见 import 之后的 needsSudo、resolveUpgradeCommand)
|
|
114
|
+
|
|
65
115
|
// 当前安装的版本(从外层 package.json 读取)
|
|
66
116
|
function getCurrentVersion() {
|
|
67
117
|
try {
|
|
@@ -176,13 +226,12 @@ export function registerNpmRoutes({
|
|
|
176
226
|
}
|
|
177
227
|
const finish = () => { try { res.end() } catch { /* ignore */ } }
|
|
178
228
|
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
const cmd
|
|
185
|
-
const finalArgs = isWin ? args : ['-n', npmCmd, ...args]
|
|
229
|
+
// 升级命令按"运行环境"而非"操作系统名"决定要不要 sudo。
|
|
230
|
+
// 之前用 process.platform === 'win32' 判断,MSYS/Cygwin 的伪 Unix Node
|
|
231
|
+
// (platform 报 'linux')会误走 sudo 分支,撞上 MSYS 那个假 sudo 桩程序卡死。
|
|
232
|
+
// 详见 needsSudo / resolveUpgradeCommand 的注释。
|
|
233
|
+
const upgradeArgs = ['install', '-g', 'zen-gitsync', '--registry', 'https://registry.npmjs.org/']
|
|
234
|
+
const { cmd, args: finalArgs, useShell, sudo } = resolveUpgradeCommand(upgradeArgs)
|
|
186
235
|
|
|
187
236
|
activeUpgrade = send
|
|
188
237
|
const cleanup = () => { activeUpgrade = null }
|
|
@@ -193,7 +242,7 @@ export function registerNpmRoutes({
|
|
|
193
242
|
env: { ...process.env, FORCE_COLOR: '0' },
|
|
194
243
|
windowsHide: true,
|
|
195
244
|
// Windows 下调用 .cmd 必须 shell:true
|
|
196
|
-
shell:
|
|
245
|
+
shell: useShell
|
|
197
246
|
})
|
|
198
247
|
} catch (err) {
|
|
199
248
|
send({ type: 'error', message: `启动升级进程失败: ${err.message}` })
|
|
@@ -219,8 +268,14 @@ export function registerNpmRoutes({
|
|
|
219
268
|
latestVersionCache = { value: null, at: 0 }
|
|
220
269
|
} else {
|
|
221
270
|
let hint = ''
|
|
222
|
-
if (
|
|
223
|
-
|
|
271
|
+
if (sudo) {
|
|
272
|
+
// 只有真的走了 sudo 分支才提示提权;Windows / MSYS / root 都不该看到这句
|
|
273
|
+
hint = '(提示:全局安装需要管理员权限,请用管理员权限重启 GUI 后再试,'
|
|
274
|
+
+ '或手动执行 npm install -g zen-gitsync)'
|
|
275
|
+
} else {
|
|
276
|
+
// 无 sudo 仍失败:大概率是 npm prefix 目录无写权限,给出可自救的手动命令
|
|
277
|
+
hint = '(提示:可手动执行 npm install -g zen-gitsync 后重启 GUI;'
|
|
278
|
+
+ '若报 EACCES,请检查 npm prefix -g 目录的写权限)'
|
|
224
279
|
}
|
|
225
280
|
send({ type: 'error', message: `\n升级失败,退出码 ${code}${hint ? ' ' + hint : ''}\n` })
|
|
226
281
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Copyright 2026 xz333221
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
//
|
|
15
|
+
// 自升级命令环境判定回归测试(2026-09-12)
|
|
16
|
+
//
|
|
17
|
+
// 背景:GUI 里点「升级」曾固定执行 `sudo -n npm install -g zen-gitsync` 并报
|
|
18
|
+
// "sudo: 需要密码",用户无论输什么都装不上。根因是判定写成了
|
|
19
|
+
// `process.platform === 'win32'`,而 MSYS/Cygwin 的 Node 是伪 Unix 构建
|
|
20
|
+
// (platform 报 'linux'),于是误走 sudo 分支,撞上 MSYS 那个只会输出
|
|
21
|
+
// "a password is required" 的 sudo 桩程序。
|
|
22
|
+
//
|
|
23
|
+
// 这里守住两条契约:
|
|
24
|
+
// 1. needsSudo() 只在"真 Unix + 非 root"时返回 true;
|
|
25
|
+
// 2. resolveUpgradeCommand() 在 MSYS/Cygwin 下拼出的命令里绝不能出现 sudo。
|
|
26
|
+
import { test } from 'node:test'
|
|
27
|
+
import assert from 'node:assert/strict'
|
|
28
|
+
import { needsSudo, resolveUpgradeCommand } from './npm.js'
|
|
29
|
+
|
|
30
|
+
// ── needsSudo:环境判定 ────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
test('needsSudo: Windows 原生 Node 不需要 sudo', () => {
|
|
33
|
+
assert.equal(needsSudo({ platform: 'win32', env: {}, getuid: undefined }), false)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('needsSudo: MSYS/Cygwin 的伪 Unix Node 不需要 sudo(本次 bug 的核心场景)', () => {
|
|
37
|
+
// MSYS2 / Git Bash:platform 报 linux,但注入 MSYSTEM
|
|
38
|
+
assert.equal(
|
|
39
|
+
needsSudo({ platform: 'linux', env: { MSYSTEM: 'MINGW64' }, getuid: undefined }),
|
|
40
|
+
false
|
|
41
|
+
)
|
|
42
|
+
// Cygwin:platform 报 linux,但注入 CYGWIN
|
|
43
|
+
assert.equal(
|
|
44
|
+
needsSudo({ platform: 'linux', env: { CYGWIN: 'ntsec' }, getuid: undefined }),
|
|
45
|
+
false
|
|
46
|
+
)
|
|
47
|
+
// Git Bash 通常两个都有
|
|
48
|
+
assert.equal(
|
|
49
|
+
needsSudo({ platform: 'linux', env: { MSYSTEM: 'MINGW64', CYGWIN: 'nodosfilewarning' }, getuid: undefined }),
|
|
50
|
+
false
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('needsSudo: 真 Unix 的普通用户需要 sudo', () => {
|
|
55
|
+
assert.equal(needsSudo({ platform: 'linux', env: {}, getuid: () => 1000 }), true)
|
|
56
|
+
assert.equal(needsSudo({ platform: 'darwin', env: {}, getuid: () => 501 }), true)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('needsSudo: 真 Unix 的 root(uid 0)不需要 sudo', () => {
|
|
60
|
+
assert.equal(needsSudo({ platform: 'linux', env: {}, getuid: () => 0 }), false)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('needsSudo: getuid 缺失时不崩,保守返回需要 sudo', () => {
|
|
64
|
+
assert.equal(needsSudo({ platform: 'linux', env: {}, getuid: undefined }), true)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('needsSudo: getuid 抛异常时不崩,保守返回需要 sudo', () => {
|
|
68
|
+
assert.equal(
|
|
69
|
+
needsSudo({ platform: 'linux', env: {}, getuid: () => { throw new Error('EPERM') } }),
|
|
70
|
+
true
|
|
71
|
+
)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('needsSudo: 默认参数取自 process,不会抛错', () => {
|
|
75
|
+
assert.equal(typeof needsSudo(), 'boolean')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// ── resolveUpgradeCommand:命令拼装 ────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
const PKG_ARGS = ['install', '-g', 'zen-gitsync', '--registry', 'https://registry.npmjs.org/']
|
|
81
|
+
|
|
82
|
+
test('resolveUpgradeCommand: Windows 原生走 npm.cmd + shell:true,无 sudo', () => {
|
|
83
|
+
const r = resolveUpgradeCommand(PKG_ARGS, { platform: 'win32', env: {}, getuid: undefined })
|
|
84
|
+
assert.equal(r.cmd, 'npm.cmd')
|
|
85
|
+
assert.equal(r.useShell, true)
|
|
86
|
+
assert.equal(r.sudo, false)
|
|
87
|
+
assert.deepEqual(r.args, PKG_ARGS)
|
|
88
|
+
assert.ok(!r.args.includes('sudo'))
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('resolveUpgradeCommand: MSYS 下绝不出现 sudo(回归本次 bug)', () => {
|
|
92
|
+
const r = resolveUpgradeCommand(PKG_ARGS, {
|
|
93
|
+
platform: 'linux',
|
|
94
|
+
env: { MSYSTEM: 'MINGW64' },
|
|
95
|
+
getuid: undefined,
|
|
96
|
+
})
|
|
97
|
+
assert.equal(r.cmd, 'npm')
|
|
98
|
+
assert.equal(r.sudo, false)
|
|
99
|
+
assert.equal(r.isMsysLike, true)
|
|
100
|
+
assert.ok(
|
|
101
|
+
!r.args.some((a) => String(a).includes('sudo')),
|
|
102
|
+
`MSYS 环境不应拼出 sudo,实际: ${[r.cmd, ...r.args].join(' ')}`
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('resolveUpgradeCommand: Cygwin 下同样不走 sudo', () => {
|
|
107
|
+
const r = resolveUpgradeCommand(PKG_ARGS, {
|
|
108
|
+
platform: 'linux',
|
|
109
|
+
env: { CYGWIN: 'ntsec' },
|
|
110
|
+
getuid: undefined,
|
|
111
|
+
})
|
|
112
|
+
assert.equal(r.sudo, false)
|
|
113
|
+
assert.match(r.cmd, /^npm(\.cmd)?$/)
|
|
114
|
+
assert.ok(!r.args.some((a) => String(a).includes('sudo')))
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('resolveUpgradeCommand: 真 Unix 普通用户走 sudo -n', () => {
|
|
118
|
+
const r = resolveUpgradeCommand(PKG_ARGS, { platform: 'linux', env: {}, getuid: () => 1000 })
|
|
119
|
+
assert.equal(r.cmd, 'sudo')
|
|
120
|
+
assert.equal(r.sudo, true)
|
|
121
|
+
// -n 保证非交互:免密直接过,需密码立刻失败,不挂死 GUI
|
|
122
|
+
assert.deepEqual(r.args, ['-n', 'npm', ...PKG_ARGS])
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test('resolveUpgradeCommand: 真 Unix root 直接裸装 npm,无 sudo', () => {
|
|
126
|
+
const r = resolveUpgradeCommand(PKG_ARGS, { platform: 'linux', env: {}, getuid: () => 0 })
|
|
127
|
+
assert.equal(r.cmd, 'npm')
|
|
128
|
+
assert.equal(r.sudo, false)
|
|
129
|
+
assert.deepEqual(r.args, PKG_ARGS)
|
|
130
|
+
assert.ok(!r.args.includes('sudo'))
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test('resolveUpgradeCommand: 完整命令串里不会出现 "sudo -n npm" 之外的提权痕迹', () => {
|
|
134
|
+
// 三个免提权场景逐个检查拼出的完整命令
|
|
135
|
+
const cases = [
|
|
136
|
+
{ platform: 'win32', env: {}, getuid: undefined },
|
|
137
|
+
{ platform: 'linux', env: { MSYSTEM: 'MINGW64' }, getuid: undefined },
|
|
138
|
+
{ platform: 'linux', env: {}, getuid: () => 0 },
|
|
139
|
+
]
|
|
140
|
+
for (const c of cases) {
|
|
141
|
+
const r = resolveUpgradeCommand(PKG_ARGS, c)
|
|
142
|
+
const full = [r.cmd, ...r.args].join(' ')
|
|
143
|
+
assert.ok(!full.includes('sudo'), `不应含 sudo: ${full}`)
|
|
144
|
+
assert.ok(full.includes('zen-gitsync'), `应含包名: ${full}`)
|
|
145
|
+
}
|
|
146
|
+
})
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,B as t,Bn as n,Br as r,D as i,Dn as a,Dr as o,En as s,Et as c,G as l,Gr as u,Hn as d,Ln as f,Nn as p,Sn as m,Wn as h,Y as g,bn as _,i as v,kn as y,nt as b,or as x,pr as S,r as C,rt as w,tr as T,vn as E,xn as D,yn as O,yr as k}from"./element-plus-CgvKuDqm.js";import{n as A,t as j}from"./_plugin-vue_export-helper-BnAB3nEU.js";async function M(e,t){let n=e.body.getReader(),r=new TextDecoder(`utf-8`),i=``;for(;;){let{done:e,value:a}=await n.read();if(e)break;i+=r.decode(a,{stream:!0});let o=i.split(`
|
|
2
|
-
`);i=o.pop()??``;for(let e of o)e.trim()&&t(e)}i.trim()&&t(i)}async function N(){let e=await fetch(`/api/app-version`);return e.ok?e.json():{success:!1,current:``,latest:null,hasUpdate:!1,error:`HTTP ${e.status}`}}async function P(e){let t=await fetch(`/api/app-upgrade`,{method:`POST`});if(!t.ok){let n=`HTTP ${t.status}`;try{let e=await t.json();e?.error&&(n=e.error)}catch{}e({type:`error`,message:n}),e({type:`done`,code:t.status});return}if(!t.body){e({type:`error`,message:`响应无 body`}),e({type:`done`,code:-1});return}await M(t,t=>{try{e(JSON.parse(t))}catch{}})}async function F(){let e=await fetch(`/api/app-restart`,{method:`POST`});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n?.error&&(t=n.error)}catch{}throw Error(t)}if(!e.body)throw Error(`响应无 body`);return new Promise((t,n)=>{let r=!1,i=e=>{r||(r=!0,e())};M(e,e=>{try{let r=JSON.parse(e);r.type===`ready`&&typeof r.port==`number`&&r.port>0?i(()=>t(r.port)):r.type===`timeout`?i(()=>n(Error(`restart.timeout`))):r.type===`error`&&i(()=>n(Error(r.message||`restart.failed`)))}catch{}}).then(()=>{i(()=>n(Error(`restart.stream-closed`)))}).catch(()=>{})})}p(),x(),o();var I={key:3},L={key:4},R={key:5},z={key:0,class:`upgrade-hint`},B={key:0,class:`upgrade-countdown`},V=j(y({__name:`UpgradeDialog`,props:{modelValue:{type:Boolean},logs:{},status:{},countdown:{default:0}},emits:[`update:modelValue`,`retry`,`restart`,`cancel`],setup(n,{emit:o}){let l=n,d=o,p=S(null);e(()=>l.logs,async()=>{await f(),p.value&&(p.value.scrollTop=p.value.scrollHeight)});function v(){l.status!==`running`&&(l.status===`success`&&l.countdown>0&&d(`cancel`),d(`update:modelValue`,!1))}function y(){d(`retry`)}function x(){d(`restart`)}function C(){d(`cancel`),d(`update:modelValue`,!1)}return(e,o)=>{let l=g,f=t,S=i;return h(),_(S,{"model-value":n.modelValue,"onUpdate:modelValue":o[0]||=e=>d(`update:modelValue`,e),title:k(A)(`@F13B4:升级`),width:`680px`,"close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":n.status!==`running`,"append-to-body":``,onClose:v},{footer:T(()=>[n.status===`failed`?(h(),_(f,{key:0,type:`primary`,onClick:y},{default:T(()=>[s(u(k(A)(`@F13B4:重试`)),1)]),_:1})):D(``,!0),n.status===`success`?(h(),_(f,{key:1,type:`primary`,onClick:x},{default:T(()=>[s(u(k(A)(`@F13B4:立即重启并刷新`)),1)]),_:1})):D(``,!0),n.status===`success`?(h(),_(f,{key:2,onClick:C},{default:T(()=>[s(u(k(A)(`@F13B4:稍后手动重启`)),1)]),_:1})):D(``,!0),n.status===`running`?(h(),_(f,{key:3,disabled:``},{default:T(()=>[s(u(k(A)(`@F13B4:升级中`))+`... `,1)]),_:1})):D(``,!0)]),default:T(()=>[O(`div`,{class:r([`upgrade-status`,`is-${n.status}`])},[n.status===`running`?(h(),_(l,{key:0,class:`is-loading`},{default:T(()=>[a(k(c))]),_:1})):n.status===`success`?(h(),_(l,{key:1,color:`#67c23a`},{default:T(()=>[a(k(b))]),_:1})):(h(),_(l,{key:2,color:`#f56c6c`},{default:T(()=>[a(k(w))]),_:1})),n.status===`running`?(h(),m(`span`,I,u(k(A)(`@F13B4:升级中`)),1)):n.status===`success`?(h(),m(`span`,L,u(k(A)(`@F13B4:升级完成`)),1)):(h(),m(`span`,R,u(k(A)(`@F13B4:升级失败`)),1))],2),n.status===`success`?(h(),m(`p`,z,[s(u(k(A)(`@F13B4:新版本已全局安装,需要重启服务才能生效`))+` `,1),n.countdown>0?(h(),m(`span`,B,u(k(A)(`@F13B4:{seconds} 秒后自动刷新`,{seconds:n.countdown})),1)):D(``,!0)])):D(``,!0),O(`pre`,{ref_key:`logEl`,ref:p,class:`upgrade-log`},u(n.logs||k(A)(`@F13B4:等待日志输出`)),513)]),_:1},8,[`model-value`,`title`,`show-close`])}}}),[[`__scopeId`,`data-v-3de8edac`]]);p(),x(),o();var H={class:`app-version-badge`},U=[`aria-label`],W=[`aria-label`],G=[`title`,`aria-label`],K={class:`upgrade-btn__label`},q={class:`upgrade-btn__version`},J=`https://github.com/xz333221/zen-gitsync/releases`,Y=5,X=`app-version-check`,Z=36e5,Q=j(y({__name:`AppVersionBadge`,setup(e){let t=`2.16.45`,r=S(t),i=E(()=>r.value||t),o=S(null),s=S(!1),c=S(``),f=S(`running`),p=S(0),g=null,_=S(!1);function y(){try{let e=sessionStorage.getItem(X);if(!e)return null;let{at:t,data:n}=JSON.parse(e);return Date.now()-t>Z?null:n}catch{return null}}function b(e){try{sessionStorage.setItem(X,JSON.stringify({at:Date.now(),data:e}))}catch{}}async function x(e=!1){let t=y();t&&(o.value=t);try{let t=await N();o.value=t,b(t),t.current&&(r.value=t.current),!e&&t.success&&t.hasUpdate&&v({type:`success`,message:A(`@F13B4:发现新版本 {version}`,{version:t.latest??``}),duration:4e3})}catch(t){e||v({type:`warning`,message:A(`@F13B4:检查更新失败 {error}`,{error:t?.message||``})})}}async function w(){if(o.value?.hasUpdate){try{await C.confirm(A(`@F13B4:确定要从 {current} 升级到 {latest} 吗?`,{current:o.value.current,latest:o.value.latest}),A(`@F13B4:升级`),{confirmButtonText:A(`@F13B4:确定升级`),cancelButtonText:A(`@F13B4:取消`),type:`info`})}catch{return}c.value=``,f.value=`running`,s.value=!0,await P(e=>{if(e.type===`done`){if(f.value=e.code===0?`success`:`failed`,e.code===0){try{sessionStorage.removeItem(X)}catch{}o.value?.latest&&(r.value=o.value.latest),j()}}else e.message&&(c.value+=e.message)})}}function j(){M(),p.value=Y,g=setInterval(()=>{--p.value,p.value<=0&&(g&&=(clearInterval(g),null),L())},1e3)}function M(){g&&=(clearInterval(g),null),p.value=0}function I(){M()}async function L(){if(M(),!_.value){_.value=!0;try{let e=await F(),{pathname:t,search:n,hash:r}=window.location;window.location.href=`http://localhost:${e}${t}${n}${r}`}catch(e){let t=e?.message||``,n={"restart.timeout":`@F13B4:重启超时`,"restart.stream-closed":`@F13B4:重启失败,请刷新页面重试`,"restart.failed":`@F13B4:重启失败`}[t];v({type:`warning`,message:n?A(n):A(`@F13B4:重启失败 {error}`,{error:t})}),_.value=!1}}}return n(()=>{M()}),d(()=>{x(!0)}),(e,t)=>{let n=l;return h(),m(`div`,H,[a(n,{content:k(A)(`@F13B4:在 GitHub 上查看源码`),placement:`top`,effect:`dark`,"show-after":300},{default:T(()=>[O(`a`,{href:`https://github.com/xz333221/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link`,"aria-label":k(A)(`@F13B4:在 GitHub 上查看源码`)},[...t[1]||=[O(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[O(`path`,{d:`M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2z`})],-1)]],8,U)]),_:1},8,[`content`]),a(n,{content:k(A)(`@F13B4:在 npm 上查看包`),placement:`top`,effect:`dark`,"show-after":300},{default:T(()=>[O(`a`,{href:`https://www.npmjs.com/package/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link badge-icon-link--npm`,"aria-label":k(A)(`@F13B4:在 npm 上查看包`)},[...t[2]||=[O(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[O(`path`,{d:`M2 2v20h20V2H2zm17.167 17.167H12.5v-10h-3.333v10H4.833V4.833h14.334v14.334z`})],-1)]],8,W)]),_:1},8,[`content`]),a(n,{content:k(A)(`@F13B4:查看更新`),placement:`top`,effect:`dark`,"show-after":300},{default:T(()=>[O(`a`,{href:J,target:`_blank`,rel:`noopener noreferrer`,class:`version-link`},`v`+u(i.value),1)]),_:1},8,[`content`]),o.value?.hasUpdate?(h(),m(`button`,{key:0,type:`button`,class:`upgrade-btn`,title:k(A)(`@F13B4:发现新版本 {version},点击升级`,{version:o.value.latest??``}),"aria-label":k(A)(`@F13B4:发现新版本 {version},点击升级`,{version:o.value.latest??``}),onClick:w},[t[3]||=O(`span`,{class:`upgrade-btn__dot`,"aria-hidden":`true`},null,-1),O(`span`,K,u(k(A)(`@F13B4:升级`)),1),O(`span`,q,`v`+u(o.value.latest),1)],8,G)):D(``,!0),a(V,{modelValue:s.value,"onUpdate:modelValue":t[0]||=e=>s.value=e,logs:c.value,status:f.value,countdown:p.value,onRetry:w,onRestart:L,onCancel:I},null,8,[`modelValue`,`logs`,`status`,`countdown`])])}}}),[[`__scopeId`,`data-v-bc7c0d5c`]]);export{Q as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.upgrade-status[data-v-3de8edac]{align-items:center;gap:var(--spacing-base);margin-bottom:var(--spacing-md);font-size:14px;font-weight:500;display:flex}.upgrade-status.is-running[data-v-3de8edac]{color:var(--el-color-primary)}.upgrade-status.is-success[data-v-3de8edac]{color:var(--el-color-success)}.upgrade-status.is-failed[data-v-3de8edac]{color:var(--el-color-danger)}.upgrade-status .is-loading[data-v-3de8edac]{animation:2s linear infinite rotating-3de8edac}.upgrade-log[data-v-3de8edac]{color:#d4d4d4;white-space:pre-wrap;word-break:break-all;background:#1e1e1e;border-radius:4px;height:320px;margin:0;padding:12px;font-family:JetBrains Mono,Cascadia Code,Consolas,monospace;font-size:12px;line-height:1.6;overflow:auto}.upgrade-hint[data-v-3de8edac]{margin:0 0 var(--spacing-md) 0;border-left:3px solid var(--el-color-success);color:var(--el-color-success);background:#67c23a14;border-radius:4px;padding:8px 12px;font-size:13px}.upgrade-countdown[data-v-3de8edac]{background:var(--el-color-success);color:#fff;border-radius:10px;margin-left:8px;padding:1px 8px;font-size:12px;font-weight:600;animation:1s ease-in-out infinite pulse-3de8edac;display:inline-block}@keyframes pulse-3de8edac{0%,to{opacity:1}50%{opacity:.55}}@keyframes rotating-3de8edac{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.app-version-badge[data-v-bc7c0d5c]{align-items:center;gap:var(--spacing-base);margin-left:auto;display:inline-flex}.badge-icon-link[data-v-bc7c0d5c]{width:22px;height:22px;color:var(--text-tertiary);opacity:.7;border-radius:4px;justify-content:center;align-items:center;text-decoration:none;transition:color .18s,opacity .18s,background .18s;display:inline-flex}.badge-icon-link[data-v-bc7c0d5c]:hover{opacity:1;color:var(--text-secondary);background:var(--bg-hover,#0000000f)}.badge-icon-link--npm[data-v-bc7c0d5c]:hover{color:var(--color-npm)}.badge-icon-link[data-v-bc7c0d5c]:first-child:hover{color:var(--text-primary)}.version-link[data-v-bc7c0d5c]{color:var(--text-secondary);border-radius:3px;padding:2px 6px;font-family:monospace;font-size:11px;text-decoration:none;transition:color .2s,background-color .2s}.version-link[data-v-bc7c0d5c]:hover{color:var(--color-primary);background-color:#0000000a}.upgrade-btn[data-v-bc7c0d5c]{appearance:none;cursor:pointer;color:#fff;background:linear-gradient(135deg, var(--color-primary) 0%, #3a8ee6 100%);height:22px;box-shadow:var(--shadow-sm);transition:transform var(--transition-fast) var(--ease-custom), box-shadow var(--transition-fast) var(--ease-custom), filter var(--transition-fast) var(--ease-custom);white-space:nowrap;-webkit-user-select:none;user-select:none;border:0;border-radius:11px;outline:none;align-items:center;gap:5px;margin:0;padding:0 10px 0 8px;font-family:inherit;font-size:11px;font-weight:600;line-height:1;display:inline-flex}.upgrade-btn[data-v-bc7c0d5c]:hover{filter:brightness(1.08);box-shadow:var(--shadow-md);transform:translateY(-1px)}.upgrade-btn[data-v-bc7c0d5c]:active{filter:brightness(.96);box-shadow:var(--shadow-sm);transform:translateY(0)}.upgrade-btn[data-v-bc7c0d5c]:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.upgrade-btn__dot[data-v-bc7c0d5c]{background:#fff;border-radius:50%;flex-shrink:0;width:6px;height:6px;animation:1.6s ease-in-out infinite upgrade-pulse-bc7c0d5c;box-shadow:0 0 0 2px #ffffff59}.upgrade-btn__label[data-v-bc7c0d5c]{letter-spacing:.5px}.upgrade-btn__version[data-v-bc7c0d5c]{background:#ffffff38;border-radius:6px;padding:1px 5px;font-family:monospace;font-size:10px;font-weight:500;line-height:1.2}@keyframes upgrade-pulse-bc7c0d5c{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(.8)}}
|