Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
65 lines
1.6 KiB
Go
65 lines
1.6 KiB
Go
//go:build windows
|
|
|
|
package runtimecmd
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
const defaultWindowsPathExt = ".COM;.EXE;.BAT;.CMD;.PS1"
|
|
|
|
func executableNameCandidates(command string, env []string) []string {
|
|
if filepath.Ext(command) != "" {
|
|
return []string{command}
|
|
}
|
|
pathExt := strings.TrimSpace(envValue(env, "PATHEXT"))
|
|
if pathExt == "" {
|
|
pathExt = defaultWindowsPathExt
|
|
}
|
|
// Prefer Windows PATHEXT launchers before an extensionless file. npm writes
|
|
// both a POSIX `opencode` shim and a Windows `opencode.cmd` shim into the
|
|
// same prefix; choosing the POSIX shim makes ACP probes hang or fail on
|
|
// Windows. Keep the extensionless candidate as a final fallback for managed
|
|
// PE launchers such as the Tutti agent binary.
|
|
result := make([]string, 0, 6)
|
|
seen := map[string]struct{}{}
|
|
extensions := strings.Split(pathExt, ";")
|
|
hasPowerShell := false
|
|
for _, extension := range extensions {
|
|
if strings.EqualFold(strings.TrimSpace(extension), ".PS1") {
|
|
hasPowerShell = true
|
|
break
|
|
}
|
|
}
|
|
if !hasPowerShell {
|
|
extensions = append(extensions, ".PS1")
|
|
}
|
|
for _, extension := range extensions {
|
|
extension = strings.TrimSpace(extension)
|
|
if extension == "" {
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(extension, ".") {
|
|
extension = "." + extension
|
|
}
|
|
candidate := command + extension
|
|
key := strings.ToLower(candidate)
|
|
if _, ok := seen[key]; ok {
|
|
continue
|
|
}
|
|
seen[key] = struct{}{}
|
|
result = append(result, candidate)
|
|
}
|
|
if _, ok := seen[strings.ToLower(command)]; !ok {
|
|
result = append(result, command)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func isExecutableFile(path string) bool {
|
|
stat, err := os.Stat(path)
|
|
return err == nil && !stat.IsDir()
|
|
}
|