package tools import ( "regexp" "strings" ) type shellRuntime struct { GOOS string Executable string Syntax string } type shellIssue struct { Kind string Message string Suggestion string } var ( windowsBashStyleCDPattern = regexp.MustCompile(`(?i)(^|[&|;]\s*)cd\s+/(?:[a-ce-z0-9_./~-]|d[a-z0-9_./~-])[a-z0-9_./~-]*`) windowsLSCommandPattern = regexp.MustCompile(`(?i)(^|[&|;]\s*)ls\b(?:\s+|$)`) ) func detectShellRuntime(goos string) shellRuntime { if goos == "windows" { return shellRuntime{GOOS: goos, Executable: "cmd.exe", Syntax: "Windows cmd.exe"} } return shellRuntime{GOOS: goos, Executable: "/bin/sh", Syntax: "/bin/sh"} } func shellGuidanceForGOOS(goos string) string { runtime := detectShellRuntime(goos) if goos == "windows" { return "Uses " + runtime.Syntax + " syntax on Windows; prefer cwd over cd when changing directories." } return "Uses " + runtime.Syntax + " syntax." } func detectShellCommandIssue(command string, goos string) *shellIssue { if goos != "windows" { return nil } trimmed := strings.TrimSpace(command) if windowsBashStyleCDPattern.MatchString(trimmed) || windowsLSCommandPattern.MatchString(trimmed) { return &shellIssue{ Kind: "windows_shell_syntax", Message: "Command looks like POSIX/Bash syntax, but Zero runs bash tool commands through Windows cmd.exe on this host.", Suggestion: "Use the cwd argument instead of cd, use Windows cmd.exe syntax, or use native tools such as list_directory, read_file, grep, and glob.", } } return nil } func detectShellOutputIssue(command string, output string, goos string) *shellIssue { if goos != "windows" { return nil } haystack := strings.ToLower(command + "\n" + output) if strings.Contains(haystack, "the syntax of the command is incorrect") || strings.Contains(haystack, "is not recognized as an internal or external command") { return &shellIssue{ Kind: "windows_shell_syntax", Message: "Windows cmd.exe rejected the command syntax.", Suggestion: "Translate the command to Windows cmd.exe syntax, set the bash tool cwd argument instead of running cd, or prefer native Zero tools for file inspection.", } } return nil } func appendShellIssueHint(output string, issue shellIssue) string { output = strings.TrimRight(output, "\r\n") hint := "[zero] shell issue: " + issue.Message if strings.TrimSpace(issue.Suggestion) != "" { hint += "\nSuggestion: " + issue.Suggestion } if output == "" { return hint } return output + "\n" + hint }