diff --git a/Makefile b/Makefile index b37bfaf..152f528 100644 --- a/Makefile +++ b/Makefile @@ -114,18 +114,18 @@ run: build clean: rm -f cursor-api-proxy $(ENV_FILE) -## 設定 OpenCode 使用此代理(更新 opencode.json 的 cursor provider) +## 設定 OpenCode 使用此代理(更新 opencode.json 的 cursor 與 gemini-web provider) opencode: build @if [ ! -f "$(OPENCODE_CONFIG)" ]; then \ echo "找不到 $(OPENCODE_CONFIG),建立新設定檔"; \ mkdir -p $$(dirname "$(OPENCODE_CONFIG)"); \ - printf '{\n "model": "$(OPENCODE_MODEL)",\n "small_model": "$(OPENCODE_SMALL_MODEL)",\n "provider": {\n "cursor": {\n "npm": "@ai-sdk/openai-compatible",\n "name": "Cursor Agent",\n "options": {\n "baseURL": "http://$(HOST):$(PORT)/v1",\n "apiKey": "unused"\n },\n "models": { "auto": { "name": "Cursor Auto" } }\n }\n }\n}\n' > "$(OPENCODE_CONFIG)"; \ - echo "已建立 $(OPENCODE_CONFIG)"; \ + printf '{\n "model": "$(OPENCODE_MODEL)",\n "small_model": "$(OPENCODE_SMALL_MODEL)",\n "provider": {\n "cursor": {\n "npm": "@ai-sdk/openai-compatible",\n "name": "Cursor Agent",\n "options": {\n "baseURL": "http://$(HOST):$(PORT)/v1",\n "apiKey": "unused"\n },\n "models": { "auto": { "name": "Cursor Auto" } }\n },\n "gemini-web": {\n "npm": "@ai-sdk/openai-compatible",\n "name": "Gemini Web",\n "options": {\n "baseURL": "http://$(HOST):$(PORT)/v1",\n "apiKey": "unused"\n },\n "models": {\n "gemini-2.0-flash": { "name": "Gemini 2.0 Flash" },\n "gemini-2.5-pro": { "name": "Gemini 2.5 Pro" },\n "gemini-2.5-pro-thinking": { "name": "Gemini 2.5 Pro Thinking" }\n }\n }\n }\n}\n' > "$(OPENCODE_CONFIG)"; \ + echo "已建立 $(OPENCODE_CONFIG)(包含 cursor 與 gemini-web provider)"; \ elif [ -n "$(API_KEY)" ]; then \ - jq --arg model "$(OPENCODE_MODEL)" --arg small "$(OPENCODE_SMALL_MODEL)" --arg base "http://$(HOST):$(PORT)/v1" --arg key "$(API_KEY)" '.model = $$model | .small_model = $$small | .provider.cursor.options.baseURL = $$base | .provider.cursor.options.apiKey = $$key' "$(OPENCODE_CONFIG)" > "$(OPENCODE_CONFIG).tmp" && mv "$(OPENCODE_CONFIG).tmp" "$(OPENCODE_CONFIG)"; \ + jq --arg model "$(OPENCODE_MODEL)" --arg small "$(OPENCODE_SMALL_MODEL)" --arg base "http://$(HOST):$(PORT)/v1" --arg key "$(API_KEY)" '.model = $$model | .small_model = $$small | .provider.cursor.options.baseURL = $$base | .provider.cursor.options.apiKey = $$key | .provider["gemini-web"].options.baseURL = $$base | .provider["gemini-web"].options.apiKey = $$key' "$(OPENCODE_CONFIG)" > "$(OPENCODE_CONFIG).tmp" && mv "$(OPENCODE_CONFIG).tmp" "$(OPENCODE_CONFIG)"; \ echo "已更新 $(OPENCODE_CONFIG)(model=$(OPENCODE_MODEL), small_model=$(OPENCODE_SMALL_MODEL), baseURL → http://$(HOST):$(PORT)/v1,apiKey 已設定)"; \ else \ - jq --arg model "$(OPENCODE_MODEL)" --arg small "$(OPENCODE_SMALL_MODEL)" --arg base "http://$(HOST):$(PORT)/v1" '.model = $$model | .small_model = $$small | .provider.cursor.options.baseURL = $$base' "$(OPENCODE_CONFIG)" > "$(OPENCODE_CONFIG).tmp" && mv "$(OPENCODE_CONFIG).tmp" "$(OPENCODE_CONFIG)"; \ + jq --arg model "$(OPENCODE_MODEL)" --arg small "$(OPENCODE_SMALL_MODEL)" --arg base "http://$(HOST):$(PORT)/v1" '.model = $$model | .small_model = $$small | .provider.cursor.options.baseURL = $$base | .provider["gemini-web"].options.baseURL = $$base' "$(OPENCODE_CONFIG)" > "$(OPENCODE_CONFIG).tmp" && mv "$(OPENCODE_CONFIG).tmp" "$(OPENCODE_CONFIG)"; \ echo "已更新 $(OPENCODE_CONFIG)(model=$(OPENCODE_MODEL), small_model=$(OPENCODE_SMALL_MODEL), baseURL → http://$(HOST):$(PORT)/v1)"; \ fi @@ -138,8 +138,8 @@ opencode-models: opencode MODELS=$$(curl -s http://$(HOST):$(PORT)/v1/models | jq '[.data[].id]'); \ kill $$PID 2>/dev/null; wait $$PID 2>/dev/null; \ if [ -n "$$MODELS" ] && [ "$$MODELS" != "null" ]; then \ - jq --argjson ids "$$MODELS" 'reduce $ids[] as $id (.; .provider.cursor.models[$id] = { name: $id })' "$(OPENCODE_CONFIG)" > "$(OPENCODE_CONFIG).tmp" && mv "$(OPENCODE_CONFIG).tmp" "$(OPENCODE_CONFIG)"; \ - echo "已同步模型列表到 $(OPENCODE_CONFIG)"; \ + jq --argjson ids "$$MODELS" 'reduce $ids[] as $id (.; .provider.cursor.models[$id] = { name: $id } | .provider["gemini-web"].models[$id] = { name: $id })' "$(OPENCODE_CONFIG)" > "$(OPENCODE_CONFIG).tmp" && mv "$(OPENCODE_CONFIG).tmp" "$(OPENCODE_CONFIG)"; \ + echo "已同步模型列表到 $(OPENCODE_CONFIG)(cursor 與 gemini-web)"; \ else \ echo "無法取得模型列表,請確認代理已啟動"; \ fi @@ -299,8 +299,21 @@ help: @echo " make docker-restart 重新建置並啟動容器" @echo " make docker-shell 進入容器 shell(除錯用)" @echo "" + @echo "Provider 設定範例:" + @echo " make env PROVIDER=cursor # 使用 Cursor(預設)" + @echo " make env PROVIDER=gemini-web # 使用 Gemini Web" + @echo " make env PROVIDER=gemini-web GEMINI_ACCOUNT_DIR=/path/to/sessions" + @echo " make env PROVIDER=gemini-web GEMINI_BROWSER_VISIBLE=true" + @echo " make opencode # 設定 OpenCode(含 cursor 與 gemini-web provider)" + @echo "" @echo "覆寫範例:" @echo " make env PORT=9000 API_KEY=mysecret TIMEOUT_MS=60000" @echo " make pm2-claude-code PORT=8765 API_KEY=mykey" @echo " make pm2-opencode PORT=8765" @echo " make claude-settings PORT=8766 ANTHROPIC_BASE_HOST=localhost ANTHROPIC_DEFAULT_OPUS_MODEL=claude-4.6-opus-high" + @echo "" + @echo "使用 Gemini Web Provider:" + @echo " 1. make env PROVIDER=gemini-web" + @echo " 2. gemini-login my-session # 登入並儲存 session" + @echo " 3. make run # 啟動代理" + @echo " 4. 在 OpenCode 設定 model: gemini/gemini-2.5-pro" diff --git a/internal/logger/logger.go b/internal/logger/logger.go index c658e92..db18a0a 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -71,18 +71,29 @@ func LogDebug(format string, args ...interface{}) { } func LogServerStart(version, scheme, host string, port int, cfg config.BridgeConfig) { + provider := cfg.Provider + if provider == "" { + provider = "cursor" + } fmt.Printf("\n%s%s╔══════════════════════════════════════════╗%s\n", cBold, cBCyan, cReset) fmt.Printf("%s%s cursor-api-proxy %sv%s%s%s%s ready%s\n", cBold, cBCyan, cReset, cBold, cWhite, version, cBCyan, cReset) fmt.Printf("%s%s╚══════════════════════════════════════════╝%s\n\n", cBold, cBCyan, cReset) url := fmt.Sprintf("%s://%s:%d", scheme, host, port) fmt.Printf(" %s●%s listening %s%s%s\n", cBGreen, cReset, cBold, url, cReset) + fmt.Printf(" %s▸%s provider %s%s%s\n", cCyan, cReset, cBold, provider, cReset) fmt.Printf(" %s▸%s agent %s%s%s\n", cCyan, cReset, cDim, cfg.AgentBin, cReset) fmt.Printf(" %s▸%s workspace %s%s%s\n", cCyan, cReset, cDim, cfg.Workspace, cReset) fmt.Printf(" %s▸%s model %s%s%s\n", cCyan, cReset, cDim, cfg.DefaultModel, cReset) fmt.Printf(" %s▸%s mode %s%s%s\n", cCyan, cReset, cDim, cfg.Mode, cReset) fmt.Printf(" %s▸%s timeout %s%d ms%s\n", cCyan, cReset, cDim, cfg.TimeoutMs, cReset) + // 顯示 Gemini Web Provider 相關設定 + if provider == "gemini-web" { + fmt.Printf(" %s▸%s gemini-dir %s%s%s\n", cCyan, cReset, cDim, cfg.GeminiAccountDir, cReset) + fmt.Printf(" %s▸%s max-sess %s%d%s\n", cCyan, cReset, cDim, cfg.GeminiMaxSessions, cReset) + } + flags := []string{} if cfg.Force { flags = append(flags, "force")