From 2d91c2a3f5f0741f313e8b88e79306c356e1a7b2 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 19 Dec 2025 18:13:15 +0800 Subject: [PATCH] add missing Kiro config synthesis --- internal/watcher/synthesizer/config.go | 97 ++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/internal/watcher/synthesizer/config.go b/internal/watcher/synthesizer/config.go index 4b19f2f3..f73ae3e7 100644 --- a/internal/watcher/synthesizer/config.go +++ b/internal/watcher/synthesizer/config.go @@ -4,8 +4,10 @@ import ( "fmt" "strings" + kiroauth "github.com/router-for-me/CLIProxyAPI/v6/internal/auth/kiro" "github.com/router-for-me/CLIProxyAPI/v6/internal/watcher/diff" coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth" + log "github.com/sirupsen/logrus" ) // ConfigSynthesizer generates Auth entries from configuration API keys. @@ -30,6 +32,8 @@ func (s *ConfigSynthesizer) Synthesize(ctx *SynthesisContext) ([]*coreauth.Auth, out = append(out, s.synthesizeClaudeKeys(ctx)...) // Codex API Keys out = append(out, s.synthesizeCodexKeys(ctx)...) + // Kiro (AWS CodeWhisperer) + out = append(out, s.synthesizeKiroKeys(ctx)...) // OpenAI-compat out = append(out, s.synthesizeOpenAICompat(ctx)...) // Vertex-compat @@ -292,3 +296,96 @@ func (s *ConfigSynthesizer) synthesizeVertexCompat(ctx *SynthesisContext) []*cor } return out } + +// synthesizeKiroKeys creates Auth entries for Kiro (AWS CodeWhisperer) tokens. +func (s *ConfigSynthesizer) synthesizeKiroKeys(ctx *SynthesisContext) []*coreauth.Auth { + cfg := ctx.Config + now := ctx.Now + idGen := ctx.IDGenerator + + if len(cfg.KiroKey) == 0 { + return nil + } + + out := make([]*coreauth.Auth, 0, len(cfg.KiroKey)) + kAuth := kiroauth.NewKiroAuth(cfg) + + for i := range cfg.KiroKey { + kk := cfg.KiroKey[i] + var accessToken, profileArn, refreshToken string + + // Try to load from token file first + if kk.TokenFile != "" && kAuth != nil { + tokenData, err := kAuth.LoadTokenFromFile(kk.TokenFile) + if err != nil { + log.Warnf("failed to load kiro token file %s: %v", kk.TokenFile, err) + } else { + accessToken = tokenData.AccessToken + profileArn = tokenData.ProfileArn + refreshToken = tokenData.RefreshToken + } + } + + // Override with direct config values if provided + if kk.AccessToken != "" { + accessToken = kk.AccessToken + } + if kk.ProfileArn != "" { + profileArn = kk.ProfileArn + } + if kk.RefreshToken != "" { + refreshToken = kk.RefreshToken + } + + if accessToken == "" { + log.Warnf("kiro config[%d] missing access_token, skipping", i) + continue + } + + // profileArn is optional for AWS Builder ID users + id, token := idGen.Next("kiro:token", accessToken, profileArn) + attrs := map[string]string{ + "source": fmt.Sprintf("config:kiro[%s]", token), + "access_token": accessToken, + } + if profileArn != "" { + attrs["profile_arn"] = profileArn + } + if kk.Region != "" { + attrs["region"] = kk.Region + } + if kk.AgentTaskType != "" { + attrs["agent_task_type"] = kk.AgentTaskType + } + if kk.PreferredEndpoint != "" { + attrs["preferred_endpoint"] = kk.PreferredEndpoint + } else if cfg.KiroPreferredEndpoint != "" { + // Apply global default if not overridden by specific key + attrs["preferred_endpoint"] = cfg.KiroPreferredEndpoint + } + if refreshToken != "" { + attrs["refresh_token"] = refreshToken + } + proxyURL := strings.TrimSpace(kk.ProxyURL) + a := &coreauth.Auth{ + ID: id, + Provider: "kiro", + Label: "kiro-token", + Status: coreauth.StatusActive, + ProxyURL: proxyURL, + Attributes: attrs, + CreatedAt: now, + UpdatedAt: now, + } + + if refreshToken != "" { + if a.Metadata == nil { + a.Metadata = make(map[string]any) + } + a.Metadata["refresh_token"] = refreshToken + } + + out = append(out, a) + } + return out +}