Merge branch 'main' into fix/cli-local-mode-endpoints

# Conflicts:
#	internal/backend/server/middleware.go
This commit is contained in:
leookun
2026-08-03 00:39:56 +08:00
41 changed files with 2325 additions and 725 deletions
+30 -2
View File
@@ -2,6 +2,7 @@ package upstream
import (
"bytes"
"fmt"
"io"
"net/http"
"strings"
@@ -19,7 +20,7 @@ type CompatRouteConfig struct {
ConsoleLog bool
}
func DirectAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
func ForwardAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
@@ -29,6 +30,34 @@ func DirectAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
}
}
// AuthenticatedForwardAction forwards a Cursor control-plane request with the
// independent desktop account after the local-mode identity rewrite has run.
func AuthenticatedForwardAction(deps Dependencies, cfg CompatRouteConfig, authorizationProvider AuthorizationProvider) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, _, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
if reqCtx == nil || reqCtx.Request == nil {
return fmt.Errorf("Cursor 控制面请求上下文无效")
}
if authorizationProvider == nil {
return fmt.Errorf("Cursor 账号服务未初始化")
}
authorization, err := authorizationProvider.Authorization(reqCtx.Request.Context())
if err != nil {
return err
}
_, err = ForwardToUpstream(reqCtx, ForwardOptions{
PatchHeaders: func(headers http.Header) {
headers.Set("Authorization", authorization)
headers.Set("x-cursor-checksum", BuildCursorChecksum(authorization))
},
})
return err
}
}
func FixedStatusAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
@@ -133,7 +162,6 @@ func newCompatRouteObjects(ctx *server.Context, deps Dependencies, cfg CompatRou
Headers: ctx.Request.Header.Clone(),
ContentType: strings.TrimSpace(ctx.Request.Header.Get("content-type")),
RequestBody: body,
Mode: ctx.Mode,
Deps: &deps,
HTTPRequestID: resolveHTTPRequestID(ctx.Request),
}
+1 -2
View File
@@ -15,7 +15,6 @@ import (
"time"
"cursor/gen/aiserverv1"
"cursor/internal/backend/server"
"cursor/internal/logger"
"cursor/internal/netproxy"
legacyruntime "cursor/internal/runtime"
@@ -87,7 +86,7 @@ func buildUpstreamRequest(reqCtx *RequestContext, body []byte, options ForwardOp
}
upstreamRequest.Host = reqCtx.TargetURL.Host
if reqCtx.Mode == server.ModeLocal && shouldRewriteHost(reqCtx.TargetURL.Hostname()) {
if shouldRewriteHost(reqCtx.TargetURL.Hostname()) {
auth := formatBearerAuthorization(legacyruntime.LocalRelayToken)
if auth == "" {
return nil, nil, legacyruntime.ErrInvalidSystemSetting
+7 -1
View File
@@ -20,6 +20,13 @@ type SystemSettingService interface {
ResolveModelAdapters(context.Context) ([]legacyruntime.ModelAdapterConfig, error)
}
// AuthorizationProvider supplies the independent Cursor account used only by
// official control-plane requests such as Plugins, Skills, and MCP registry.
type AuthorizationProvider interface {
Authorization(context.Context) (string, error)
SignedIn() bool
}
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
@@ -41,7 +48,6 @@ type RequestContext struct {
Headers http.Header
ContentType string
RequestBody []byte
Mode server.ExecutionMode
Deps *Dependencies
HTTPRequestID string
}