launch/vscode: prefer known vs code paths over code on PATH

This commit is contained in:
Eva Ho
2026-03-26 15:14:20 -04:00
parent d1151e18a1
commit 63f3612ed9

View File

@@ -25,11 +25,10 @@ type VSCode struct{}
func (v *VSCode) String() string { return "Visual Studio Code" }
// findBinary returns the path/command to launch VS Code, or "" if not found.
// It checks for the "code" CLI on PATH first, then falls back to platform-specific locations.
// It checks platform-specific locations first, then falls back to "code" on
// PATH only if it resolves to a known VS Code installation (not Cursor or
// another fork).
func (v *VSCode) findBinary() string {
if _, err := exec.LookPath("code"); err == nil {
return "code"
}
var candidates []string
switch runtime.GOOS {
case "darwin":
@@ -51,9 +50,49 @@ func (v *VSCode) findBinary() string {
return c
}
}
if codePath, err := exec.LookPath("code"); err == nil {
if v.isVSCodeBinary(codePath) {
return codePath
}
}
return ""
}
// isVSCodeBinary checks whether a "code" binary on PATH actually belongs to
// Visual Studio Code by resolving symlinks and checking that the real path
// contains a VS Code-specific component. If the path is a wrapper script
// rather than a symlink, the script content is also checked.
func (v *VSCode) isVSCodeBinary(codePath string) bool {
vsCodeMarkers := []string{
"Visual Studio Code",
"Microsoft VS Code",
"/share/code/",
"/snap/code/",
}
// Check the resolved symlink path
if resolved, err := filepath.EvalSymlinks(codePath); err == nil {
for _, marker := range vsCodeMarkers {
if strings.Contains(resolved, marker) {
return true
}
}
}
// If not a symlink (or symlink didn't match), check if it's a wrapper
// script whose content references a VS Code path
if content, err := os.ReadFile(codePath); err == nil && len(content) < 4096 {
text := string(content)
for _, marker := range vsCodeMarkers {
if strings.Contains(text, marker) {
return true
}
}
}
return false
}
// IsRunning reports whether VS Code is currently running.
// Each platform uses a pattern specific enough to avoid matching Cursor or
// other VS Code forks.