2026-11-10 01:24:28 +08:00
|
|
|
|
package client
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2026-11-10 09:59:34 +08:00
|
|
|
|
"errors"
|
2026-11-10 01:24:28 +08:00
|
|
|
|
"fmt"
|
|
|
|
|
|
goruntime "runtime"
|
|
|
|
|
|
|
|
|
|
|
|
"cursor/internal/cursor"
|
|
|
|
|
|
"cursor/internal/logger"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ApplyCursorSettings 用于处理与 ApplyCursorSettings 相关的逻辑。
|
|
|
|
|
|
func (s *ProxyService) ApplyCursorSettings() error {
|
2026-11-10 09:59:34 +08:00
|
|
|
|
if s == nil || s.proxyServer() == nil {
|
2026-11-10 01:24:28 +08:00
|
|
|
|
return fmt.Errorf("proxy is not initialized")
|
|
|
|
|
|
}
|
|
|
|
|
|
s.caFileMu.Lock()
|
|
|
|
|
|
caCertPath, err := cursor.EnsureCACertFile(s.caCertPEM, s.caFilePath)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
s.caFilePath = caCertPath
|
|
|
|
|
|
}
|
|
|
|
|
|
s.caFileMu.Unlock()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("ensure ca cert file: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch goruntime.GOOS {
|
|
|
|
|
|
case "windows":
|
|
|
|
|
|
if err := cursor.EnsureCACertInstalled(s.caCertPEM, caCertPath); err != nil {
|
|
|
|
|
|
return fmt.Errorf("install ca cert: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
case "darwin":
|
|
|
|
|
|
if err := cursor.EnsureCACertInstalled(s.caCertPEM, caCertPath); err != nil {
|
|
|
|
|
|
return fmt.Errorf("install ca cert: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := cursor.SetSystemNodeExtraCACerts(caCertPath); err != nil {
|
|
|
|
|
|
return fmt.Errorf("set node extra ca certs: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-11-10 09:59:34 +08:00
|
|
|
|
proxyURL := cursor.ProxyURLFromListenAddr(s.proxyServer().Snapshot().ListenAddr)
|
2026-11-10 01:24:28 +08:00
|
|
|
|
|
|
|
|
|
|
if err := cursor.WriteUserProxySettings(proxyURL); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CLI 版 wrapper: 不再需要 HTTP_PROXY,由 preload 脚本直接重定向 tls.connect 到后端 HTTPS 端口
|
|
|
|
|
|
// 注入 NODE_EXTRA_CA_CERTS + CURSOR_AUTH_TOKEN
|
|
|
|
|
|
// 如果未检测到 CLI 安装,跳过但不报错
|
|
|
|
|
|
if cliPath := cursor.DetectCLIInstallPath(); cliPath != "" {
|
|
|
|
|
|
cliHTTPSAddr := ""
|
2026-11-10 09:59:34 +08:00
|
|
|
|
if s.backend() != nil {
|
|
|
|
|
|
cliHTTPSAddr = s.backend().CLIHTTPSListenAddr()
|
2026-11-10 01:24:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
if err := cursor.WriteCLIProxyWrapper(cliHTTPSAddr, caCertPath); err != nil {
|
|
|
|
|
|
logger.Errorf("write cli proxy wrapper failed: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 写入 mock auth.json,使 CLI 跳过交互式登录
|
|
|
|
|
|
if err := cursor.WriteCLIAuthFile(); err != nil {
|
|
|
|
|
|
logger.Errorf("write cli auth.json failed: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
logger.Infof("applyCursorSettings: cli not detected, skipping wrapper")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s.setCursorSettingsApplied(true)
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ClearCursorSettings 用于处理与 ClearCursorSettings 相关的逻辑。
|
|
|
|
|
|
func (s *ProxyService) ClearCursorSettings() error {
|
2026-11-10 09:59:34 +08:00
|
|
|
|
var errs []error
|
2026-11-10 01:24:28 +08:00
|
|
|
|
if goruntime.GOOS == "darwin" {
|
|
|
|
|
|
if err := cursor.ClearSystemNodeExtraCACerts(); err != nil {
|
2026-11-10 09:59:34 +08:00
|
|
|
|
errs = append(errs, err)
|
2026-11-10 01:24:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-11-10 09:59:34 +08:00
|
|
|
|
for _, clear := range []func() error{cursor.ClearUserProxySettings, cursor.ClearCLIProxyWrapper, cursor.ClearCLIAuthFile} {
|
|
|
|
|
|
if err := clear(); err != nil {
|
|
|
|
|
|
errs = append(errs, err)
|
|
|
|
|
|
}
|
2026-11-10 01:24:28 +08:00
|
|
|
|
}
|
2026-11-10 09:59:34 +08:00
|
|
|
|
if len(errs) == 0 {
|
|
|
|
|
|
s.setCursorSettingsApplied(false)
|
2026-11-10 01:24:28 +08:00
|
|
|
|
}
|
2026-11-10 09:59:34 +08:00
|
|
|
|
return errors.Join(errs...)
|
2026-11-10 01:24:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetDeviceID 用于处理与 GetDeviceID 相关的逻辑。
|
|
|
|
|
|
func (s *ProxyService) GetDeviceID() (string, error) {
|
|
|
|
|
|
return cursor.GetDeviceID()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CLIStatus 返回 CLI 版 cursor-agent 的代理状态。
|
|
|
|
|
|
type CLIStatus struct {
|
|
|
|
|
|
Installed bool `json:"installed"`
|
|
|
|
|
|
InstallPath string `json:"installPath"`
|
|
|
|
|
|
WrapperActive bool `json:"wrapperActive"`
|
|
|
|
|
|
WrapperPath string `json:"wrapperPath"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetCLIStatus 用于处理与 GetCLIStatus 相关的逻辑。
|
|
|
|
|
|
func (s *ProxyService) GetCLIStatus() CLIStatus {
|
|
|
|
|
|
path := cursor.DetectCLIInstallPath()
|
|
|
|
|
|
return CLIStatus{
|
|
|
|
|
|
Installed: path != "",
|
|
|
|
|
|
InstallPath: path,
|
|
|
|
|
|
WrapperActive: cursor.CLIWrapperExists(),
|
|
|
|
|
|
WrapperPath: cursor.CLIWrapperPath(),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|