Skip to content

Feature: Add Gemini and Z.ai (GLM) usage tracking#773

Open
gsxdsm wants to merge 4 commits intoAutoMaker-Org:v0.15.0rcfrom
gsxdsm:feat/add-zai-usage-tracking
Open

Feature: Add Gemini and Z.ai (GLM) usage tracking#773
gsxdsm wants to merge 4 commits intoAutoMaker-Org:v0.15.0rcfrom
gsxdsm:feat/add-zai-usage-tracking

Conversation

@gsxdsm
Copy link
Collaborator

@gsxdsm gsxdsm commented Feb 16, 2026

Add usage tracking for Gemini and Z.ai coding plan models.

Summary by CodeRabbit

Release Notes

  • New Features
    • Integrated z.ai provider with usage tracking, token quota management, and API key configuration
    • Integrated Gemini provider with quota and authentication status monitoring
    • Expanded usage popover to display z.ai and Gemini quota information alongside existing providers
    • Added z.ai API key verification and configuration in settings
    • Enhanced mobile and desktop UI to show usage indicators for z.ai and Gemini

@coderabbitai
Copy link

coderabbitai bot commented Feb 16, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive support for two new AI providers: z.ai and Gemini. It introduces backend services for usage tracking and API routes, alongside frontend UI components for authentication, configuration, and usage display, with corresponding type definitions and store updates.

Changes

Cohort / File(s) Summary
Backend z.ai Service
apps/server/src/services/zai-usage-service.ts, apps/server/src/routes/zai/index.ts
New z.ai integration with usage service for quota/token tracking via API, configurable host/token, token verification, and status reporting; routes handle /usage, /configure, /verify, /status endpoints with comprehensive error handling and logging.
Backend Gemini Service
apps/server/src/services/gemini-usage-service.ts, apps/server/src/routes/gemini/index.ts
New Gemini usage service extracting OAuth credentials from CLI installation, fetching quota data from internal endpoints with token refresh; routes expose /usage and /status endpoints with structured tier quotas and installation detection.
Backend Server Setup
apps/server/src/index.ts, apps/server/src/services/settings-service.ts
Routes and services instantiated and mounted; settings migration adds zai field to credentials alongside existing provider keys.
UI Type Definitions
apps/ui/src/store/types/usage-types.ts, libs/types/src/settings.ts, apps/ui/src/store/types/settings-types.ts
New usage data types for z.ai (ZaiUsage, ZaiQuotaLimit, ZaiPlanType) and Gemini (GeminiUsage, GeminiTierQuota, GeminiQuotaBucket) with response wrappers; credentials types extended with zai API key field.
UI Store - App State
apps/ui/src/store/app-store.ts, apps/ui/src/store/types/state-types.ts
New zaiUsage state field and setZaiUsage action added to app store; zai initialized in apiKeys; state mirrors Codex usage pattern for z.ai.
UI Store - Setup Auth
apps/ui/src/store/setup-store.ts
New ZaiAuthStatus and GeminiAuthStatus types; setup store extended with setZaiAuthStatus and setGeminiAuthStatus actions and corresponding state fields.
UI API Integration
apps/ui/src/lib/http-api-client.ts, apps/ui/src/lib/electron.ts
HTTP client and electron bridge extended with zai and gemini API methods (getStatus, getUsage, configure, verify for zai; getUsage for gemini) including mock implementations.
UI Query Hooks
apps/ui/src/hooks/queries/use-usage.ts, apps/ui/src/hooks/queries/index.ts, apps/ui/src/lib/query-keys.ts
New useZaiUsage and useGeminiUsage hooks with polling/refresh logic; error handling updated for Claude/Codex ("API bridge unavailable"); query keys added for zai and gemini.
UI Provider Config
apps/ui/src/config/api-providers.ts, apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts
ProviderKey extended with 'zai'; api-key management adds zai state, test connection, and server-side configuration; zai test endpoint and auth status updates wired into save flow.
UI Provider Icons
apps/ui/src/components/ui/provider-icon.tsx
GLM icon fill updated to explicit color; ZaiIcon exported as GlmIcon alias.
UI Provider Auth Initialization
apps/ui/src/hooks/use-provider-auth-init.ts
Hook extended to query z.ai and Gemini status endpoints; zai/gemini auth statuses wired into refresh logic; initialization guard updated to await all four provider statuses.
UI Usage Display
apps/ui/src/components/usage-popover.tsx, apps/ui/src/components/views/board-view/mobile-usage-bar.tsx, apps/ui/src/components/views/board-view/board-header.tsx, apps/ui/src/components/views/board-view/header-mobile-menu.tsx
Usage popover and mobile bar extended with z.ai and Gemini tabs/sections; formatting utilities added (formatResetTime, formatNumber); per-provider quota cards, authentication status, and error handling integrated; board header and mobile menu updated to show/pass z.ai and Gemini usage visibility flags.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI Component
    participant Store as App Store
    participant Hook as useZaiUsage Hook
    participant Client as HTTP API Client
    participant Server as Server (/api/zai)
    participant Service as ZaiUsageService
    participant ZaiAPI as z.ai API

    UI->>Hook: useZaiUsage(enabled=true)
    Hook->>Store: Read zaiUsage, check staleness
    alt Data is stale or missing
        Hook->>Client: http.zai.getUsage()
        Client->>Server: GET /api/zai/usage
        Server->>Service: fetchUsageData()
        Service->>ZaiAPI: POST /quota (with token)
        ZaiAPI-->>Service: Quota response
        Service->>Service: parseApiResponse()
        Service-->>Server: ZaiUsageData
        Server-->>Client: ZaiUsageData
        Client-->>Hook: ZaiUsageData
        Hook->>Store: setZaiUsage(data)
    end
    Store-->>UI: zaiUsage state
    UI->>UI: Render usage cards (tokens, MCP)
Loading
sequenceDiagram
    participant UI as UI Component
    participant Store as Setup Store
    participant Hook as useProviderAuthInit
    participant Client as HTTP API Client
    participant Server as Server (/api/gemini)
    participant Service as GeminiUsageService
    participant CLI as Gemini CLI

    Hook->>Client: http.setup.getGeminiStatus()
    Client->>Server: GET /api/gemini/status
    Server->>Service: Create GeminiProvider instance
    Service->>Service: detectInstallation()
    Service->>CLI: Find binary, read oauth2.js
    CLI-->>Service: OAuth credentials, version
    Service->>Service: Extract clientId/clientSecret
    Service-->>Server: Status payload
    Server-->>Client: { installed, authenticated, version, method }
    Client-->>Hook: Status data
    Hook->>Store: setGeminiAuthStatus(status)
    Store-->>UI: geminiAuthStatus
    UI->>UI: Enable/disable Gemini features
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Enhancement


🐰 Two new friends hop into the warren,
z.ai and Gemini, no need for sparrin',
Quotas and tokens, we track 'em with care,
Usage displayed, for all users to share!

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding usage tracking for two new providers (Gemini and Z.ai). The changeset contains extensive additions for both services including routes, services, UI components, and state management.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into v0.15.0rc

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gsxdsm gsxdsm changed the base branch from main to v0.15.0rc February 16, 2026 05:23
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @gsxdsm, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly expands the platform's monitoring capabilities by integrating usage tracking for Gemini and Z.ai models, offering users better visibility into their coding plan consumption. It also refines the Claude model experience by upgrading to Opus 4.6 with adaptive thinking and enhances authentication diagnostics. Furthermore, the update includes support for the latest GPT-5.3-Codex model and streamlines the Docker environment for automated testing with Playwright.

Highlights

  • Gemini and Z.ai Usage Tracking: Introduced comprehensive usage tracking for Gemini and Z.ai (GLM) coding plan models, including new API routes, services, and UI components to display real-time quota and usage data.
  • Claude Opus 4.6 Integration with Adaptive Thinking: Updated the Claude Opus model to version 4.6, which now supports 'adaptive thinking'. This feature allows the model to dynamically determine its reasoning depth, removing the need for a fixed token budget for thinking. The UI has been updated to reflect this new thinking level option.
  • Enhanced Claude CLI Authentication Logging: Improved the Claude CLI authentication process by adding detailed logging and better detection of OAuth tokens versus API keys, providing more clarity during setup and credential checks.
  • New GPT-5.3-Codex Model: Added support for the new GPT-5.3-Codex model, updating model definitions and descriptions across the application to reflect its status as the latest frontier agentic coding model.
  • Playwright Chromium Pre-installation in Docker: Integrated Playwright Chromium directly into the Docker image, enabling automated AI agent verification tests out-of-the-box without additional setup. Documentation has been updated to guide users on persisting browser installations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .gitignore
    • Added new entries for '.mcp.json' and '.planning' to ignore files generated by the system.
  • CLAUDE.md
    • Updated the Claude Opus model version from 'claude-opus-4-5-20251101' to 'claude-opus-4-6'.
  • Dockerfile
    • Added a blank line after the OpenCode CLI installation command for formatting.
    • Installed Playwright Chromium browser for AI agent verification tests, adding approximately 300MB to the image size.
  • README.md
    • Added a new section detailing Playwright Chromium pre-installation in the Docker image for automated testing.
    • Included instructions for optionally persisting Playwright browsers using a volume mount and manually updating them.
  • apps/server/package.json
    • Updated the @anthropic-ai/claude-agent-sdk dependency from 0.1.76 to 0.2.32.
    • Updated the @openai/codex-sdk dependency from 0.77.0 to 0.98.0.
    • Added @playwright/test version 1.57.0 as a dev dependency.
  • apps/server/src/index.ts
    • Imported createZaiRoutes, ZaiUsageService, and createGeminiRoutes.
    • Initialized zaiUsageService.
    • Registered new API routes for /api/zai and /api/gemini.
  • apps/server/src/lib/sdk-options.ts
    • Updated the buildThinkingOptions function to support 'adaptive' thinking for Claude Opus 4.6, omitting maxThinkingTokens when adaptive thinking is selected.
  • apps/server/src/providers/claude-provider.ts
    • Updated the Claude Opus model ID from 'claude-opus-4-5-20251101' to 'claude-opus-4-6' in getAvailableModels.
    • Adjusted the maxOutputTokens for Claude Opus 4.6 from 16000 to 128000.
    • Modified the description for Claude Opus 4.6 to highlight adaptive thinking.
    • Updated the maxThinkingTokens logic to set it to undefined for 'adaptive' thinking levels.
  • apps/server/src/providers/codex-models.ts
    • Added a new GPT-5.3-Codex model definition.
    • Updated the description for GPT-5.2-Codex and GPT-5.1-Codex-Max models.
    • Modified the description for GPT-5.1-Codex-Mini and GPT-5.2 models.
  • apps/server/src/providers/provider-factory.ts
    • Updated the example model ID in the JSDoc for getProviderForModel to 'claude-opus-4-6'.
  • apps/server/src/routes/gemini/index.ts
    • Added a new file to define API routes for Gemini usage and status, including endpoints for fetching usage data and checking CLI installation/authentication status.
  • apps/server/src/routes/setup/routes/verify-claude-auth.ts
    • Imported getClaudeAuthIndicators from @automaker/platform.
    • Enhanced the Claude authentication verification logic to determine and return a specific authType ('oauth', 'api_key', or 'cli').
  • apps/server/src/routes/zai/index.ts
    • Added a new file to define API routes for Z.ai usage, configuration, and verification, including endpoints for fetching usage data, setting API tokens, and testing API key validity.
  • apps/server/src/services/gemini-usage-service.ts
    • Added a new file to implement the GeminiUsageService, responsible for tracking Gemini CLI usage and quota by interacting with Google Cloud's internal quota API and extracting OAuth credentials.
  • apps/server/src/services/settings-service.ts
    • Added a 'zai' property to the apiKeys object within the credentials migration logic, initializing it as an empty string.
  • apps/server/src/services/zai-usage-service.ts
    • Added a new file to implement the ZaiUsageService, which fetches usage quota data from the z.ai API, handles API token authentication, and parses various API response formats.
  • apps/server/tests/unit/lib/model-resolver.test.ts
    • Updated expected model string for 'opus' alias to 'claude-opus-4-6' in unit tests.
  • apps/server/tests/unit/lib/sdk-options.test.ts
    • Added new test cases for 'adaptive' thinking level, ensuring maxThinkingTokens is not set for adaptive thinking in createAutoModeOptions.
  • apps/server/tests/unit/providers/claude-provider.test.ts
    • Updated all references to the Claude Opus model ID from 'claude-opus-4-5-20251101' to 'claude-opus-4-6' in unit tests.
  • apps/server/tests/unit/providers/provider-factory.test.ts
    • Updated expected model ID for ClaudeProvider tests to 'claude-opus-4-6'.
  • apps/ui/docs/AGENT_ARCHITECTURE.md
    • Updated the example model in the agent configuration snippet from 'claude-opus-4-5-20251101' to 'claude-opus-4-6'.
  • apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx
    • Added a new section with troubleshooting steps for users running Automaker in Docker, including checks for IS_CONTAINERIZED and server logs.
  • apps/ui/src/components/ui/provider-icon.tsx
    • Added a fill color (#3B82F6) to the GLM icon definition.
    • Exported ZaiIcon as an alias of GlmIcon.
  • apps/ui/src/components/usage-popover.tsx
    • Imported ZaiIcon and GeminiIcon.
    • Imported useZaiUsage and useGeminiUsage hooks.
    • Modified formatCodexResetTime to be a general formatResetTime and added a legacy alias.
    • Added a formatNumber helper function for large numbers.
    • Integrated Z.ai and Gemini usage data fetching and display into the usage popover, including new tabs and usage cards.
    • Adjusted tab visibility logic to include Z.ai and Gemini.
  • apps/ui/src/components/views/board-view/board-header.tsx
    • Added zaiAuthStatus and geminiAuthStatus to the component state.
    • Implemented logic to determine showZaiUsage and showGeminiUsage based on authentication status.
    • Updated the UsagePopover and HeaderMobileMenu components to conditionally display based on Z.ai and Gemini usage visibility.
  • apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx
    • Imported isAdaptiveThinkingModel from @automaker/types.
    • Modified handleModelChange to normalize thinking levels when switching between adaptive and non-adaptive models (e.g., auto-switching to 'adaptive' for Opus 4.6 or 'high' when switching away).
  • apps/ui/src/components/views/board-view/header-mobile-menu.tsx
    • Added showZaiUsage and showGeminiUsage props.
    • Updated conditional rendering for MobileUsageBar to include Z.ai and Gemini usage.
  • apps/ui/src/components/views/board-view/mobile-usage-bar.tsx
    • Imported ZaiIcon and GeminiIcon.
    • Added showZaiUsage and showGeminiUsage props.
    • Implemented formatNumber and formatResetTime helper functions.
    • Added state for Z.ai and Gemini usage, loading, and last updated times.
    • Integrated fetching and display of Z.ai and Gemini usage data, including usage bars for tokens, MCP, Flash, and Pro quotas.
  • apps/ui/src/components/views/board-view/shared/model-constants.ts
    • Added 'adaptive' to THINKING_LEVELS and THINKING_LEVEL_LABELS.
  • apps/ui/src/components/views/board-view/shared/thinking-level-selector.tsx
    • Imported getThinkingLevelsForModel from @automaker/types.
    • Modified the component to filter available thinking levels based on the selected model, specifically for adaptive thinking models.
    • Updated the descriptive text to explain adaptive thinking.
  • apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts
    • Imported useQueryClient, useSetupStore, getHttpApiClient, and queryKeys.
    • Added hasZaiKey to ApiKeyStatus interface.
    • Added state for zaiKey, showZaiKey, testingZaiConnection, and zaiTestResult.
    • Implemented handleTestZaiConnection to verify Z.ai API keys.
    • Modified handleSave to persist zaiKey and configure the Z.ai service on the server, including updating Z.ai auth status and invalidating usage queries.
  • apps/ui/src/components/views/settings-view/model-defaults/phase-model-selector.tsx
    • Imported getThinkingLevelsForModel from @automaker/types.
    • Updated the thinking level options to dynamically show 'adaptive' for appropriate models and provide a description for it.
  • apps/ui/src/components/views/settings-view/providers/codex-model-configuration.tsx
    • Imported supportsReasoningEffort from @automaker/types.
    • Added codex-gpt-5.3-codex to CODEX_MODEL_INFO.
    • Updated descriptions for existing Codex models.
  • apps/ui/src/components/views/setup-view/steps/claude-setup-step.tsx
    • Added cliAuthType state to track the specific type of Claude CLI authentication.
    • Modified verifyCliAuth to store authType and display specific success messages for Claude Code subscription (OAuth) vs. generic CLI authentication.
  • apps/ui/src/config/api-providers.ts
    • Added 'zai' to ProviderKey type.
    • Included Z.ai API key configuration in buildProviderConfigs, defining its label, input fields, test button, and description.
  • apps/ui/src/hooks/queries/index.ts
    • Exported useZaiUsage and useGeminiUsage from ./use-usage.
  • apps/ui/src/hooks/queries/use-usage.ts
    • Updated JSDoc to include z.ai and Gemini API usage data.
    • Modified error messages for Claude and Codex API unavailability to specify 'API bridge unavailable'.
    • Added useZaiUsage hook to fetch z.ai API usage data with polling.
    • Added useGeminiUsage hook to fetch Gemini API usage/status data with polling.
  • apps/ui/src/hooks/use-provider-auth-init.ts
    • Added setZaiAuthStatus, setGeminiCliStatus, setGeminiAuthStatus, zaiAuthStatus, and geminiAuthStatus to the component state.
    • Extended refreshStatuses to initialize Z.ai and Gemini authentication statuses on app startup.
    • Updated the useEffect dependency array to include new Z.ai and Gemini auth statuses.
  • apps/ui/src/lib/agent-context-parser.ts
    • Updated DEFAULT_MODEL to 'claude-opus-4-6'.
    • Modified formatModelName to display 'Opus 4.6' and 'GPT-5.3 Codex' correctly.
  • apps/ui/src/lib/electron.ts
    • Imported new usage response types for Z.ai and Gemini.
    • Added zai and gemini properties to the ElectronAPI interface, defining their respective API methods.
    • Implemented mock data for zai and gemini API calls in _getMockElectronAPI.
    • Added authType to the return type of verifyClaudeAuth in SetupAPI.
  • apps/ui/src/lib/http-api-client.ts
    • Imported GeminiUsage type.
    • Added authType to the return type of verifyClaudeAuth.
    • Implemented zai API client methods for status, usage, configure, and verify.
    • Implemented gemini API client method for getUsage.
  • apps/ui/src/lib/query-keys.ts
    • Added new query keys for zai and gemini API usage.
  • apps/ui/src/store/app-store.ts
    • Imported new types for Z.ai and Gemini usage.
    • Added zai to the initial apiKeys state.
    • Added zaiUsage and zaiUsageLastUpdated to the initial AppState.
    • Added setZaiUsage action to update Z.ai usage state.
  • apps/ui/src/store/setup-store.ts
    • Defined new types ZaiAuthMethod, ZaiAuthStatus, GeminiAuthMethod, and GeminiAuthStatus.
    • Added geminiAuthStatus and zaiAuthStatus to SetupState.
    • Added setGeminiAuthStatus and setZaiAuthStatus actions to SetupActions.
  • apps/ui/src/store/types/settings-types.ts
    • Added zai property to the ApiKeys interface.
  • apps/ui/src/store/types/state-types.ts
    • Imported ZaiUsage type.
    • Added zaiUsage and zaiUsageLastUpdated properties to AppState.
    • Added setZaiUsage to AppActions.
  • apps/ui/src/store/types/usage-types.ts
    • Defined new types for Z.ai usage (ZaiPlanType, ZaiQuotaLimit, ZaiUsage, ZaiUsageResponse).
    • Defined new types for Gemini usage (GeminiQuotaBucket, GeminiTierQuota, GeminiUsage, GeminiUsageResponse).
  • docker-compose.override.yml.example
    • Updated comments for the Playwright browser cache section, clarifying pre-installation and manual update instructions.
  • docs/llm-shared-packages.md
    • Updated the Claude Opus model version from 'claude-opus-4-5-20251101' to 'claude-opus-4-6'.
  • docs/server/providers.md
    • Updated Claude Opus model references from 'claude-opus-4-5-20251101' to 'claude-opus-4-6' in documentation examples.
  • docs/server/utilities.md
    • Updated Claude Opus model references from 'claude-opus-4-5-20251101' to 'claude-opus-4-6' in documentation examples.
  • libs/model-resolver/README.md
    • Updated Claude Opus model references from 'claude-opus-4-5-20251101' to 'claude-opus-4-6' in README examples.
  • libs/model-resolver/tests/resolver.test.ts
    • Updated Claude Opus model references from 'claude-opus-4-5-20251101' to 'claude-opus-4-6' in unit tests.
  • libs/platform/src/index.ts
    • Exported FileCheckResult and DirectoryCheckResult types.
  • libs/platform/src/system-paths.ts
    • Added getNvmWindowsCliPaths helper function to include NVM for Windows symlink paths for CLI tools.
    • Integrated getNvmWindowsCliPaths into getClaudeCliPaths, getCodexCliPaths, and getOpenCodeCliPaths.
    • Defined FileCheckResult and DirectoryCheckResult interfaces.
    • Enhanced getClaudeAuthIndicators to provide detailed checks results for settings file, stats cache, projects directory, and credential files, including existence, readability, and error information.
  • libs/platform/tests/oauth-credential-detection.test.ts
    • Added a new file containing comprehensive unit tests for OAuth credential detection scenarios, covering various Claude, Codex, and OpenCode authentication file formats, edge cases, and combined setups.
  • libs/types/src/codex-models.ts
    • Added codex-gpt-5.3-codex to CodexModelId type.
    • Included codex-gpt-5.3-codex in CODEX_MODEL_CONFIG_MAP with its description and capabilities.
    • Updated descriptions for existing Codex models like gpt52Codex, gpt51CodexMax, gpt51CodexMini, and gpt52.
  • libs/types/src/event.ts
    • Added dev-server:url-detected to EventType.
  • libs/types/src/index.ts
    • Exported isAdaptiveThinkingModel and getThinkingLevelsForModel.
  • libs/types/src/model-display.ts
    • Added codex-gpt-5.3-codex to CODEX_MODELS.
    • Updated descriptions for existing Codex models.
    • Added 'adaptive' to THINKING_LEVELS and THINKING_LEVEL_LABELS.
  • libs/types/src/model.ts
    • Updated CLAUDE_CANONICAL_MAP and CLAUDE_MODEL_MAP to reference 'claude-opus-4-6' instead of 'claude-opus-4-5-20251101'.
    • Added gpt53Codex to CODEX_MODEL_MAP and REASONING_CAPABLE_MODELS.
    • Updated descriptions for various Codex models in CODEX_MODEL_MAP.
  • libs/types/src/settings.ts
    • Added 'adaptive' to ThinkingLevel type.
    • Included adaptive: undefined in THINKING_TOKEN_BUDGET.
    • Added isAdaptiveThinkingModel and getThinkingLevelsForModel functions.
    • Added zai property to ApiKeys and Credentials interfaces, and to DEFAULT_CREDENTIALS.
  • package-lock.json
    • Updated @anthropic-ai/claude-agent-sdk to 0.2.32.
    • Updated @openai/codex-sdk to 0.98.0.
    • Adjusted zod peer dependency version for @anthropic-ai/claude-agent-sdk.
    • Removed peer: true from several @playwright/browser-chromium entries.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds usage tracking for Gemini and Z.ai models, including backend services, API routes, and UI components. The changes are extensive and well-structured. I've identified a few areas for improvement, mainly concerning error handling, performance in synchronous calls, and code duplication in the new backend services. Additionally, there's a minor regression in the UI that should be addressed. Overall, this is a solid feature addition.

Comment on lines +22 to +30
// Return error in a format the UI expects
res.status(200).json({
authenticated: false,
authMethod: 'none',
usedPercent: 0,
remainingPercent: 100,
lastUpdated: new Date().toISOString(),
error: `Failed to fetch Gemini usage: ${message}`,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The catch block for the /usage route currently returns a 200 status with authenticated: false for any unexpected error. This can be misleading, as an error (e.g., a file parsing error for credentials) doesn't necessarily mean the user is unauthenticated. For unexpected server-side errors, it's more appropriate to return a 500 status code. This provides a clearer signal to the client that something went wrong on the server, distinct from a normal "not authenticated" state which is handled gracefully within the service.

      res.status(500).json({
        error: `An unexpected error occurred while fetching Gemini usage: ${message}`,
      });

private findGeminiBinaryPath(): string | null {
try {
// Try 'which' on Unix-like systems
const whichResult = execSync('which gemini 2>/dev/null', { encoding: 'utf8' }).trim();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of execSync is synchronous and blocks the Node.js event loop, which can degrade server performance. While extractOAuthClientCredentials caches the result, the first call to this endpoint will block. This happens again on line 559. It is recommended to use the asynchronous exec from child_process and make the calling functions (findGeminiBinaryPath and extractOAuthClientCredentials) async to avoid blocking.

Comment on lines +113 to +126
// Test the key by making a request to z.ai API
const quotaUrl =
process.env.Z_AI_QUOTA_URL ||
`${process.env.Z_AI_API_HOST ? `https://${process.env.Z_AI_API_HOST}` : 'https://api.z.ai'}/api/monitor/usage/quota/limit`;

logger.info(`[verify] Testing API key against: ${quotaUrl}`);

const response = await fetch(quotaUrl, {
method: 'GET',
headers: {
Authorization: `Bearer ${apiKey.trim()}`,
Accept: 'application/json',
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for constructing the quotaUrl and performing the API key verification is implemented directly in this route handler. This duplicates logic from ZaiUsageService and couples the route tightly with the external API's implementation details. To improve separation of concerns and code reuse, this verification logic should be moved into a new method on the ZaiUsageService.

Comment on lines 354 to 359
: activeTab === 'codex'
? {
icon: OpenAIIcon,
percentage: codexWindowUsage ?? 0,
isStale: isCodexStale,
title: `Usage (${codexWindowLabel})`,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The title property for the codex case in indicatorInfo seems to have been accidentally removed. This will result in an empty title attribute for the usage indicator when the Codex tab is active. The previous implementation included a title, which should be restored for consistency and better user experience.

        ? {
           icon: OpenAIIcon,
           percentage: codexWindowUsage ?? 0,
           isStale: isCodexStale,
           title: `Usage (${codexWindowLabel})`,
         }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/server/src/services/settings-service.ts (1)

728-754: ⚠️ Potential issue | 🟠 Major

getMaskedCredentials() does not include the new zai key.

The method returns masked credentials for anthropic, google, and openai but omits the newly added zai key. This means the UI cannot display whether a z.ai API key is configured.

🔧 Proposed fix
   async getMaskedCredentials(): Promise<{
     anthropic: { configured: boolean; masked: string };
     google: { configured: boolean; masked: string };
     openai: { configured: boolean; masked: string };
+    zai: { configured: boolean; masked: string };
   }> {
     const credentials = await this.getCredentials();
 
     const maskKey = (key: string): string => {
       if (!key || key.length < 8) return '';
       return `${key.substring(0, 4)}...${key.substring(key.length - 4)}`;
     };
 
     return {
       anthropic: {
         configured: !!credentials.apiKeys.anthropic,
         masked: maskKey(credentials.apiKeys.anthropic),
       },
       google: {
         configured: !!credentials.apiKeys.google,
         masked: maskKey(credentials.apiKeys.google),
       },
       openai: {
         configured: !!credentials.apiKeys.openai,
         masked: maskKey(credentials.apiKeys.openai),
       },
+      zai: {
+        configured: !!credentials.apiKeys.zai,
+        masked: maskKey(credentials.apiKeys.zai),
+      },
     };
   }
apps/ui/src/components/usage-popover.tsx (1)

30-46: ⚠️ Potential issue | 🟡 Minor

Guard against past reset times in formatResetTime.

If the reset time is already in the past, the current logic yields negative “Resets in -Xm” text. Add a clamp or fallback message.

🧹 Suggested fix
   const now = new Date();
   const diff = date.getTime() - now.getTime();
+  if (diff <= 0) {
+    return 'Resetting soon';
+  }
🤖 Fix all issues with AI agents
In `@apps/server/src/routes/gemini/index.ts`:
- Around line 35-57: Remove the unsafe (status as any) casts: use the typed
InstallationStatus returned by GeminiProvider.detectInstallation() and compute
authMethod using the existing fields (status.authenticated / status.hasApiKey)
without casting; also remove or type-augment hasCredentialsFile—either add
hasCredentialsFile to the InstallationStatus interface (and populate it in
detectInstallation) or stop returning hasCredentialsFile and default it to false
in the JSON response; update the route in apps/server/src/routes/gemini/index.ts
(references: GeminiProvider, detectInstallation, authMethod, hasCredentialsFile,
InstallationStatus) accordingly.

In `@apps/server/src/routes/zai/index.ts`:
- Around line 63-155: The route handlers for router.post('/configure') and
router.post('/verify') contain business logic
(usageService.setApiToken/setApiHost, settingsService.updateCredentials, fetch
to quota URL and response handling) and must be moved into ZaiUsageService (or a
new service) as methods like configure({apiToken, apiHost}) and
verifyApiKey(apiKey); those service methods should perform the persistence (call
settingsService.updateCredentials), runtime updates (usageService calls),
external fetch, and emit events via the shared emitter from createEventEmitter()
(e.g., emit 'zai.configured' and 'zai.verify.result' with status and error
info). Update the route handlers to simply call ZaiUsageService.configure(...)
and ZaiUsageService.verifyApiKey(...), await results, and return minimal JSON
responses, handling exceptions only to map errors to HTTP responses. Ensure you
reference and replace direct calls to usageService and
settingsService.updateCredentials inside the service and add emitter.emit calls
for UI updates.
- Around line 120-147: The z.ai verification fetch call can hang indefinitely;
update the fetch invocation in the route handler that calls quotaUrl to pass a
signal created via AbortSignal.timeout(timeoutMs) (e.g., const controllerSignal
= AbortSignal.timeout(5000)) in the fetch options so the request auto-aborts
after a reasonable timeout, and enhance the catch block to handle aborts (detect
AbortError / error.name === 'AbortError' and return a clear timeout JSON
response). Ensure you reference the existing fetch call that sets headers
Authorization/Accept and the surrounding try/catch so you only add the signal
option and the abort-specific error branch.

In `@apps/server/src/services/gemini-usage-service.ts`:
- Around line 688-697: The refreshed token is always written to
this.credentialsPath (e.g., in the getValidAccessToken flow) even when
credentials were loaded from a different file (such as
~/.config/gemini/oauth_creds.json), causing divergence; modify the
credential-loading logic (where cachedCredentials is set) to record the actual
source path into a new property (e.g., this.loadedCredentialsPath) and then
change the write path in the save/refresh block to use that recorded
this.loadedCredentialsPath (falling back to this.credentialsPath if not set) so
refreshed tokens are persisted back to the same file they were read from.
- Around line 349-353: The possiblePaths array contains a duplicate because the
constructor already sets this.credentialsPath to the home
'.gemini/oauth_creds.json' path; remove the redundant literal path from
possiblePaths or dedupe the array before use (e.g., filter out duplicates by
keeping only the first occurrence) so possiblePaths only contains unique
entries; update references around possiblePaths and ensure the logic using
possiblePaths still checks the same fallback locations in
GeminiUsageService/constructor.
- Around line 343-384: The cachedCredentials in loadCredentials() is never
invalidated so stale/expired creds persist; modify loadCredentials (and/or
clearCache()) to implement automatic invalidation by adding a TTL (e.g., 5
minutes) or validating the credentials file mtime before returning
cachedCredentials: store a cachedAt timestamp alongside cachedCredentials when
setting it in loadCredentials(), and when loadCredentials is called check if
cachedAt + TTL has expired or if fs.statSync(credPath).mtimeMs is newer than
cachedAt — if expired or file changed, discard cachedCredentials and re-read
from disk (then update cachedAt); ensure clearCache() still exists to allow
explicit invalidation and reference credentialsPath/possiblePaths when comparing
mtimes.
- Around line 557-578: The fallback search in extractOAuthClientCredentials uses
execSync with an interpolated baseDir, creating a command-injection and
quoting/portability risk; change it to only run on POSIX (guard with
process.platform !== 'win32') and replace the string-shell execSync call with a
safe execFileSync/spawnSync invocation that passes 'find' and its arguments as
an array (e.g., args: [ `${baseDir}/..`, '-name', 'oauth2.js', '-path',
'*gemini*', '-path', '*code_assist*' ]) to avoid shell interpolation, keep the
same encoding/timeout options, then proceed to read and pass the result to
parseOAuthCredentialsFromSource and set this.cachedClientCredentials as before.
- Around line 168-202: The external fetch calls in fetchUsageData
(CODE_ASSIST_URL, QUOTA_API_URL, GOOGLE_TOKEN_URL) lack timeouts and can hang;
add an AbortSignal with a timeout for each request (e.g., use
AbortSignal.timeout(timeoutMs) or new AbortController().signal with setTimeout
to abort) and pass the signal option into fetch, catch the resulting
abort/timeout errors and handle/log them similarly to other fetch failures;
ensure each fetch (the code block around CODE_ASSIST_URL, the QUOTA_API_URL
POST, and the GOOGLE_TOKEN_URL call) is updated to create/use a signal and clean
up any controllers if you use AbortController.

In `@apps/server/src/services/zai-usage-service.ts`:
- Around line 165-176: The fetchUsageData method does not emit lifecycle events
for frontend streaming; modify fetchUsageData to call createEventEmitter()
(import from lib/events.ts) at start and emit a "zai.usage.start" event, then
emit "zai.usage.success" with the fetched ZaiUsageData on successful completion,
and emit "zai.usage.error" with error details if any exception occurs (rethrow
after emitting). Use the existing method name fetchUsageData and the same logger
for messages, ensure the emitter is created inside the method and closed/handled
per createEventEmitter's contract so events stream via WebSocket to the
frontend.
- Around line 182-190: The fetch call to quotaUrl currently has no timeout; wrap
it with an AbortController and a timeout like other services (e.g.,
verify-claude-auth.ts/event-hook-service.ts): create an AbortController, start a
setTimeout to call controller.abort() after the configured timeout, pass
controller.signal into the fetch options (where Authorization and Accept headers
are set), and clear the timeout after fetch completes; also handle the abort
error case so the calling function (the code around quotaUrl/token/response)
throws or returns a proper timeout error instead of hanging.

In `@apps/ui/src/components/views/board-view/mobile-usage-bar.tsx`:
- Around line 38-54: The formatResetTime function returns negative "Resets in
-Xm" for past timestamps; update formatResetTime(unixTimestamp, isMilliseconds)
to detect diff <= 0 and return a short message like "Resetting soon" (matching
server-side behavior) before computing minutes/hours/dates, keeping the existing
branches for <1h, <24h and fallback to date; touch the function name
formatResetTime and ensure the diff calculation (const diff = date.getTime() -
now.getTime()) is used to decide the early-return for past/resetting-soon cases.
- Around line 166-167: Add geminiUsage and geminiUsageLastUpdated to the
existing Zustand store alongside the other provider states (the same store that
exposes setClaudeUsage/setCodexUsage/setZaiUsage): add state fields geminiUsage:
GeminiUsage | null and geminiUsageLastUpdated: number | null, and a setter
setGeminiUsage((usage, lastUpdated?) => void) that updates both fields. In
mobile-usage-bar.tsx remove the local useState declarations for geminiUsage and
geminiUsageLastUpdated and replace them with the store selectors/hooks (e.g.,
const { geminiUsage, geminiUsageLastUpdated, setGeminiUsage } = useStore(...))
and update any places that call setGeminiUsage to use the store setter. Ensure
types match the existing GeminiUsage type and that other components (like
UsagePopover) can read the new store fields.

In
`@apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts`:
- Around line 239-259: The code persists the z.ai key to the local store via
setApiKeys before calling api.zai.configure, and uses a loose check
(result.success || result.isAvailable) so the local state can show "Saved" even
if server config failed; either move the setApiKeys call so it runs only after
api.zai.configure succeeds (and then update setZaiAuthStatus and call
queryClient.invalidateQueries), or implement a rollback in the catch where you
remove the stored zai key using the same setApiKeys call; also tighten the
success condition to require result.success (not just isAvailable) when deciding
success for configuring z.ai.
- Around line 246-252: The code in use-api-key-management.ts hardcodes
hasEnvApiKey: false when calling setZaiAuthStatus after saving a UI key, which
can incorrectly clear an existing env-configured key; update the call in the
block that calls setZaiAuthStatus to preserve the current env key flag by
reading the existing apiKeyStatus (e.g., use apiKeyStatus.hasEnvApiKey) and set
hasEnvApiKey to that value instead of false so you only update the fields that
truly change (authenticated, method, hasApiKey) while keeping hasEnvApiKey in
sync.
- Line 1: Remove the top-level "// `@ts-nocheck`" and add explicit TypeScript
typings for the hook and its internal entities: declare interfaces/types such as
ApiKey (id, name, key, createdAt, revoked?), ApiKeyState (array + validation
errors), AuthState (isAuthenticated, userId, token), and ServerConfig
(allowedOrigins, keyPolicy) used by the useApiKeyManagement hook; update
function signatures (useApiKeyManagement, loadApiKeys, saveApiKeys,
validateApiKey, revokeApiKey) and React state hooks to use these types, type any
localStorage/parsing and async calls with proper unions/Optionals, and fix
resulting type errors rather than silencing them so the file compiles with full
type safety.

In `@apps/ui/src/hooks/use-provider-auth-init.ts`:
- Around line 133-138: The code is assigning the wrong field to the CLI path:
update the call to setGeminiCliStatus so the path uses result.path (the actual
filesystem path) instead of result.status; locate the block where
setGeminiCliStatus is called (in use-provider-auth-init.ts) and replace the
path: result.status assignment with path: result.path while keeping installed:
result.installed ?? false and version: result.version unchanged.
- Around line 107-124: The z.ai auth response handler (api.zai.getStatus) can
leave authenticated/hasApiKey undefined; update the logic in the try block that
calls setZaiAuthStatus so it coerces result.available, result.hasApiKey, and
result.hasEnvApiKey to booleans (e.g., using !! or ?? false) and derive method
using those boolean values, and also add a fallback setZaiAuthStatus in the
non-success/exception path to set authenticated: false, method: 'none',
hasApiKey: false, hasEnvApiKey: false; reference setZaiAuthStatus,
api.zai.getStatus, and ZaiAuthMethod when making the changes.
🧹 Nitpick comments (6)
apps/ui/src/store/app-store.ts (1)

97-105: Consider hoisting Zai/Gemini usage types into @automaker/types.

These usage shapes now exist in both server services and the UI store; centralizing them avoids drift and simplifies cross-layer contracts.
Based on learnings, “Core TypeScript definitions with no dependencies should be isolated in the automaker/types package”.

Also applies to: 184-191

apps/ui/src/store/types/usage-types.ts (3)

65-66: limitType: 'TOKENS_LIMIT' | 'TIME_LIMIT' | string — the literal union members are redundant.

Since string is a supertype of all string literals, 'TOKENS_LIMIT' | 'TIME_LIMIT' | string collapses to just string at the type level. If the intent is to provide autocomplete hints while still allowing arbitrary strings, use the (string & {}) idiom instead.

✏️ Suggested fix
 export interface ZaiQuotaLimit {
-  limitType: 'TOKENS_LIMIT' | 'TIME_LIMIT' | string;
+  limitType: 'TOKENS_LIMIT' | 'TIME_LIMIT' | (string & {});
   limit: number;

108-133: authMethod is typed as string but documented with known values — prefer a string literal union.

The JSDoc on Line 111 lists 'cli_login' | 'api_key' | 'api_key_env' | 'none' but the actual type is string. This weakens type safety for consumers (e.g., the ternary chains in mobile-usage-bar.tsx Lines 407-411 comparing against literal strings). Using a union (with a (string & {}) escape hatch if needed) would catch typos at compile time.

✏️ Suggested fix
+export type GeminiAuthMethod = 'cli_login' | 'api_key' | 'api_key_env' | 'none';
+
 export interface GeminiUsage {
   /** Whether the user is authenticated (via CLI or API key) */
   authenticated: boolean;
-  /** Authentication method: 'cli_login' | 'api_key' | 'api_key_env' | 'none' */
-  authMethod: string;
+  /** Authentication method */
+  authMethod: GeminiAuthMethod | (string & {});

62-84: Move API response types to @automaker/types and standardize type definitions.

ZaiPlanType, ZaiQuotaLimit, ZaiUsage, GeminiQuotaBucket, GeminiTierQuota, and GeminiUsage are duplicated across frontend (apps/ui/src/store/types/usage-types.ts) and backend services (apps/server/src/services/). Since these are core type definitions with no app-specific dependencies, they should be defined once in @automaker/types and imported by both frontend and backend.

Additionally, align type safety for GeminiUsage.authMethod: use a literal union type ('cli_login' | 'api_key' | 'none') instead of string to match the backend definition and prevent type mismatches. The JSDoc mentions 'api_key_env', which is not present in the backend's type—clarify whether this is needed or remove it.

apps/ui/src/components/views/board-view/mobile-usage-bar.tsx (2)

375-425: Gemini usage rendering handles multiple states clearly.

The nested ternary covers: authenticated with tier quotas → authenticated without quotas (shows auth method + error/no-usage) → not authenticated → loading. The logic is sound, though the deeply nested ternaries could be extracted to a sub-component for readability in a follow-up.


24-54: Extract formatNumber and formatResetTime to a shared utility module.

These helpers are duplicated identically in usage-popover.tsx and mobile-usage-bar.tsx. Extract them to @/lib/format-utils.ts to eliminate duplication and improve maintainability across desktop (UsagePopover) and mobile (MobileUsageBar) usage-display components.

Note: codex-usage-popover.tsx has a separate, simpler formatResetTime implementation for Codex-specific formatting that should remain separate.

Comment on lines +35 to +57
router.get('/status', async (_req: Request, res: Response) => {
try {
const provider = new GeminiProvider();
const status = await provider.detectInstallation();

const authMethod =
(status as any).authMethod ||
(status.authenticated ? (status.hasApiKey ? 'api_key' : 'cli_login') : 'none');

res.json({
success: true,
installed: status.installed,
version: status.version || null,
path: status.path || null,
authenticated: status.authenticated || false,
authMethod,
hasCredentialsFile: (status as any).hasCredentialsFile || false,
});
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
res.status(500).json({ success: false, error: message });
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find GeminiProvider class and detectInstallation method
find . -type f -name "*.ts" -o -name "*.js" | xargs grep -l "class GeminiProvider" | head -5

Repository: AutoMaker-Org/automaker

Length of output: 113


🏁 Script executed:

#!/bin/bash
# Search for detectInstallation method definition
rg "detectInstallation" --type ts --type tsx -B 5 -A 15

Repository: AutoMaker-Org/automaker

Length of output: 94


🏁 Script executed:

#!/bin/bash
# Search for detectInstallation method with corrected flags
rg "detectInstallation" --type ts -B 5 -A 20

Repository: AutoMaker-Org/automaker

Length of output: 50379


🏁 Script executed:

#!/bin/bash
# Read the GeminiProvider file
wc -l ./apps/server/src/providers/gemini-provider.ts

Repository: AutoMaker-Org/automaker

Length of output: 117


🏁 Script executed:

#!/bin/bash
# Read the detectInstallation method in gemini-provider.ts
sed -n '110,145p' ./apps/server/src/providers/gemini-provider.ts

Repository: AutoMaker-Org/automaker

Length of output: 1064


🏁 Script executed:

#!/bin/bash
# Also check InstallationStatus type definition
rg "interface InstallationStatus|type InstallationStatus" --type ts -A 15

Repository: AutoMaker-Org/automaker

Length of output: 963


🏁 Script executed:

#!/bin/bash
# Read the full detectInstallation method in gemini-provider.ts to see exact return
rg "async detectInstallation" ./apps/server/src/providers/gemini-provider.ts -A 25

Repository: AutoMaker-Org/automaker

Length of output: 731


🏁 Script executed:

#!/bin/bash
# Check if there's any place where status is modified before being used in the route
head -60 ./apps/server/src/routes/gemini/index.ts

Repository: AutoMaker-Org/automaker

Length of output: 2061


Remove unnecessary as any casts; the accessed fields don't exist on InstallationStatus.

Lines 40-42 and 51 use (status as any) to access authMethod and hasCredentialsFile, which are not defined in the InstallationStatus interface. The code already has proper fallback logic that computes authMethod from existing fields; simply remove the unsafe cast and rely on the fallback computation. For hasCredentialsFile, either add it to the InstallationStatus type if needed, or remove it from the response and default to false.

🤖 Prompt for AI Agents
In `@apps/server/src/routes/gemini/index.ts` around lines 35 - 57, Remove the
unsafe (status as any) casts: use the typed InstallationStatus returned by
GeminiProvider.detectInstallation() and compute authMethod using the existing
fields (status.authenticated / status.hasApiKey) without casting; also remove or
type-augment hasCredentialsFile—either add hasCredentialsFile to the
InstallationStatus interface (and populate it in detectInstallation) or stop
returning hasCredentialsFile and default it to false in the JSON response;
update the route in apps/server/src/routes/gemini/index.ts (references:
GeminiProvider, detectInstallation, authMethod, hasCredentialsFile,
InstallationStatus) accordingly.

Comment on lines +63 to +155
// Configure API token (for settings page)
router.post('/configure', async (req: Request, res: Response) => {
try {
const { apiToken, apiHost } = req.body;

if (apiToken !== undefined) {
// Set in-memory token
usageService.setApiToken(apiToken || '');

// Persist to credentials (deep merge happens in updateCredentials)
try {
await settingsService.updateCredentials({
apiKeys: { zai: apiToken || '' },
} as Parameters<typeof settingsService.updateCredentials>[0]);
logger.info('[configure] Saved z.ai API key to credentials');
} catch (persistError) {
logger.error('[configure] Failed to persist z.ai API key:', persistError);
}
}

if (apiHost) {
usageService.setApiHost(apiHost);
}

res.json({
success: true,
message: 'z.ai configuration updated',
isAvailable: usageService.isAvailable(),
});
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
logger.error('Error configuring z.ai:', error);
res.status(500).json({ error: message });
}
});

// Verify API key without storing it (for testing in settings)
router.post('/verify', async (req: Request, res: Response) => {
try {
const { apiKey } = req.body;

if (!apiKey || typeof apiKey !== 'string' || apiKey.trim().length === 0) {
res.json({
success: false,
authenticated: false,
error: 'Please provide an API key to test.',
});
return;
}

// Test the key by making a request to z.ai API
const quotaUrl =
process.env.Z_AI_QUOTA_URL ||
`${process.env.Z_AI_API_HOST ? `https://${process.env.Z_AI_API_HOST}` : 'https://api.z.ai'}/api/monitor/usage/quota/limit`;

logger.info(`[verify] Testing API key against: ${quotaUrl}`);

const response = await fetch(quotaUrl, {
method: 'GET',
headers: {
Authorization: `Bearer ${apiKey.trim()}`,
Accept: 'application/json',
},
});

if (response.ok) {
res.json({
success: true,
authenticated: true,
message: 'Connection successful! z.ai API responded.',
});
} else if (response.status === 401 || response.status === 403) {
res.json({
success: false,
authenticated: false,
error: 'Invalid API key. Please check your key and try again.',
});
} else {
res.json({
success: false,
authenticated: false,
error: `API request failed: ${response.status} ${response.statusText}`,
});
}
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
logger.error('Error verifying z.ai API key:', error);
res.json({
success: false,
authenticated: false,
error: `Network error: ${message}`,
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Move z.ai config/verify logic into a service and emit events.
The route performs provider configuration and verification directly and doesn’t emit events for these operations. Please delegate this work to ZaiUsageService (or a dedicated service) and emit corresponding events via the shared emitter so the UI can react in real time. As per coding guidelines: 'Server business logic should be organized into services in the services/ directory, with Express route handlers in routes/ that delegate to services' and 'All server operations should emit events using createEventEmitter() from lib/events.ts that stream to the frontend via WebSocket'.

🤖 Prompt for AI Agents
In `@apps/server/src/routes/zai/index.ts` around lines 63 - 155, The route
handlers for router.post('/configure') and router.post('/verify') contain
business logic (usageService.setApiToken/setApiHost,
settingsService.updateCredentials, fetch to quota URL and response handling) and
must be moved into ZaiUsageService (or a new service) as methods like
configure({apiToken, apiHost}) and verifyApiKey(apiKey); those service methods
should perform the persistence (call settingsService.updateCredentials), runtime
updates (usageService calls), external fetch, and emit events via the shared
emitter from createEventEmitter() (e.g., emit 'zai.configured' and
'zai.verify.result' with status and error info). Update the route handlers to
simply call ZaiUsageService.configure(...) and
ZaiUsageService.verifyApiKey(...), await results, and return minimal JSON
responses, handling exceptions only to map errors to HTTP responses. Ensure you
reference and replace direct calls to usageService and
settingsService.updateCredentials inside the service and add emitter.emit calls
for UI updates.

Comment on lines +120 to +147
const response = await fetch(quotaUrl, {
method: 'GET',
headers: {
Authorization: `Bearer ${apiKey.trim()}`,
Accept: 'application/json',
},
});

if (response.ok) {
res.json({
success: true,
authenticated: true,
message: 'Connection successful! z.ai API responded.',
});
} else if (response.status === 401 || response.status === 403) {
res.json({
success: false,
authenticated: false,
error: 'Invalid API key. Please check your key and try again.',
});
} else {
res.json({
success: false,
authenticated: false,
error: `API request failed: ${response.status} ${response.statusText}`,
});
}
} catch (error) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find package.json files in the project root and apps/server to check Node engine requirements
fd package.json -t f -E node_modules -E dist -E build | head -5

Repository: AutoMaker-Org/automaker

Length of output: 211


🏁 Script executed:

#!/bin/bash
# Get the actual content of the file in question
cat -n apps/server/src/routes/zai/index.ts | head -170 | tail -60

Repository: AutoMaker-Org/automaker

Length of output: 2408


🏁 Script executed:

#!/bin/bash
# Check for service directory and existing service files in apps/server
find apps/server/src/services -type f -name "*zai*" 2>/dev/null || echo "No zai service found"
ls -la apps/server/src/services/ 2>/dev/null | head -20

Repository: AutoMaker-Org/automaker

Length of output: 1493


🏁 Script executed:

#!/bin/bash
# Check Node engine requirement in apps/server package.json
cat apps/server/package.json | grep -A 5 '"engines"'

Repository: AutoMaker-Org/automaker

Length of output: 179


🏁 Script executed:

#!/bin/bash
# Get fuller context of the zai route file to check for event emission
cat -n apps/server/src/routes/zai/index.ts | head -160

Repository: AutoMaker-Org/automaker

Length of output: 6514


🏁 Script executed:

#!/bin/bash
# Check zai-usage-service to understand service structure
head -60 apps/server/src/services/zai-usage-service.ts

Repository: AutoMaker-Org/automaker

Length of output: 1496


Add a timeout to the external z.ai verification request.

Without a timeout, the fetch request can hang indefinitely during upstream stalls, blocking the server thread. Your Node 22 runtime fully supports AbortSignal.timeout(), so add it directly:

Suggested fix
      const response = await fetch(quotaUrl, {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${apiKey.trim()}`,
          Accept: 'application/json',
        },
+        signal: AbortSignal.timeout(5000),
      });
🤖 Prompt for AI Agents
In `@apps/server/src/routes/zai/index.ts` around lines 120 - 147, The z.ai
verification fetch call can hang indefinitely; update the fetch invocation in
the route handler that calls quotaUrl to pass a signal created via
AbortSignal.timeout(timeoutMs) (e.g., const controllerSignal =
AbortSignal.timeout(5000)) in the fetch options so the request auto-aborts after
a reasonable timeout, and enhance the catch block to handle aborts (detect
AbortError / error.name === 'AbortError' and return a clear timeout JSON
response). Ensure you reference the existing fetch call that sets headers
Authorization/Accept and the surrounding try/catch so you only add the signal
option and the abort-specific error branch.

Comment on lines +168 to +202
// First, get the project ID from loadCodeAssist endpoint
// This is required to get accurate quota data
let projectId: string | undefined;
try {
const codeAssistResponse = await fetch(CODE_ASSIST_URL, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});

if (codeAssistResponse.ok) {
const codeAssistData = (await codeAssistResponse.json()) as {
cloudaicompanionProject?: string;
currentTier?: { id?: string; name?: string };
};
projectId = codeAssistData.cloudaicompanionProject;
logger.debug('[fetchUsageData] Got project ID:', projectId);
}
} catch (e) {
logger.debug('[fetchUsageData] Failed to get project ID:', e);
}

// Fetch quota from Google Cloud API
// Pass project ID to get accurate quota (without it, returns default 100%)
const response = await fetch(QUOTA_API_URL, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(projectId ? { project: projectId } : {}),
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

No timeouts on external HTTP requests.

The fetch calls to CODE_ASSIST_URL, QUOTA_API_URL, and GOOGLE_TOKEN_URL have no timeout configured. If Google's servers are slow or unresponsive, these calls could hang indefinitely, blocking the route handler.

Consider using AbortSignal.timeout():

 const response = await fetch(QUOTA_API_URL, {
   method: 'POST',
   headers: { ... },
   body: JSON.stringify(...),
+  signal: AbortSignal.timeout(15000),
 });
🤖 Prompt for AI Agents
In `@apps/server/src/services/gemini-usage-service.ts` around lines 168 - 202, The
external fetch calls in fetchUsageData (CODE_ASSIST_URL, QUOTA_API_URL,
GOOGLE_TOKEN_URL) lack timeouts and can hang; add an AbortSignal with a timeout
for each request (e.g., use AbortSignal.timeout(timeoutMs) or new
AbortController().signal with setTimeout to abort) and pass the signal option
into fetch, catch the resulting abort/timeout errors and handle/log them
similarly to other fetch failures; ensure each fetch (the code block around
CODE_ASSIST_URL, the QUOTA_API_URL POST, and the GOOGLE_TOKEN_URL call) is
updated to create/use a signal and clean up any controllers if you use
AbortController.

Comment on lines +343 to +384
private async loadCredentials(): Promise<OAuthCredentials | null> {
if (this.cachedCredentials) {
return this.cachedCredentials;
}

// Check multiple possible paths
const possiblePaths = [
this.credentialsPath,
path.join(os.homedir(), '.gemini', 'oauth_creds.json'),
path.join(os.homedir(), '.config', 'gemini', 'oauth_creds.json'),
];

for (const credPath of possiblePaths) {
try {
if (fs.existsSync(credPath)) {
const content = fs.readFileSync(credPath, 'utf8');
const creds = JSON.parse(content);

// Handle different credential formats
if (creds.access_token || creds.refresh_token) {
this.cachedCredentials = creds;
logger.info('[loadCredentials] Loaded from:', credPath);
return creds;
}

// Some formats nest credentials under 'web' or 'installed'
if (creds.web?.client_id || creds.installed?.client_id) {
const clientCreds = creds.web || creds.installed;
this.cachedCredentials = {
client_id: clientCreds.client_id,
client_secret: clientCreds.client_secret,
};
return this.cachedCredentials;
}
}
} catch (error) {
logger.debug('[loadCredentials] Failed to load from', credPath, error);
}
}

return null;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Credentials are cached indefinitely with no invalidation strategy.

loadCredentials() caches the first successful read and never re-reads from disk. If a user runs gemini auth login to re-authenticate, the service will continue using stale/expired credentials until the process restarts. clearCache() exists but nothing calls it automatically.

Consider adding a TTL (e.g., 5 minutes) or checking the file's mtime before returning cached credentials.

🤖 Prompt for AI Agents
In `@apps/server/src/services/gemini-usage-service.ts` around lines 343 - 384, The
cachedCredentials in loadCredentials() is never invalidated so stale/expired
creds persist; modify loadCredentials (and/or clearCache()) to implement
automatic invalidation by adding a TTL (e.g., 5 minutes) or validating the
credentials file mtime before returning cachedCredentials: store a cachedAt
timestamp alongside cachedCredentials when setting it in loadCredentials(), and
when loadCredentials is called check if cachedAt + TTL has expired or if
fs.statSync(credPath).mtimeMs is newer than cachedAt — if expired or file
changed, discard cachedCredentials and re-read from disk (then update cachedAt);
ensure clearCache() still exists to allow explicit invalidation and reference
credentialsPath/possiblePaths when comparing mtimes.

@@ -1,7 +1,11 @@
// @ts-nocheck - API key management state with validation and persistence
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if `@ts-nocheck` was pre-existing or newly added in this PR
git log --oneline -10 -- "apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" 2>/dev/null || echo "File may not have history yet"
echo "---"
echo "Checking if file exists and its first line:"
if [ -f "apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" ]; then
  head -1 "apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts"
  echo "---"
  echo "Full diff for this file (latest change):"
  git diff HEAD -- "apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" 2>/dev/null | head -50 || echo "No diff available"
else
  echo "File not found at expected path"
fi

Repository: AutoMaker-Org/automaker

Length of output: 304


🏁 Script executed:

#!/bin/bash
# Check when `@ts-nocheck` was introduced to this file
echo "Searching for when `@ts-nocheck` was added to the file:"
git log -p -- "apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" 2>/dev/null | grep -B5 "@ts-nocheck" | head -30

echo "---"
echo "Checking the commit that introduced `@ts-nocheck`:"
git log --all --full-history -S "@ts-nocheck" --oneline -- "apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" 2>/dev/null | head -5

echo "---"
echo "Current HEAD and base comparison:"
git log --oneline -20 2>/dev/null | head -10

Repository: AutoMaker-Org/automaker

Length of output: 537


🏁 Script executed:

#!/bin/bash
# Check the state of this file before the most recent commit
echo "Content of file in the commit BEFORE `@ts-nocheck` was added (bea26a6b~1):"
git show bea26a6b~1:"apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" 2>/dev/null | head -5

echo "---"
echo "Content of file at current HEAD (after `@ts-nocheck`):"
git show bea26a6b:"apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" 2>/dev/null | head -5

echo "---"
echo "Diff showing what changed in bea26a6b for this specific file:"
git show bea26a6b -- "apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts" 2>/dev/null | head -50

Repository: AutoMaker-Org/automaker

Length of output: 2473


New file with @ts-nocheck should not be merged without type safety.

This entire file is newly created in this PR yet includes @ts-nocheck from line 1, disabling all TypeScript type checking for sensitive API key management, authentication state, and server-side configuration logic. This is not legacy code being refactored — it's new code intentionally written without type safety. Remove the directive and fix any resulting type errors before merging.

🤖 Prompt for AI Agents
In
`@apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts`
at line 1, Remove the top-level "// `@ts-nocheck`" and add explicit TypeScript
typings for the hook and its internal entities: declare interfaces/types such as
ApiKey (id, name, key, createdAt, revoked?), ApiKeyState (array + validation
errors), AuthState (isAuthenticated, userId, token), and ServerConfig
(allowedOrigins, keyPolicy) used by the useApiKeyManagement hook; update
function signatures (useApiKeyManagement, loadApiKeys, saveApiKeys,
validateApiKey, revokeApiKey) and React state hooks to use these types, type any
localStorage/parsing and async calls with proper unions/Optionals, and fix
resulting type errors rather than silencing them so the file compiles with full
type safety.

Comment on lines +239 to +259
// Configure z.ai service on the server with the new key
if (zaiKey && zaiKey.trim().length > 0) {
try {
const api = getHttpApiClient();
const result = await api.zai.configure(zaiKey.trim());

if (result.success || result.isAvailable) {
// Update z.ai auth status in the store
setZaiAuthStatus({
authenticated: true,
method: 'api_key' as ZaiAuthMethod,
hasApiKey: true,
hasEnvApiKey: false,
});
// Invalidate the z.ai usage query so it refetches with the new key
await queryClient.invalidateQueries({ queryKey: queryKeys.usage.zai() });
logger.info('z.ai API key configured successfully');
}
} catch (error) {
logger.error('Failed to configure z.ai API key:', error);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Partial failure: store is updated before the server call succeeds.

setApiKeys(...) on Line 232 persists the z.ai key to the local store before the server-side api.zai.configure(...) call on Line 243. If the configure call fails (caught on Line 257), the user sees "Saved" feedback, the store has the key, but the server isn't configured. On next app launch the key will be in the store but z.ai won't work until the user re-saves.

Consider either:

  1. Moving setApiKeys after successful server config, or
  2. Rolling back the zai key in the catch block.

Also, the success check result.success || result.isAvailable (Line 245) is loose — isAvailable alone (without success) could represent a state where the service exists but the key wasn't actually accepted.

🤖 Prompt for AI Agents
In
`@apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts`
around lines 239 - 259, The code persists the z.ai key to the local store via
setApiKeys before calling api.zai.configure, and uses a loose check
(result.success || result.isAvailable) so the local state can show "Saved" even
if server config failed; either move the setApiKeys call so it runs only after
api.zai.configure succeeds (and then update setZaiAuthStatus and call
queryClient.invalidateQueries), or implement a rollback in the catch where you
remove the stored zai key using the same setApiKeys call; also tighten the
success condition to require result.success (not just isAvailable) when deciding
success for configuring z.ai.

Comment on lines +246 to +252
// Update z.ai auth status in the store
setZaiAuthStatus({
authenticated: true,
method: 'api_key' as ZaiAuthMethod,
hasApiKey: true,
hasEnvApiKey: false,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Hardcoding hasEnvApiKey: false may overwrite valid environment key state.

When the user saves a UI-provided key, you set hasEnvApiKey: false. If a z.ai key was also configured via environment variable, this would incorrectly clear that flag. Consider reading the current env key status (from apiKeyStatus) before overwriting.

✏️ Suggested fix
           setZaiAuthStatus({
             authenticated: true,
             method: 'api_key' as ZaiAuthMethod,
             hasApiKey: true,
-            hasEnvApiKey: false,
+            hasEnvApiKey: apiKeyStatus?.hasZaiKey ?? false,
           });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Update z.ai auth status in the store
setZaiAuthStatus({
authenticated: true,
method: 'api_key' as ZaiAuthMethod,
hasApiKey: true,
hasEnvApiKey: false,
});
// Update z.ai auth status in the store
setZaiAuthStatus({
authenticated: true,
method: 'api_key' as ZaiAuthMethod,
hasApiKey: true,
hasEnvApiKey: apiKeyStatus?.hasZaiKey ?? false,
});
🤖 Prompt for AI Agents
In
`@apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts`
around lines 246 - 252, The code in use-api-key-management.ts hardcodes
hasEnvApiKey: false when calling setZaiAuthStatus after saving a UI key, which
can incorrectly clear an existing env-configured key; update the call in the
block that calls setZaiAuthStatus to preserve the current env key flag by
reading the existing apiKeyStatus (e.g., use apiKeyStatus.hasEnvApiKey) and set
hasEnvApiKey to that value instead of false so you only update the fields that
truly change (authenticated, method, hasApiKey) while keeping hasEnvApiKey in
sync.

Comment on lines +107 to +124
// 3. z.ai Auth Status
try {
const result = await api.zai.getStatus();
if (result.success || result.available !== undefined) {
let method: ZaiAuthMethod = 'none';
if (result.hasEnvApiKey) {
method = 'api_key_env';
} else if (result.hasApiKey || result.available) {
method = 'api_key';
}

setZaiAuthStatus({
authenticated: result.available,
method,
hasApiKey: result.hasApiKey ?? result.available,
hasEnvApiKey: result.hasEnvApiKey ?? false,
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Coalesce z.ai auth fields to booleans to avoid undefined state.

If result.available (or hasApiKey) is missing, authenticated/hasApiKey can become undefined. Defaulting to false keeps the status shape consistent; consider a fallback status in the non-success path as well.

💡 Suggested adjustment
-        setZaiAuthStatus({
-          authenticated: result.available,
-          method,
-          hasApiKey: result.hasApiKey ?? result.available,
-          hasEnvApiKey: result.hasEnvApiKey ?? false,
-        });
+        const authenticated = result.available ?? false;
+        setZaiAuthStatus({
+          authenticated,
+          method,
+          hasApiKey: result.hasApiKey ?? authenticated,
+          hasEnvApiKey: result.hasEnvApiKey ?? false,
+        });
🤖 Prompt for AI Agents
In `@apps/ui/src/hooks/use-provider-auth-init.ts` around lines 107 - 124, The z.ai
auth response handler (api.zai.getStatus) can leave authenticated/hasApiKey
undefined; update the logic in the try block that calls setZaiAuthStatus so it
coerces result.available, result.hasApiKey, and result.hasEnvApiKey to booleans
(e.g., using !! or ?? false) and derive method using those boolean values, and
also add a fallback setZaiAuthStatus in the non-success/exception path to set
authenticated: false, method: 'none', hasApiKey: false, hasEnvApiKey: false;
reference setZaiAuthStatus, api.zai.getStatus, and ZaiAuthMethod when making the
changes.

Comment on lines +133 to +138
// Set CLI status
setGeminiCliStatus({
installed: result.installed ?? false,
version: result.version,
path: result.status,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use the Gemini CLI path field instead of status.

setGeminiCliStatus assigns path: result.status, but the CLI path is exposed as result.path. This will surface a status string where a filesystem path is expected.

🐛 Suggested fix
-          path: result.status,
+          path: result.path ?? null,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Set CLI status
setGeminiCliStatus({
installed: result.installed ?? false,
version: result.version,
path: result.status,
});
// Set CLI status
setGeminiCliStatus({
installed: result.installed ?? false,
version: result.version,
path: result.path ?? null,
});
🤖 Prompt for AI Agents
In `@apps/ui/src/hooks/use-provider-auth-init.ts` around lines 133 - 138, The code
is assigning the wrong field to the CLI path: update the call to
setGeminiCliStatus so the path uses result.path (the actual filesystem path)
instead of result.status; locate the block where setGeminiCliStatus is called
(in use-provider-auth-init.ts) and replace the path: result.status assignment
with path: result.path while keeping installed: result.installed ?? false and
version: result.version unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant