feat(vscode): worktree 打开方式可选 VS Code/PyCharm,并修复 handleOpenWorktree 不展开 ~ 的打开报错

- worktree.ts: handleOpenWorktree/handleDeleteWorktree/dispatchImplTabPostCloseAsync 三处改用 resolveWorktreePath,修复带 ~ 的存量路径被拼成 <工作区>/~/... 导致打不开
- 新增全局设置 worktreeOpenWith('vscode' | 'pycharm',默认 vscode),贯穿 store/settings handler/messages/KanbanPanel 与 webview 的 messages/useIssues/App/SettingsModal「钩子」分组新增「工作树打开方式」下拉
- handleOpenWorktree 按设置分支:pycharm 走 JetBrains pycharm 启动器,ENOENT 时提示启用命令行启动器

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-24 05:20:22 +08:00
co-authored by Claude Opus 4.7
parent 5e7a3d20d9
commit cacc60eb0e
9 changed files with 78 additions and 4 deletions
@@ -24,6 +24,7 @@ interface SubmitValues {
devBranch: string
autoBuildBranch: string
worktreeDirectory: string
worktreeOpenWith: 'vscode' | 'pycharm'
worktreePostCreateScript: string
worktreePreRemoveScript: string
implTabPreCreateScript: string
@@ -61,6 +62,7 @@ export interface SettingsModalProps {
initialDevBranch: string
initialAutoBuildBranch: string
initialWorktreeDirectory: string
initialWorktreeOpenWith: 'vscode' | 'pycharm'
initialWorktreePostCreateScript: string
initialWorktreePreRemoveScript: string
initialImplTabPreCreateScript: string
@@ -131,6 +133,7 @@ export function SettingsModal({
initialDevBranch,
initialAutoBuildBranch,
initialWorktreeDirectory,
initialWorktreeOpenWith,
initialWorktreePostCreateScript,
initialWorktreePreRemoveScript,
initialImplTabPreCreateScript,
@@ -155,6 +158,7 @@ export function SettingsModal({
const [devBranch, setDevBranch] = useState(initialDevBranch)
const [autoBuildBranch, setAutoBuildBranch] = useState(initialAutoBuildBranch)
const [worktreeDirectory, setWorktreeDirectory] = useState(initialWorktreeDirectory)
const [worktreeOpenWith, setWorktreeOpenWith] = useState(initialWorktreeOpenWith)
const [worktreePostCreateScript, setWorktreePostCreateScript] = useState(initialWorktreePostCreateScript)
const [worktreePreRemoveScript, setWorktreePreRemoveScript] = useState(initialWorktreePreRemoveScript)
const [implTabPreCreateScript, setImplTabPreCreateScript] = useState(initialImplTabPreCreateScript)
@@ -258,6 +262,7 @@ export function SettingsModal({
autoBuildBranch: autoBuildBranch.trim(),
// worktree 目录模板:trim 后留空 = 用默认模板(getSettings 读时回退)
worktreeDirectory: worktreeDirectory.trim(),
worktreeOpenWith,
// 钩子路径保持原样 trim(前后空格无意义;空串 = 用默认 .spx/*.sh
worktreePostCreateScript: worktreePostCreateScript.trim(),
worktreePreRemoveScript: worktreePreRemoveScript.trim(),
@@ -642,6 +647,28 @@ export function SettingsModal({
/>
</Field>
<Field
label="工作树打开方式"
hint={(
<>
PyCharm
{' '}
<code>pycharm</code>
{' '}
PATH JetBrains Toolbox
</>
)}
>
<select
value={worktreeOpenWith}
onChange={e => setWorktreeOpenWith(e.target.value as 'vscode' | 'pycharm')}
className={inputClass}
>
<option value="vscode">VS Code</option>
<option value="pycharm">PyCharm</option>
</select>
</Field>
<Field
label="worktree 创建后脚本"
hint={(