Skip to content

chore: Fix all 246 TypeScript errors in UI#702

Merged
Shironex merged 3 commits intov0.14.0rcfrom
chore/fix-ui-typescript-errors
Jan 25, 2026
Merged

chore: Fix all 246 TypeScript errors in UI#702
Shironex merged 3 commits intov0.14.0rcfrom
chore/fix-ui-typescript-errors

Conversation

@Shironex
Copy link
Collaborator

@Shironex Shironex commented Jan 25, 2026

Summary

  • Fixed all 246 TypeScript errors reported by npm run typecheck in the UI workspace
  • Extended SetupAPI interface with 20+ missing methods for CLI integrations
  • Fixed WorktreeInfo type to include required fields (isCurrent, hasWorktree)
  • Added null checks for optional API properties across all hooks

Test plan

  • npm run typecheck passes with 0 errors
  • npm run build:packages && npm run build succeeds
  • npm run test:packages - 519 tests pass
  • npm run test:server - 1415 tests pass

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes / Improvements

    • Added runtime guards and clearer error handling to avoid failures when platform APIs are unavailable.
    • Improved null/undefined handling and safer defaults across settings, CLI and provider status flows.
    • Terminal: testRunner sessions are no longer persisted or restored, avoiding unintended sessions.
  • Refactor

    • Wide type-safety improvements and cleanup to reduce runtime type errors in UI and hooks.
  • Chores

    • Added a workspace-level "typecheck" npm script.

✏️ Tip: You can customize this high-level summary in your review settings.

Shironex and others added 2 commits January 25, 2026 18:11
…ents

- Added a new `typecheck` script in `package.json` for better type checking in the UI workspace.
- Refactored several components to remove unnecessary type assertions and improve type safety, particularly in `new-project-modal.tsx`, `edit-project-dialog.tsx`, and `task-progress-panel.tsx`.
- Updated event handling in `git-diff-panel.tsx` to use async functions for better error handling.
- Improved type definitions in various files, including `setup-view` and `electron.ts`, to ensure consistent usage of types across the codebase.
- Cleaned up global type definitions for better clarity and maintainability.

These changes aim to streamline the development process and reduce potential runtime errors.
- Extended SetupAPI interface with 20+ missing methods for Cursor, Codex,
  OpenCode, Gemini, and Copilot CLI integrations
- Fixed WorktreeInfo type to include isCurrent and hasWorktree fields
- Added null checks for optional API properties across all hooks
- Fixed Feature type conflicts between @automaker/types and local definitions
- Added missing CLI status hooks for all providers
- Fixed type mismatches in mutation callbacks and event handlers
- Removed dead code referencing non-existent GlobalSettings properties
- Updated mock implementations in electron.ts for all new API methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds extensive TypeScript typings and runtime guards across the UI: replaces permissive any casts with concrete types, tightens Electron API/window access, validates presence of Electron APIs before use, and updates several public types and hook signatures.

Changes

Cohort / File(s) Summary
Electron & HTTP client surface
apps/ui/src/lib/electron.ts, apps/ui/src/lib/http-api-client.ts, apps/ui/src/types/electron.d.ts, apps/ui/src/types/global.d.ts, apps/ui/src/lib/workspace-config.ts
Expanded Electron API typings (ExtendedElectronAPI, getPath, getServerUrl, etc.), introduced CreatePROptions and typed event callbacks, replaced (window as any).electronAPI casts with window.electronAPI, and updated workspace/getPath usage.
Query & API guards
apps/ui/src/hooks/queries/* (e.g., use-git.ts, use-worktrees.ts, use-settings.ts, use-cli-status.ts, use-github.ts, use-models.ts, use-usage.ts, use-sessions.ts, ...)
Added runtime guards that throw if Electron API namespaces are missing (git, worktree, setup, runningAgents, agent, settings, etc.), tightened return types and renamed/mapped some fields (e.g., GitHub remote fields, validation types).
Hooks & mutations typing
apps/ui/src/hooks/* (e.g., use-cli-installation.ts, use-cli-status.ts, use-board-features.ts, use-board-effects.ts, use-auto-mode-mutations.ts, use-worktree-mutations.ts, use-github-mutations.ts)
Introduced explicit API result/progress types, widened cliType to ModelProvider, made loadFeatures async, added guards for autoMode/worktree APIs, and adjusted several hook/mutation signatures and internal typings.
Board / Kanban & drag-drop
apps/ui/src/components/views/board-view.tsx, .../board-view/* (hooks, kanban-board.tsx, kanban-card/*, agent-info-panel.tsx, card-badges.tsx)
Strengthened many types (WorktreeInfo, FeatureStatusWithPipeline, CollisionDetection/Collision), refined memo return types, adjusted branchName nullability, removed inline ESLint directive, and simplified some backlog conditionals.
Agent output & backlog events
apps/ui/src/components/views/board-view/dialogs/agent-output-modal.tsx, apps/ui/src/components/layout/project-switcher/components/edit-project-dialog.tsx
Tightened event typing (unknown → specific event types), switched to window.__currentProject access (no cast), updated useAgentOutput usage to options { enabled }, and removed permissive (project as any) casts.
UI components & panels
apps/ui/src/components/ui/git-diff-panel.tsx, apps/ui/src/components/ui/task-progress-panel.tsx, apps/ui/src/components/dialogs/new-project-modal.tsx, apps/ui/src/components/views/analysis-view.tsx
Replaced some onClick handlers with () => void fn() wrappers, moved to strongly typed Feature/ParsedTask usage, and created typed newFeature const for API calls.
Terminal view adjustments
apps/ui/src/components/views/terminal-view.tsx
Added comprehensive handling to ignore testRunner content for layout, persistence, rendering and navigation; adjusted nullable ref reset behavior.
Settings & providers
apps/ui/src/components/views/settings-view/**, apps/ui/src/components/views/setup-view/**
Added type imports (EditorInfo, CursorModelId, InstallProgressEvent, CliStatusApiResponse), guarded presence of setup/auth methods before calling (show toast on absent methods), normalized version/path to null, derived installCommand from installCommands arrays, and removed Codex sync fields from settings sync.
Store & public types
apps/ui/src/store/app-store.ts
Exported ReasoningEffort, expanded Feature public interface with optional fields (dependencies, model, branchName, thinkingLevel, reasoningEffort, summary), and added worktree isCurrent/hasWorktree booleans.
File picker & misc utilities
apps/ui/src/lib/file-picker.ts, apps/ui/src/lib/*, apps/ui/src/components/views/* (various small files)
Replaced prototype-based showPicker detection with runtime instance check, improved window typing in tests and setup helpers, and other small type-safety tweaks (e.g., casting via unknown).
Tests & build
apps/ui/tests/*, apps/ui/tests/utils/project/setup.ts, package.json
Tightened test typings for project fixtures and added typecheck npm script for the UI workspace.

Sequence Diagram(s)

(Skipped — changes are broad typing and guards without introducing a single new multi-component control flow to visualize.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Suggested labels

Ready-To-Merge

Poem

🐰 I hopped through types with nimble paws,

Replaced each any with stricter laws.
Windows checked and APIs confirmed,
Guards in place where calls once squirmed.
Hooray — well-typed fields in tidy rows!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 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: fixing 246 TypeScript errors in the UI workspace. It is specific, concise, and directly reflects the primary objective of the pull request.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@Shironex Shironex self-assigned this Jan 25, 2026
@Shironex Shironex added Refactor A complete logic rewrite is requested or being performed for an issue. cleanup remove unused files in the codebase labels Jan 25, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Shironex, 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 primarily focuses on a large-scale refactor to enhance the UI's type safety and strictness. It cleans up numerous existing TypeScript errors, solidifies API interfaces, and ensures data structures are more accurately represented, leading to a more reliable and maintainable codebase.

Highlights

  • TypeScript Error Resolution: Addressed and fixed all 246 TypeScript errors reported by npm run typecheck within the UI workspace, significantly improving type safety and code quality.
  • API Interface Enhancements: Extended the SetupAPI interface with over 20 missing methods, crucial for robust CLI integrations and better type definitions for Electron API interactions.
  • WorktreeInfo Type Correction: Rectified the WorktreeInfo type to accurately include required fields such as isCurrent and hasWorktree, ensuring data consistency.
  • Null Safety Improvements: Implemented comprehensive null checks for optional API properties across various hooks and components, preventing potential runtime errors and enhancing application stability.

🧠 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.

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 is a substantial and valuable pull request that significantly improves the TypeScript type safety across the UI codebase. The effort to eliminate any types and introduce stricter typing is commendable and will certainly enhance maintainability and reduce potential runtime errors. The changes are well-executed and demonstrate a good understanding of the codebase's types. I've identified a couple of minor areas for improvement and one potential bug, but overall, this is excellent work.

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: 4

Caution

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

⚠️ Outside diff range comments (3)
apps/ui/src/components/views/board-view/dialogs/pull-resolve-conflicts-dialog.tsx (1)

41-46: Await async onConfirm to avoid unhandled failures.
With onConfirm now possibly async, the dialog closes before the operation finishes and any rejection is unhandled. Consider awaiting and surfacing errors.

✅ Suggested fix
-  const handleConfirm = () => {
+  const handleConfirm = async () => {
     if (!worktree || !selectedBranch) return;
-    onConfirm(worktree, selectedBranch);
-    onOpenChange(false);
+    try {
+      await onConfirm(worktree, selectedBranch);
+      onOpenChange(false);
+    } catch (err) {
+      logger.error('Failed to start pull/resolve', err);
+      toast.error('Failed to start pull/resolve');
+    }
   };
apps/ui/src/hooks/use-settings-sync.ts (1)

548-548: The double type assertion masks an incomplete API response type definition.

The as unknown as GlobalSettings cast at line 548 (and also in use-settings-migration.ts:493 and use-settings.ts:35) suppresses TypeScript checks because the actual API response type in http-api-client.ts (lines 2402–2430) is narrower than GlobalSettings. The API type omits fields like sidebarStyle, collapsedNavSections, cursorDefaultModel, enabledOpencodeModels, and many others that the code attempts to use after the assertion.

The code does perform some validation—model ID migration and sanitization using functions like migrateCursorModelIds() and validation against available model sets—but this occurs after the assertion, so it doesn't prevent the type mismatch.

To improve type safety, either:

  1. Expand the API response type in http-api-client.ts to match all fields actually returned by the server, or
  2. Add schema-based runtime validation (e.g., Zod) to validate the entire response shape at the API boundary.

Also note: Line 682 contains a separate double assertion (theme as unknown as ThemeMode) which should be addressed separately.

apps/ui/src/store/app-store.ts (1)

680-688: Worktree fields isCurrent and hasWorktree are missing from backend payload in the sync flow.

The backend WorktreeInfo type (from React Query hook) does not include isCurrent or hasWorktree fields, but setWorktrees in the store requires them. When use-worktrees.ts syncs backend worktrees directly to the store at line 34, these required fields will be undefined at runtime.

Manual creations in graph-view-page.tsx and board-view.tsx explicitly provide both fields, but the backend sync path does not. Either:

  1. Backend should populate these fields in the API response, or
  2. The sync in use-worktrees.ts should enrich the data before calling setWorktrees, or
  3. These fields should be optional in the store schema if they're computed locally
🤖 Fix all issues with AI agents
In `@apps/ui/src/components/views/settings-view/cli-status/claude-cli-status.tsx`:
- Around line 92-98: The code calls api.setup.authClaude without ensuring
authClaude exists; add a guard mirroring the deauthClaude check by verifying
api.setup && typeof api.setup.authClaude === 'function' before awaiting
api.setup.authClaude(), and if missing show the same toast.error (e.g.,
'Authentication Failed' with description 'Setup API is not available') and
return; update the block that currently checks only api.setup to perform this
combined check to prevent runtime exceptions when authClaude is undefined.

In `@apps/ui/src/components/views/settings-view/cli-status/cursor-cli-status.tsx`:
- Around line 211-222: The code assumes getElectronAPI() always returns an
object and directly dereferences api.setup; change the guard to first
optional-chain on the API itself (use (getElectronAPI()?.setup ...) or check api
!== undefined) before accessing .setup so you don't throw when running outside
Electron; update the auth check around getElectronAPI, api.setup and the
authCursor extraction in cursor-cli-status.tsx (also apply same
optional-chaining/undefined check to the similar block referenced at lines
246-257) and keep the existing toast.error fallback when authCursor is missing.

In `@apps/ui/src/hooks/mutations/use-auto-mode-mutations.ts`:
- Around line 348-351: The mutation in useStartAutoMode (inside mutationFn)
passes String(maxConcurrency) as the second argument to api.autoMode.start,
which treats it as branchName and leaves maxConcurrency undefined; update the
call to pass branchName (or undefined/null) as the second parameter and the
numeric maxConcurrency as the third — e.g., call api.autoMode.start(projectPath,
undefined, maxConcurrency ?? undefined) or Number(maxConcurrency) — so that
api.autoMode.start receives (projectPath, branchName?, maxConcurrency?) in the
correct order.

In `@apps/ui/src/hooks/queries/use-cli-status.ts`:
- Around line 58-75: The hook useApiKeysStatus currently returns the raw result
from api.setup.getApiKeys without validating its success flag; mirror the other
hooks (e.g., useClaudeCliStatus/useGitHubCliStatus) by checking result.success
after calling getElectronAPI() and api.setup.getApiKeys, and if result.success
is false throw a new Error('Failed to fetch API keys') before returning the
result so callers only receive successful responses.
♻️ Duplicate comments (7)
apps/ui/src/hooks/queries/use-settings.ts (4)

52-60: Same API guard issue as above.
Apply the same api?.settings check here.


76-79: Same API guard issue as above.
Apply the same api?.settings check here.


96-99: Same API guard issue as above.
Apply the same api?.settings check here.


125-128: Same API guard issue as above.
Apply the same api?.settings check here.

apps/ui/src/components/views/setup-view/steps/providers-setup-step.tsx (3)

1007-1019: Same OpenCode command fallback concern as above.

This repeats the same potential regression discussed in OpencodeSetupStep; if the Electron API still exposes installCommand/loginCommand, consider preserving those values with a fallback.


1861-1876: Duplicate Codex auth-method guard.

Same refactor suggestion as the CodexContent block: centralize the guard to avoid drift.


1890-1902: Duplicate OpenCode command fallback concern.

Same issue as the OpenCode blocks above; ensure API-provided commands aren’t dropped unless the contract guarantees they’re gone.

🧹 Nitpick comments (19)
apps/ui/src/hooks/use-settings-migration.ts (1)

671-676: Consider extracting the cast to reduce duplication.

The double-cast pattern is valid for accessing properties not declared in the type, but it's duplicated. Extracting to a variable improves readability and reduces repetition.

♻️ Suggested refactor
+  const settingsRecord = settings as unknown as Record<string, unknown>;
+  if (settingsRecord.autoModeByWorktree) {
+    const persistedSettings = settingsRecord.autoModeByWorktree as Record<
-  if ((settings as unknown as Record<string, unknown>).autoModeByWorktree) {
-    const persistedSettings = (settings as unknown as Record<string, unknown>)
-      .autoModeByWorktree as Record<
       string,
       { maxConcurrency?: number; branchName?: string | null }
     >;

Ideally, if autoModeByWorktree is a legitimate property that should be persisted, consider adding it to the GlobalSettings type in @automaker/types to eliminate the need for type assertions entirely.

apps/ui/src/components/views/settings-view/providers/cursor-permissions-section.tsx (1)

174-176: Type assertion may mask future runtime issues.

The profile.id as 'strict' | 'development' assertion bypasses type safety. If availableProfiles ever contains profiles with different IDs, this would silently pass invalid values to onApplyProfile.

Consider either:

  1. Narrowing the profile.id type in PermissionsData to 'strict' | 'development'
  2. Adding a runtime guard before calling the handler
♻️ Optional: Add runtime validation
  onClick={() =>
-   onApplyProfile(profile.id as 'strict' | 'development', 'global')
+   {
+     if (profile.id === 'strict' || profile.id === 'development') {
+       onApplyProfile(profile.id, 'global');
+     }
+   }
  }
apps/ui/src/hooks/use-query-invalidation.ts (1)

326-329: Consider a type guard for better runtime safety.

The as StreamEvent cast works but provides no runtime validation. The defensive 'sessionId' in event check on line 329 helps, but a type guard would catch malformed events earlier.

Optional: Add a type guard for StreamEvent validation
function isStreamEvent(data: unknown): data is StreamEvent {
  return (
    typeof data === 'object' &&
    data !== null &&
    'type' in data &&
    'sessionId' in data &&
    typeof (data as StreamEvent).sessionId === 'string'
  );
}

Then use it:

 const unsubscribe = api.agent.onStream((data: unknown) => {
-  const event = data as StreamEvent;
-  // Only handle events for the current session
-  if ('sessionId' in event && event.sessionId !== sessionId) return;
+  if (!isStreamEvent(data)) return;
+  // Only handle events for the current session
+  if (data.sessionId !== sessionId) return;
apps/ui/src/components/views/board-view/shared/model-selector.tsx (2)

42-43: Avoid @ts-expect-error by narrowing codexCliStatus (or fixing its store type).
If codexCliStatus truly has auth, prefer a type guard (or update the store type) and remove the suppression.

♻️ Suggested local guard to drop the suppression
-  // `@ts-expect-error` - codexCliStatus uses CliStatus type but should use CodexCliStatus which has auth
-  const isCodexAvailable = codexCliStatus?.installed && codexCliStatus?.auth?.authenticated;
+  const hasCodexAuth = (
+    status: typeof codexCliStatus
+  ): status is typeof codexCliStatus & { auth: { authenticated?: boolean } } =>
+    !!status && typeof status === 'object' && 'auth' in status;
+
+  const isCodexAvailable =
+    hasCodexAuth(codexCliStatus) &&
+    !!codexCliStatus.installed &&
+    !!codexCliStatus.auth?.authenticated;

76-79: Normalize enabled Cursor model IDs once to avoid unsafe casts.
Canonicalize to cursor-* and compare without as CursorModelId.

♻️ Suggested normalization
-  const filteredCursorModels = CURSOR_MODELS.filter((model) => {
-    // enabledCursorModels stores CursorModelIds which may or may not have "cursor-" prefix
-    // (e.g., 'auto', 'sonnet-4.5' without prefix, but 'cursor-gpt-5.2' with prefix)
-    // CURSOR_MODELS always has the "cursor-" prefix added in model-constants.ts
-    // Check both the full ID (for GPT models) and the unprefixed version (for non-GPT models)
-    const unprefixedId = model.id.startsWith('cursor-') ? model.id.slice(7) : model.id;
-    return (
-      enabledCursorModels.includes(model.id as CursorModelId) ||
-      enabledCursorModels.includes(unprefixedId as CursorModelId)
-    );
-  });
+  const canonicalEnabledCursorModels = new Set(
+    enabledCursorModels.map((id) => (id.startsWith('cursor-') ? id : `cursor-${id}`))
+  );
+
+  const filteredCursorModels = CURSOR_MODELS.filter((model) =>
+    canonicalEnabledCursorModels.has(model.id)
+  );
apps/ui/src/hooks/use-settings-sync.ts (1)

357-362: The 50ms delay is a fragile heuristic.

The delay to wait for React render completion is well-documented but may be insufficient on slower devices or during heavy rendering. Consider using requestIdleCallback or queueMicrotask with a fallback for more reliable scheduling.

♻️ Alternative using requestIdleCallback
-        // Wait for React to finish rendering after store hydration.
-        // Zustand's subscribe() fires during setState(), which happens BEFORE React's
-        // render completes. Use a small delay to ensure all pending state updates
-        // have propagated through the React tree before we read state.
-        await new Promise((resolve) => setTimeout(resolve, 50));
+        // Wait for React to finish rendering after store hydration.
+        // Zustand's subscribe() fires during setState(), which happens BEFORE React's
+        // render completes. Use requestIdleCallback to wait until the browser is idle.
+        await new Promise<void>((resolve) => {
+          if ('requestIdleCallback' in window) {
+            window.requestIdleCallback(() => resolve(), { timeout: 100 });
+          } else {
+            setTimeout(resolve, 50);
+          }
+        });
apps/ui/src/components/views/setup-view/steps/providers-setup-step.tsx (1)

708-725: Prefer a shared CodexAuthMethod guard to avoid drift.

You already export CodexAuthMethod from apps/ui/src/store/setup-store.ts. Duplicating the valid methods list here (and again in checkAllProviders) risks future mismatch. Consider extracting a single helper (or reusing the store type) for both sites.

♻️ Example refactor (within this block)
-          const validMethods = ['api_key_env', 'api_key', 'cli_authenticated', 'none'] as const;
-          type CodexAuthMethod = (typeof validMethods)[number];
-          const method: CodexAuthMethod = validMethods.includes(
-            result.auth.method as CodexAuthMethod
-          )
-            ? (result.auth.method as CodexAuthMethod)
-            : 'cli_authenticated';
+          const method = coerceCodexAuthMethod(result.auth.method);

You could define the helper once (near the top of this file) and reuse it:

import type { CodexAuthMethod } from '@/store/setup-store';

const CODEX_AUTH_METHODS: readonly CodexAuthMethod[] = [
  'api_key_env',
  'api_key',
  'cli_authenticated',
  'none',
];

const coerceCodexAuthMethod = (value?: string): CodexAuthMethod =>
  CODEX_AUTH_METHODS.includes(value as CodexAuthMethod)
    ? (value as CodexAuthMethod)
    : 'cli_authenticated';
apps/ui/src/components/views/settings-view/providers/opencode-settings-tab.tsx (1)

57-58: Type cast works but masks a potential type mismatch.

The cast as typeof cliStatusData.auth & { error?: string } suggests the source type (cliStatusData.auth) is missing the error field. Since OpencodeAuthStatus already includes error?: string (per opencode-cli-status.tsx), consider updating the upstream type definition (likely the query hook's return type) to include error instead of casting here.

This cast is acceptable as a workaround for this PR's scope, but tracking this for a future cleanup would improve type coherence.

apps/ui/src/components/ui/git-diff-panel.tsx (1)

482-490: Redundant async/await wrapper.

The async () => await loadDiffs() pattern is functionally equivalent to () => loadDiffs() since the promise result isn't being used. The extra async wrapper adds no error handling benefit here.

However, this is a minor stylistic point and doesn't affect functionality.

Simplified handlers
-                onClick={async () => await loadDiffs()}
+                onClick={() => loadDiffs()}

Also applies to: 558-566

apps/ui/src/components/views/board-view/hooks/use-board-persistence.ts (1)

52-53: Redundant cast and potential type mismatch.

Line 52 casts result.feature to Feature, and line 53 immediately recasts it to Partial<Feature>. The intermediate cast to Feature is unnecessary since you're using it as Partial<Feature> anyway. More importantly, ApiFeature may lack required UI-specific fields (e.g., steps is required string[] in UI Feature but optional in ApiFeature), so casting directly to Feature could mask type errors.

Suggested simplification
        if (result.success && result.feature) {
-          const updatedFeature = result.feature as Feature;
-          updateFeature(updatedFeature.id, updatedFeature as Partial<Feature>);
+          const updatedFeature = result.feature;
+          updateFeature(updatedFeature.id, updatedFeature as Partial<Feature>);
apps/ui/src/components/views/settings-view/providers/codex-settings-tab.tsx (1)

57-72: Consider extracting duplicated type definition and logic.

The getCodexStatus type definition and invocation pattern is duplicated between the useEffect (lines 57-72) and handleRefreshCodexCli (lines 116-130). This violates DRY and makes maintenance harder.

Suggested extraction
+type GetCodexStatusFn = () => Promise<{
+  success: boolean;
+  installed: boolean;
+  version?: string;
+  path?: string;
+  recommendation?: string;
+  installCommands?: { npm?: string; macos?: string; windows?: string };
+  auth?: {
+    authenticated: boolean;
+    method: string;
+    hasApiKey?: boolean;
+  };
+}>;
+
+function getCodexStatusFn(api: ReturnType<typeof getElectronAPI>): GetCodexStatusFn | undefined {
+  return (api?.setup as Record<string, unknown> | undefined)?.getCodexStatus as GetCodexStatusFn | undefined;
+}

Then use getCodexStatusFn(api) in both places.

Also applies to: 116-130

apps/ui/src/components/views/board-view/hooks/use-board-features.ts (2)

188-192: Inconsistent loadFeatures behavior between internal and external usage.

The returned loadFeatures (lines 188-192) uses queryClient.invalidateQueries, while the internal event handlers (lines 112, 116) call loadFeatures() which references the refetch function from useFeatures (line 31). This inconsistency could cause confusion:

  • Internal: calls refetch() directly, returning fresh data
  • External callers: get invalidateQueries(), which marks data stale

Consider either using consistent behavior throughout, or renaming to clarify the distinction.

Option 1: Use consistent invalidation
+  const invalidateFeatures = useCallback(async () => {
+    await queryClient.invalidateQueries({
+      queryKey: queryKeys.features.all(currentProject?.path ?? ''),
+    });
+  }, [queryClient, currentProject?.path]);
+
   // In event handlers, use:
-        loadFeatures();
+        invalidateFeatures();

35-53: Unnecessary dependency in loadCategories.

loadFeatures is included in the dependency array (line 53) but is not used within the loadCategories function body. This could cause unnecessary re-creation of the callback.

Remove unused dependency
-  }, [currentProject, loadFeatures]);
+  }, [currentProject]);
apps/ui/src/components/views/graph-view-page.tsx (1)

152-177: Consider adding runtime validation for the event payload.

Casting unknown directly to the expected shape without runtime validation can lead to silent failures if the event structure changes. Consider using a type guard or at minimum checking for required properties before accessing them.

🔧 Suggested improvement
     const unsubscribe = api.backlogPlan.onEvent((data: unknown) => {
-      const event = data as { type: string; result?: BacklogPlanResult; error?: string };
+      if (typeof data !== 'object' || data === null || !('type' in data)) {
+        logger.warn('Received malformed backlog plan event', { data });
+        return;
+      }
+      const event = data as { type: string; result?: BacklogPlanResult; error?: string };
       logger.debug('Backlog plan event received', {
apps/ui/src/components/ui/task-progress-panel.tsx (1)

57-60: Consider improving the API result typing upstream.

The cast (result as { success: boolean; feature?: Feature }) suggests the api.features.get return type may need improvement in the Electron API types. The guard at line 58 makes the subsequent access safe.

apps/ui/src/components/views/board-view/dialogs/agent-output-modal.tsx (1)

264-266: Consider adding type guard or validation before casting.

The pattern of accepting unknown and immediately casting to BacklogPlanEvent is safe for type checking but provides no runtime protection if the API returns unexpected data. The null check on line 266 (if (!event?.type)) helps, but a type guard would be more robust.

This is acceptable given the trusted internal API, but worth noting for future maintainability.

💡 Optional: Add a type guard for safer casting
function isBacklogPlanEvent(data: unknown): data is BacklogPlanEvent {
  return (
    typeof data === 'object' &&
    data !== null &&
    'type' in data &&
    typeof (data as { type: unknown }).type === 'string'
  );
}

// Then use:
const unsubscribe = api.backlogPlan.onEvent((data: unknown) => {
  if (!isBacklogPlanEvent(data)) return;
  // data is now typed as BacklogPlanEvent
  // ...
});
apps/ui/src/types/electron.d.ts (1)

1445-1460: Redundant properties in ExtendedElectronAPI.

Several properties in ExtendedElectronAPI already exist in the base ElectronAPI:

  • isElectron (line 566)
  • getApiKey (line 569)

These re-declarations are redundant since ExtendedElectronAPI extends ElectronAPI.

Additionally, getPath has a stricter type signature here ('documents' | 'home' | 'appData' | 'userData') compared to the base (string). This is valid TypeScript (narrowing), but consider whether this restriction is intentional or should be applied to the base interface.

♻️ Remove redundant properties
 export interface ExtendedElectronAPI extends ElectronAPI {
-  /** Runtime marker indicating Electron environment */
-  isElectron?: boolean;
   /** Get the server URL (Electron-only) */
   getServerUrl?: () => Promise<string>;
-  /** Get the API key (Electron-only) */
-  getApiKey?: () => Promise<string | null>;
   /** Check if running in external server mode (Electron-only) */
   isExternalServerMode?: () => Promise<boolean>;
   /** Get system paths (Electron-only) */
   getPath?: (name: 'documents' | 'home' | 'appData' | 'userData') => Promise<string>;
 }
apps/ui/src/types/global.d.ts (2)

58-64: Duplicate Window.electronAPI augmentation with electron.d.ts.

This file augments Window.electronAPI with extended properties, but electron.d.ts (lines 1462-1467) also declares a global Window augmentation using ExtendedElectronAPI. Having two separate augmentations for the same property can cause confusion and potential type conflicts.

Consider consolidating the Window augmentation in one location. Since electron.d.ts already defines ExtendedElectronAPI with the same extended methods, this file could simply import and reference that type instead of inline re-declaring the extensions.

♻️ Consolidate Window.electronAPI typing
-import type { ElectronAPI } from '../lib/electron';
+import type { ExtendedElectronAPI } from './electron';

 declare global {
   interface Window {
     // ... mock properties ...

     /**
      * Electron API exposed via preload script
      */
-    electronAPI?: ElectronAPI & {
-      isElectron?: boolean;
-      getServerUrl?: () => Promise<string>;
-      getApiKey?: () => Promise<string | null>;
-      isExternalServerMode?: () => Promise<boolean>;
-      getPath?: (name: 'documents' | 'home' | 'appData' | 'userData') => Promise<string>;
-    };
+    electronAPI?: ExtendedElectronAPI;
   }
 }

14-28: Inconsistent export of interface types.

MockProject is exported (line 23) while MockContextFile is not. If MockContextFile is also needed outside this file (e.g., in test utilities), consider exporting it for consistency.

♻️ Export MockContextFile for consistency
 /**
  * Mock context file data for testing
  */
-interface MockContextFile {
+export interface MockContextFile {
   featureId: string;
   path: string;
   content: string;
 }

- Fix window.Electron to window.isElectron in http-api-client.ts
- Use void operator instead of async/await for onClick handlers in git-diff-panel.tsx
- Fix critical bug: correct parameter order in useStartAutoMode (maxConcurrency was passed as branchName)
- Add error handling for getApiKeys() result in use-cli-status.ts
- Add authClaude guard in claude-cli-status.tsx for consistency with deauthClaude
- Add optional chaining on api object in cursor-cli-status.tsx

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@Shironex
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Labels

cleanup remove unused files in the codebase Refactor A complete logic rewrite is requested or being performed for an issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant