diff --git a/.gitignore b/.gitignore index 848c4b31..d4b5fc62 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,10 @@ _bmad-output/* # macOS .DS_Store ._* + +# Opencode +.beads/ +.opencode/ +.cli-proxy-api/ +.venv/ *.bak diff --git a/cmd/fetch_antigravity_models/main.go b/cmd/fetch_antigravity_models/main.go index 0cf45d3b..54ec16ca 100644 --- a/cmd/fetch_antigravity_models/main.go +++ b/cmd/fetch_antigravity_models/main.go @@ -188,7 +188,7 @@ func fetchModels(ctx context.Context, auth *coreauth.Auth) []modelEntry { httpReq.Close = true httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("Authorization", "Bearer "+accessToken) - httpReq.Header.Set("User-Agent", "antigravity/1.19.6 darwin/arm64") + httpReq.Header.Set("User-Agent", "antigravity/1.21.9 darwin/arm64") httpClient := &http.Client{Timeout: 30 * time.Second} if transport, _, errProxy := proxyutil.BuildHTTPTransport(auth.ProxyURL); errProxy == nil && transport != nil { diff --git a/cmd/server/main.go b/cmd/server/main.go index b6f5f47a..4bb90dc7 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -99,6 +99,7 @@ func main() { var codeBuddyLogin bool var projectID string var vertexImport string + var vertexImportPrefix string var configPath string var password string var tuiMode bool @@ -139,6 +140,7 @@ func main() { flag.StringVar(&projectID, "project_id", "", "Project ID (Gemini only, not required)") flag.StringVar(&configPath, "config", DefaultConfigPath, "Configure File Path") flag.StringVar(&vertexImport, "vertex-import", "", "Import Vertex service account key JSON file") + flag.StringVar(&vertexImportPrefix, "vertex-import-prefix", "", "Prefix for Vertex model namespacing (use with -vertex-import)") flag.StringVar(&password, "password", "", "") flag.BoolVar(&tuiMode, "tui", false, "Start with terminal management UI") flag.BoolVar(&standalone, "standalone", false, "In TUI mode, start an embedded local server") @@ -510,7 +512,7 @@ func main() { if vertexImport != "" { // Handle Vertex service account import - cmd.DoVertexImport(cfg, vertexImport) + cmd.DoVertexImport(cfg, vertexImport, vertexImportPrefix) } else if login { // Handle Google/Gemini login cmd.DoLogin(cfg, projectID, options) diff --git a/internal/auth/vertex/vertex_credentials.go b/internal/auth/vertex/vertex_credentials.go index 4853d340..9f830994 100644 --- a/internal/auth/vertex/vertex_credentials.go +++ b/internal/auth/vertex/vertex_credentials.go @@ -30,6 +30,10 @@ type VertexCredentialStorage struct { // Type is the provider identifier stored alongside credentials. Always "vertex". Type string `json:"type"` + + // Prefix optionally namespaces models for this credential (e.g., "teamA"). + // This results in model names like "teamA/gemini-2.0-flash". + Prefix string `json:"prefix,omitempty"` } // SaveTokenToFile writes the credential payload to the given file path in JSON format. diff --git a/internal/cmd/vertex_import.go b/internal/cmd/vertex_import.go index 32d782d8..4aa0d74b 100644 --- a/internal/cmd/vertex_import.go +++ b/internal/cmd/vertex_import.go @@ -20,7 +20,7 @@ import ( // DoVertexImport imports a Google Cloud service account key JSON and persists // it as a "vertex" provider credential. The file content is embedded in the auth // file to allow portable deployment across stores. -func DoVertexImport(cfg *config.Config, keyPath string) { +func DoVertexImport(cfg *config.Config, keyPath string, prefix string) { if cfg == nil { cfg = &config.Config{} } @@ -62,13 +62,28 @@ func DoVertexImport(cfg *config.Config, keyPath string) { // Default location if not provided by user. Can be edited in the saved file later. location := "us-central1" - fileName := fmt.Sprintf("vertex-%s.json", sanitizeFilePart(projectID)) + // Normalize and validate prefix: must be a single segment (no "/" allowed). + prefix = strings.TrimSpace(prefix) + prefix = strings.Trim(prefix, "/") + if prefix != "" && strings.Contains(prefix, "/") { + log.Errorf("vertex-import: prefix must be a single segment (no '/' allowed): %q", prefix) + return + } + + // Include prefix in filename so importing the same project with different + // prefixes creates separate credential files instead of overwriting. + baseName := sanitizeFilePart(projectID) + if prefix != "" { + baseName = sanitizeFilePart(prefix) + "-" + baseName + } + fileName := fmt.Sprintf("vertex-%s.json", baseName) // Build auth record storage := &vertex.VertexCredentialStorage{ ServiceAccount: sa, ProjectID: projectID, Email: email, Location: location, + Prefix: prefix, } metadata := map[string]any{ "service_account": sa, @@ -76,6 +91,7 @@ func DoVertexImport(cfg *config.Config, keyPath string) { "email": email, "location": location, "type": "vertex", + "prefix": prefix, "label": labelForVertex(projectID, email), } record := &coreauth.Auth{ diff --git a/internal/runtime/executor/antigravity_executor.go b/internal/runtime/executor/antigravity_executor.go index ea7682f8..b9bf4842 100644 --- a/internal/runtime/executor/antigravity_executor.go +++ b/internal/runtime/executor/antigravity_executor.go @@ -45,7 +45,7 @@ const ( antigravityGeneratePath = "/v1internal:generateContent" antigravityClientID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com" antigravityClientSecret = "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" - defaultAntigravityAgent = "antigravity/1.19.6 darwin/arm64" + defaultAntigravityAgent = "antigravity/1.21.9 darwin/arm64" antigravityAuthType = "antigravity" refreshSkew = 3000 * time.Second antigravityCreditsRetryTTL = 5 * time.Hour