Files
2026-07-13 13:00:08 +08:00

117 lines
2.5 KiB
Go

package capdiag
import (
"net/url"
"os"
"path/filepath"
"strings"
)
// displayPath rewrites absolute paths for safe reports:
// - under workspace → <workspace>/...
// - under home → ~/...
// - elsewhere → <external>/basename (no full external path, no username)
func displayPath(p, workspace, home string) string {
p = strings.TrimSpace(p)
if p == "" {
return ""
}
// Builtin markers stay as-is.
if strings.HasPrefix(p, "(builtin") {
return p
}
clean := filepath.Clean(p)
if abs, err := filepath.Abs(clean); err == nil {
clean = abs
}
ws := workspace
if ws != "" {
if abs, err := filepath.Abs(ws); err == nil {
ws = abs
}
if clean == ws {
return "<workspace>"
}
if rel, err := filepath.Rel(ws, clean); err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
return "<workspace>/" + filepath.ToSlash(rel)
}
}
if home == "" {
if h, err := os.UserHomeDir(); err == nil {
home = h
}
}
if home != "" {
home = filepath.Clean(home)
if clean == home {
return "~"
}
if rel, err := filepath.Rel(home, clean); err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
return "~/" + filepath.ToSlash(rel)
}
}
// External: only show a generic marker + base name so reports stay shareable.
base := filepath.Base(clean)
if base == "" || base == "." || base == string(os.PathSeparator) {
return "<external>"
}
return "<external>/" + base
}
func sortedKeys(m map[string]string) []string {
if len(m) == 0 {
return nil
}
keys := make([]string, 0, len(m))
for k := range m {
if strings.TrimSpace(k) != "" {
keys = append(keys, k)
}
}
// Insertion sort for stability without importing sort in hot path of small maps.
for i := 1; i < len(keys); i++ {
j := i
for j > 0 && keys[j-1] > keys[j] {
keys[j-1], keys[j] = keys[j], keys[j-1]
j--
}
}
return keys
}
// urlHostOnly returns the host (and port) from a URL without path/query/userinfo.
func urlHostOnly(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" {
return ""
}
u, err := url.Parse(raw)
if err != nil || u.Host == "" {
return "<url>"
}
return u.Host
}
func transportOf(typ string) string {
t := strings.ToLower(strings.TrimSpace(typ))
switch t {
case "", "stdio":
return "stdio"
case "http", "streamable-http", "streamable_http":
return "http"
case "sse":
return "sse"
default:
return t
}
}
func isValidTransport(t string) bool {
switch transportOf(t) {
case "stdio", "http", "sse":
return true
default:
return false
}
}