diff --git a/plugins/ztool-vsc-recent/CHANGELOG.md b/plugins/ztool-vsc-recent/CHANGELOG.md index 597021af..504c8f90 100644 --- a/plugins/ztool-vsc-recent/CHANGELOG.md +++ b/plugins/ztool-vsc-recent/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.1.2 — 2026-06-29 + +### 修复 +- 修复未安装应用或未配置环境变量时由于无报错而导致的静默失效问题 +- 修复 macOS 下 ZTools GUI 环境中环境变量缺失导致无法拉起 VSCode 的问题(重构使用 ZTools 原生 `isMacOs` 判断并优先通过 `open -b` 原生应用唤醒) +- 为 Remote 连接的 Folder URI 在 Windows shell 模式下增加双引号包裹,防御特殊路径空格导致截断的边缘异常 + + ## 0.1.1 — 2026-06-12 ### 修复 diff --git a/plugins/ztool-vsc-recent/package-lock.json b/plugins/ztool-vsc-recent/package-lock.json index 049f8521..5a5e6070 100644 --- a/plugins/ztool-vsc-recent/package-lock.json +++ b/plugins/ztool-vsc-recent/package-lock.json @@ -1,12 +1,12 @@ { "name": "ztool-vsc-recent", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ztool-vsc-recent", - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "fuse.js": "^7.0.0", "sql.js": "^1.10.3" @@ -521,9 +521,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -538,9 +535,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -555,9 +549,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -572,9 +563,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -589,9 +577,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -606,9 +591,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -623,9 +605,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -640,9 +619,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -657,9 +633,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -674,9 +647,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -691,9 +661,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -708,9 +675,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -725,9 +689,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ diff --git a/plugins/ztool-vsc-recent/package.json b/plugins/ztool-vsc-recent/package.json index 9dadf58f..a4a27c3c 100644 --- a/plugins/ztool-vsc-recent/package.json +++ b/plugins/ztool-vsc-recent/package.json @@ -1,6 +1,6 @@ { "name": "ztool-vsc-recent", - "version": "0.1.1", + "version": "0.1.2", "description": "ZTools 插件:VSCode 最近项目快速启动", "type": "commonjs", "scripts": { diff --git a/plugins/ztool-vsc-recent/plugin.json b/plugins/ztool-vsc-recent/plugin.json index b6eb0945..3956d3c9 100644 --- a/plugins/ztool-vsc-recent/plugin.json +++ b/plugins/ztool-vsc-recent/plugin.json @@ -2,7 +2,7 @@ "name": "ztool-vsc-recent", "title": "VSCode 最近项目", "description": "快速打开最近的 VSCode 项目、工作区与远程会话", - "version": "0.1.1", + "version": "0.1.2", "author": "derekxia1988", "main": "index.html", "logo": "logo.png", diff --git a/plugins/ztool-vsc-recent/src/launcher/vscode-stable.js b/plugins/ztool-vsc-recent/src/launcher/vscode-stable.js index 88fb4df0..50561b26 100644 --- a/plugins/ztool-vsc-recent/src/launcher/vscode-stable.js +++ b/plugins/ztool-vsc-recent/src/launcher/vscode-stable.js @@ -7,9 +7,6 @@ const child_process_1 = require("child_process"); * Windows 下 PATH 中的 code 是 code.cmd,所以必须 shell: true。 */ function openInVSCode(item) { - const args = item.kind === 'remote' - ? ['--folder-uri', item.rawPath] - : [quoteIfNeeded(item.rawPath)]; return new Promise(resolve => { let settled = false; const settle = (r) => { if (!settled) { @@ -17,11 +14,49 @@ function openInVSCode(item) { resolve(r); } }; try { - const child = (0, child_process_1.spawn)('code', args, { detached: true, stdio: 'ignore', shell: true }); + const isWin = (typeof ztools !== 'undefined' && typeof ztools.isWindows === 'function') + ? ztools.isWindows() + : process.platform === 'win32'; + const isMac = (typeof ztools !== 'undefined' && typeof ztools.isMacOs === 'function') + ? ztools.isMacOs() + : (typeof ztools !== 'undefined' && typeof ztools.isMacOS === 'function') + ? ztools.isMacOS() + : process.platform === 'darwin'; + let cmd; + let finalArgs; + let useShell; + const env = { ...process.env }; + if (isMac) { + // macOS 平台最佳实践:直接无视环境路径,利用 Bundle ID 原生唤醒应用 + cmd = 'open'; + useShell = false; + finalArgs = item.kind === 'remote' + ? ['-b', 'com.microsoft.VSCode', '--args', '--folder-uri', item.rawPath] + : ['-b', 'com.microsoft.VSCode', item.rawPath]; + } + else { + // Windows / Linux 依赖 code 命令唤起 + cmd = 'code'; + useShell = isWin; // Windows 下开启 shell 兼容 code.cmd + finalArgs = item.kind === 'remote' + ? ['--folder-uri', useShell ? quoteIfNeeded(item.rawPath) : item.rawPath] + : [useShell ? quoteIfNeeded(item.rawPath) : item.rawPath]; + if (!isWin) { + // 为 Linux 等环境尽力补全常规 PATH + const extraPaths = ['/usr/local/bin', '/usr/bin', '/bin']; + env.PATH = env.PATH ? `${extraPaths.join(':')}:${env.PATH}` : extraPaths.join(':'); + } + } + const child = (0, child_process_1.spawn)(cmd, finalArgs, { env, detached: true, stdio: 'ignore', shell: useShell }); child.on('error', e => settle({ ok: false, reason: e.message })); + child.on('exit', code => { + if (code !== 0 && code !== null) { + settle({ ok: false, reason: `进程异常退出(code:${code}),请检查是否已安装或环境变量配置错误` }); + } + }); child.unref(); - // 给 spawn 一个 tick 触发同步错误(如 ENOENT),再 resolve ok - setTimeout(() => settle({ ok: true }), 50); + // 给 spawn 一定时间触发错误或退出的事件,若 100ms 内没报错则假定成功 + setTimeout(() => settle({ ok: true }), 100); } catch (e) { const reason = e instanceof Error ? e.message : String(e); diff --git a/plugins/ztool-vsc-recent/src/launcher/vscode-stable.ts b/plugins/ztool-vsc-recent/src/launcher/vscode-stable.ts index 51c296b5..285d51bf 100644 --- a/plugins/ztool-vsc-recent/src/launcher/vscode-stable.ts +++ b/plugins/ztool-vsc-recent/src/launcher/vscode-stable.ts @@ -1,25 +1,66 @@ import { spawn } from 'child_process'; import type { OpenResult, RecentItem } from '../types'; +declare const ztools: any; + /** * 用 PATH 上的 `code` 命令打开项目。 * Windows 下 PATH 中的 code 是 code.cmd,所以必须 shell: true。 */ export function openInVSCode(item: RecentItem): Promise { - const args = item.kind === 'remote' - ? ['--folder-uri', item.rawPath] - : [quoteIfNeeded(item.rawPath)]; - return new Promise(resolve => { let settled = false; const settle = (r: OpenResult) => { if (!settled) { settled = true; resolve(r); } }; try { - const child = spawn('code', args, { detached: true, stdio: 'ignore', shell: true }); + const isWin = (typeof ztools !== 'undefined' && typeof ztools.isWindows === 'function') + ? ztools.isWindows() + : process.platform === 'win32'; + const isMac = (typeof ztools !== 'undefined' && typeof ztools.isMacOs === 'function') + ? ztools.isMacOs() + : (typeof ztools !== 'undefined' && typeof ztools.isMacOS === 'function') + ? ztools.isMacOS() + : process.platform === 'darwin'; + + let cmd: string; + let finalArgs: string[]; + let useShell: boolean; + const env = { ...process.env }; + + if (isMac) { + // macOS 平台最佳实践:直接无视环境路径,利用 Bundle ID 原生唤醒应用 + cmd = 'open'; + useShell = false; + finalArgs = item.kind === 'remote' + ? ['-b', 'com.microsoft.VSCode', '--args', '--folder-uri', item.rawPath] + : ['-b', 'com.microsoft.VSCode', item.rawPath]; + } else { + // Windows / Linux 依赖 code 命令唤起 + cmd = 'code'; + useShell = isWin; // Windows 下开启 shell 兼容 code.cmd + finalArgs = item.kind === 'remote' + ? ['--folder-uri', useShell ? quoteIfNeeded(item.rawPath) : item.rawPath] + : [useShell ? quoteIfNeeded(item.rawPath) : item.rawPath]; + + if (!isWin) { + // 为 Linux 等环境尽力补全常规 PATH + const extraPaths = ['/usr/local/bin', '/usr/bin', '/bin']; + env.PATH = env.PATH ? `${extraPaths.join(':')}:${env.PATH}` : extraPaths.join(':'); + } + } + + const child = spawn(cmd, finalArgs, { env, detached: true, stdio: 'ignore', shell: useShell }); + child.on('error', e => settle({ ok: false, reason: e.message })); + child.on('exit', code => { + if (code !== 0 && code !== null) { + settle({ ok: false, reason: `进程异常退出(code:${code}),请检查是否已安装或环境变量配置错误` }); + } + }); child.unref(); - // 给 spawn 一个 tick 触发同步错误(如 ENOENT),再 resolve ok - setTimeout(() => settle({ ok: true }), 50); + + // 给 spawn 一定时间触发错误或退出的事件,若 100ms 内没报错则假定成功 + setTimeout(() => settle({ ok: true }), 100); } catch (e: unknown) { const reason = e instanceof Error ? e.message : String(e); settle({ ok: false, reason });