mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-18 03:57:06 +08:00
fix(backend): cover cursor-agent CLI local-mode endpoint surface
Desktop Cursor works through the local proxy because it drives the agent
over BidiAppend/RunSSE plus the already-mocked unary endpoints. The
cursor-agent CLI speaks the same agent protocol but calls additional
unary endpoints that had no local handlers, so every request fell into a
wildcard route and came back as HTTP 404, which the Connect client maps
to '[unimplemented] HTTP 404'.
Three independent breaks, one visible symptom:
1. Startup: ServerConfigService/GetServerConfig (only the AiService
variant was mocked), DashboardService/GetTeamAdminSettingsOrEmptyIfNotInTeam
and DashboardService/ListMarketplaces were missing, so the CLI aborted
during session init.
2. Git workspaces: the CLI resolves the repo path-encryption key from
indexingConfig.default{User,Team}PathEncryptionKey in GetServerConfig
when no IDE-stored repo keys exist. The mock returned no indexingConfig,
so repository identity init failed with 'No encryption key found'.
3. Tool execution: every fs tool executor (Ls/Grep/Glob/Shell) consults
the ignore service, which calls getRepoBlockExcludeGlobs() ->
DashboardService/GetTeamReposOrEmptyIfNotInTeam. The 404 propagated as
the tool result error, so model answers arrived but every tool call
returned '[unimplemented] HTTP 404'. Non-git workspaces skip the
repo-block path, which is why tools only failed inside git repos.
Also close the remaining tolerated 404 noise so a CLI session produces
zero unimplemented responses: model listing (GetUsableModels,
GetDefaultModelForCli, GetDefaultModel), dashboard/plugin housekeeping
(GetGlobalCommands, GetEffectiveUserPlugins, RegisterMarketplaceAndPlugins,
GetCliDownloadUrl) and telemetry (AnalyticsService/SubmitLogs,
AnalyticsService/TrackEvents, OTLP /v1/traces).
Additional logging: PolicyMiddleware now includes the request path in the
per-request log line, which is what made this diagnosable from app.log.
This commit is contained in:
@@ -330,6 +330,19 @@ func (host *Host) rebuildLocked(cfg serverconfig.Config) error {
|
||||
Name: "server_config",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.ServerConfigService/GetServerConfig",
|
||||
server.Name("server_config_service_get_server_config"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "server_config_service_get_server_config",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetServerConfigResponse",
|
||||
MockBuilder: upstream.ServerConfigMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "server_config_service_get_server_config",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.AiService/AvailableModels",
|
||||
server.Name("available_models"),
|
||||
server.ConnectUnary(),
|
||||
@@ -343,6 +356,45 @@ func (host *Host) rebuildLocked(cfg serverconfig.Config) error {
|
||||
Name: "available_models",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.AiService/GetUsableModels",
|
||||
server.Name("usable_models"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "usable_models",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetUsableModelsResponse",
|
||||
MockBuilder: upstream.UsableModelsMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "usable_models",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.AiService/GetDefaultModelForCli",
|
||||
server.Name("default_model_for_cli"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "default_model_for_cli",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetDefaultModelForCliResponse",
|
||||
MockBuilder: upstream.DefaultModelForCliMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "default_model_for_cli",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.AiService/GetDefaultModel",
|
||||
server.Name("default_model"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "default_model",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetDefaultModelResponse",
|
||||
MockBuilder: upstream.DefaultModelMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "default_model",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.AiService/GetDefaultModelNudgeData",
|
||||
server.Name("default_model_nudge"),
|
||||
server.ConnectUnary(),
|
||||
@@ -382,6 +434,43 @@ func (host *Host) rebuildLocked(cfg serverconfig.Config) error {
|
||||
Name: "first_window_statsig_decision",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.AnalyticsService/SubmitLogs",
|
||||
server.Name("analytics_submit_logs"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "analytics_submit_logs",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.SubmitLogsResponse",
|
||||
MockBuilder: upstream.SubmitLogsMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "analytics_submit_logs",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.AnalyticsService/TrackEvents",
|
||||
server.Name("analytics_track_events"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "analytics_track_events",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.TrackEventsResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "analytics_track_events",
|
||||
})),
|
||||
),
|
||||
server.POST("/v1/traces",
|
||||
server.Name("otlp_traces"),
|
||||
server.HTTP(),
|
||||
server.Local(upstream.FixedStatusAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "otlp_traces",
|
||||
StatusCode: http.StatusOK,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "otlp_traces",
|
||||
})),
|
||||
),
|
||||
server.POST("/oauth/token",
|
||||
server.Name("oauth_token"),
|
||||
server.HTTP(),
|
||||
@@ -525,6 +614,97 @@ func (host *Host) rebuildLocked(cfg serverconfig.Config) error {
|
||||
Name: "dashboard_get_managed_skills",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/GetTeamAdminSettingsOrEmptyIfNotInTeam",
|
||||
server.Name("dashboard_get_team_admin_settings_or_empty"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_team_admin_settings_or_empty",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetTeamAdminSettingsResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_team_admin_settings_or_empty",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/GetTeamReposOrEmptyIfNotInTeam",
|
||||
server.Name("dashboard_get_team_repos_or_empty"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_team_repos_or_empty",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetTeamReposResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_team_repos_or_empty",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/ListMarketplaces",
|
||||
server.Name("dashboard_list_marketplaces"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_list_marketplaces",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.ListMarketplacesResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_list_marketplaces",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/GetGlobalCommands",
|
||||
server.Name("dashboard_get_global_commands"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_global_commands",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetGlobalCommandsResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_global_commands",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/GetEffectiveUserPlugins",
|
||||
server.Name("dashboard_get_effective_user_plugins"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_effective_user_plugins",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetEffectiveUserPluginsResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_effective_user_plugins",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/RegisterMarketplaceAndPlugins",
|
||||
server.Name("dashboard_register_marketplace_and_plugins"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_register_marketplace_and_plugins",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.RegisterMarketplaceAndPluginsResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_register_marketplace_and_plugins",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/GetCliDownloadUrl",
|
||||
server.Name("dashboard_get_cli_download_url"),
|
||||
server.ConnectUnary(),
|
||||
server.Local(upstream.MockProtoAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_cli_download_url",
|
||||
StatusCode: http.StatusOK,
|
||||
MockProtoType: "aiserver.v1.GetCliDownloadUrlResponse",
|
||||
MockBuilder: upstream.EmptyMockBuilder,
|
||||
})),
|
||||
server.Upstream(upstream.DirectAction(routeDeps, upstream.CompatRouteConfig{
|
||||
Name: "dashboard_get_cli_download_url",
|
||||
})),
|
||||
),
|
||||
server.POST("/aiserver.v1.DashboardService/GetMe",
|
||||
server.Name("dashboard_get_me"),
|
||||
server.ConnectUnary(),
|
||||
|
||||
Reference in New Issue
Block a user