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
119 lines
3.3 KiB
Go
119 lines
3.3 KiB
Go
package browser
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const autoConnectSetupHint = "Open Chrome and enable remote debugging at chrome://inspect/#remote-debugging, then try again."
|
|
|
|
func browserMCPSubprocessEnv() []string {
|
|
return []string{
|
|
"NO_PROXY=127.0.0.1,localhost,::1",
|
|
"no_proxy=127.0.0.1,localhost,::1",
|
|
}
|
|
}
|
|
|
|
func resolveAutoConnectMCPConnectionArgs() []string {
|
|
if endpoint, ok := stableChromeDevToolsWebSocketEndpoint(); ok {
|
|
return []string{"--wsEndpoint", endpoint, "--no-usage-statistics"}
|
|
}
|
|
return []string{"--autoConnect", "--channel", "stable", "--no-usage-statistics"}
|
|
}
|
|
|
|
func validateAutoConnectChromeReady() error {
|
|
if _, err := readStableChromeDevToolsActivePort(); err != nil {
|
|
return fmt.Errorf("could not connect to Chrome for reuse mode: %w. %s", err, autoConnectSetupHint)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func stableChromeDevToolsWebSocketEndpoint() (endpoint string, ok bool) {
|
|
activePort, err := readStableChromeDevToolsActivePort()
|
|
if err != nil {
|
|
return "", false
|
|
}
|
|
return fmt.Sprintf("ws://127.0.0.1:%d%s", activePort.port, activePort.path), true
|
|
}
|
|
|
|
func readStableChromeDevToolsActivePort() (devToolsActivePort, error) {
|
|
portPath := stableChromeDevToolsActivePortPath()
|
|
if portPath == "" {
|
|
return devToolsActivePort{}, errors.New("stable Chrome profile path is unavailable on this platform")
|
|
}
|
|
content, err := os.ReadFile(portPath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return devToolsActivePort{}, fmt.Errorf("DevToolsActivePort not found at %s", portPath)
|
|
}
|
|
return devToolsActivePort{}, fmt.Errorf("read DevToolsActivePort: %w", err)
|
|
}
|
|
activePort, ok := parseDevToolsActivePort(string(content))
|
|
if !ok {
|
|
return devToolsActivePort{}, fmt.Errorf("invalid DevToolsActivePort at %s", portPath)
|
|
}
|
|
return activePort, nil
|
|
}
|
|
|
|
func stableChromeDevToolsActivePortPath() string {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return stableChromeDevToolsActivePortPathFor(runtime.GOOS, home, os.Getenv("LOCALAPPDATA"))
|
|
}
|
|
|
|
func stableChromeDevToolsActivePortPathFor(goos string, home string, localAppData string) string {
|
|
switch goos {
|
|
case "darwin":
|
|
if strings.TrimSpace(home) == "" {
|
|
return ""
|
|
}
|
|
return filepath.Join(home, "Library", "Application Support", "Google", "Chrome", "DevToolsActivePort")
|
|
case "linux":
|
|
if strings.TrimSpace(home) == "" {
|
|
return ""
|
|
}
|
|
return filepath.Join(home, ".config", "google-chrome", "DevToolsActivePort")
|
|
case "windows":
|
|
if strings.TrimSpace(localAppData) == "" {
|
|
return ""
|
|
}
|
|
return filepath.Join(localAppData, "Google", "Chrome", "User Data", "DevToolsActivePort")
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func parseDevToolsActivePort(content string) (devToolsActivePort, bool) {
|
|
lines := make([]string, 0, 2)
|
|
for _, line := range strings.Split(content, "\n") {
|
|
trimmed := strings.TrimSpace(line)
|
|
if trimmed != "" {
|
|
lines = append(lines, trimmed)
|
|
}
|
|
}
|
|
if len(lines) < 2 {
|
|
return devToolsActivePort{}, false
|
|
}
|
|
port, err := strconv.Atoi(lines[0])
|
|
if err != nil || port <= 0 || port > 65535 {
|
|
return devToolsActivePort{}, false
|
|
}
|
|
path := lines[1]
|
|
if !strings.HasPrefix(path, "/") {
|
|
return devToolsActivePort{}, false
|
|
}
|
|
return devToolsActivePort{port: port, path: path}, true
|
|
}
|
|
|
|
type devToolsActivePort struct {
|
|
port int
|
|
path string
|
|
}
|