chore: Fix all lint errors and remove unused code

- Fix 75 ESLint errors by updating eslint.config.mjs:
  - Add missing browser globals (MouseEvent, AbortController, Response, etc.)
  - Add Vite define global (__APP_VERSION__)
  - Configure @ts-nocheck to require descriptions
  - Add no-unused-vars rule for .mjs scripts

- Fix runtime bug in agent-output-modal.tsx (setOutput -> setStreamedContent)

- Remove ~120 unused variable warnings across 97 files:
  - Remove unused imports (React hooks, lucide icons, types)
  - Remove unused constants and variables
  - Remove unused function definitions
  - Prefix intentionally unused parameters with underscore

- Add descriptions to all @ts-nocheck comments (25 files)

- Clean up misc issues:
  - Remove invalid deprecation plugin comments
  - Fix eslint-disable comment placement
  - Add missing RefreshCw import in code-view.tsx

Reduces lint warnings from ~300 to 67 (all remaining are no-explicit-any)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Shirone
2026-01-25 17:33:45 +01:00
parent 3b56d553c9
commit 006152554b
97 changed files with 129 additions and 339 deletions

View File

@@ -14,8 +14,13 @@ const eslintConfig = defineConfig([
require: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
},
},
rules: {
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' }],
},
},
{
files: ['**/*.ts', '**/*.tsx'],
@@ -45,6 +50,8 @@ const eslintConfig = defineConfig([
confirm: 'readonly',
getComputedStyle: 'readonly',
requestAnimationFrame: 'readonly',
cancelAnimationFrame: 'readonly',
alert: 'readonly',
// DOM Element Types
HTMLElement: 'readonly',
HTMLInputElement: 'readonly',
@@ -56,6 +63,8 @@ const eslintConfig = defineConfig([
HTMLParagraphElement: 'readonly',
HTMLImageElement: 'readonly',
Element: 'readonly',
SVGElement: 'readonly',
SVGSVGElement: 'readonly',
// Event Types
Event: 'readonly',
KeyboardEvent: 'readonly',
@@ -64,14 +73,24 @@ const eslintConfig = defineConfig([
CustomEvent: 'readonly',
ClipboardEvent: 'readonly',
WheelEvent: 'readonly',
MouseEvent: 'readonly',
UIEvent: 'readonly',
MediaQueryListEvent: 'readonly',
DataTransfer: 'readonly',
// Web APIs
ResizeObserver: 'readonly',
AbortSignal: 'readonly',
AbortController: 'readonly',
IntersectionObserver: 'readonly',
Audio: 'readonly',
HTMLAudioElement: 'readonly',
ScrollBehavior: 'readonly',
URL: 'readonly',
URLSearchParams: 'readonly',
XMLHttpRequest: 'readonly',
Response: 'readonly',
RequestInit: 'readonly',
RequestCache: 'readonly',
// Timers
setTimeout: 'readonly',
setInterval: 'readonly',
@@ -90,6 +109,8 @@ const eslintConfig = defineConfig([
Electron: 'readonly',
// Console
console: 'readonly',
// Vite defines
__APP_VERSION__: 'readonly',
},
},
plugins: {
@@ -99,6 +120,13 @@ const eslintConfig = defineConfig([
...ts.configs.recommended.rules,
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-nocheck': 'allow-with-description',
minimumDescriptionLength: 10,
},
],
},
},
globalIgnores([

View File

@@ -29,7 +29,7 @@ async function killProcessOnPort(port) {
try {
await execAsync(`kill -9 ${pid}`);
console.log(`[KillTestServers] Killed process ${pid}`);
} catch (error) {
} catch (_error) {
// Process might have already exited
}
}
@@ -47,7 +47,7 @@ async function killProcessOnPort(port) {
await new Promise((resolve) => setTimeout(resolve, 500));
return;
}
} catch (error) {
} catch (_error) {
// No process on port, which is fine
}
}

View File

@@ -68,7 +68,6 @@ export function CodexUsagePopover() {
// Use React Query for data fetching with automatic polling
const {
data: codexUsage,
isLoading,
isFetching,
error: queryError,
dataUpdatedAt,

View File

@@ -40,8 +40,6 @@ interface FileBrowserDialogProps {
initialPath?: string;
}
const MAX_RECENT_FOLDERS = 5;
export function FileBrowserDialog({
open,
onOpenChange,

View File

@@ -3,7 +3,7 @@
*/
import { useCallback } from 'react';
import { Bell, Check, Trash2, ExternalLink } from 'lucide-react';
import { Bell, Check, Trash2 } from 'lucide-react';
import { useNavigate } from '@tanstack/react-router';
import { useNotificationsStore } from '@/store/notifications-store';
import { useLoadNotifications, useNotificationEvents } from '@/hooks/use-notification-events';

View File

@@ -199,7 +199,6 @@ export function ProjectContextMenu({
} = useAppStore();
const [showRemoveDialog, setShowRemoveDialog] = useState(false);
const [showThemeSubmenu, setShowThemeSubmenu] = useState(false);
const [removeConfirmed, setRemoveConfirmed] = useState(false);
const themeSubmenuRef = useRef<HTMLDivElement>(null);
const closeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -331,7 +330,6 @@ export function ProjectContextMenu({
toast.success('Project removed', {
description: `${project.name} has been removed from your projects list`,
});
setRemoveConfirmed(true);
}, [moveProjectToTrash, project.id, project.name]);
const handleDialogClose = useCallback(
@@ -340,8 +338,6 @@ export function ProjectContextMenu({
// Close the context menu when dialog closes (whether confirmed or cancelled)
// This prevents the context menu from reappearing after dialog interaction
if (!isOpen) {
// Reset confirmation state
setRemoveConfirmed(false);
// Always close the context menu when dialog closes
onClose();
}

View File

@@ -1,8 +1,4 @@
import * as React from 'react';
import { Settings2 } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { useAppStore } from '@/store/app-store';
import type { ModelAlias, CursorModelId, PhaseModelKey, PhaseModelEntry } from '@automaker/types';
import { PhaseModelSelector } from '@/components/views/settings-view/model-defaults/phase-model-selector';
@@ -74,12 +70,6 @@ export function ModelOverrideTrigger({
lg: 'h-10 w-10',
};
const iconSizes = {
sm: 'w-3.5 h-3.5',
md: 'w-4 h-4',
lg: 'w-5 h-5',
};
// For icon variant, wrap PhaseModelSelector and hide text/chevron with CSS
if (variant === 'icon') {
return (

View File

@@ -37,16 +37,6 @@ function normalizeEntry(entry: PhaseModelEntry | string): PhaseModelEntry {
return entry;
}
/**
* Extract model string from PhaseModelEntry or string
*/
function extractModel(entry: PhaseModelEntry | string): ModelId {
if (typeof entry === 'string') {
return entry as ModelId;
}
return entry.model;
}
/**
* Hook for managing model overrides per phase
*

View File

@@ -1,4 +1,3 @@
import * as React from 'react';
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
const Collapsible = CollapsiblePrimitive.Root;

View File

@@ -1,4 +1,4 @@
import { useState, useMemo, useEffect, useRef } from 'react';
import { useState, useMemo, useRef } from 'react';
import {
ChevronDown,
ChevronRight,
@@ -21,7 +21,6 @@ import {
X,
Filter,
Circle,
Play,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { cn } from '@/lib/utils';

View File

@@ -36,7 +36,7 @@ export function TaskProgressPanel({
const [tasks, setTasks] = useState<TaskInfo[]>([]);
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
const [isLoading, setIsLoading] = useState(true);
const [currentTaskId, setCurrentTaskId] = useState<string | null>(null);
const [, setCurrentTaskId] = useState<string | null>(null);
// Load initial tasks from feature's planSpec
const loadInitialTasks = useCallback(async () => {
@@ -236,7 +236,7 @@ export function TaskProgressPanel({
<div className="absolute left-[2.35rem] top-4 bottom-8 w-px bg-linear-to-b from-border/80 via-border/40 to-transparent" />
<div className="space-y-5">
{tasks.map((task, index) => {
{tasks.map((task, _index) => {
const isActive = task.status === 'in_progress';
const isCompleted = task.status === 'completed';
const isPending = task.status === 'pending';

View File

@@ -25,8 +25,6 @@ type UsageError = {
message: string;
};
// Fixed refresh interval (45 seconds)
const REFRESH_INTERVAL_SECONDS = 45;
const CLAUDE_SESSION_WINDOW_HOURS = 5;
// Helper to format reset time for Codex
@@ -229,15 +227,6 @@ export function UsagePopover() {
// Calculate max percentage for header button
const claudeSessionPercentage = claudeUsage?.sessionPercentage || 0;
const codexMaxPercentage = codexUsage?.rateLimits
? Math.max(
codexUsage.rateLimits.primary?.usedPercent || 0,
codexUsage.rateLimits.secondary?.usedPercent || 0
)
: 0;
const isStale = activeTab === 'claude' ? isClaudeStale : isCodexStale;
const getProgressBarColor = (percentage: number) => {
if (percentage >= 80) return 'bg-red-500';
if (percentage >= 50) return 'bg-yellow-500';

View File

@@ -5,17 +5,7 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/com
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
FileText,
FolderOpen,
Terminal,
CheckCircle,
XCircle,
Play,
File,
Pencil,
Wrench,
} from 'lucide-react';
import { Terminal, CheckCircle, XCircle, Play, File, Pencil, Wrench } from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { cn } from '@/lib/utils';
import { getElectronAPI } from '@/lib/electron';
@@ -29,13 +19,6 @@ interface ToolResult {
timestamp: Date;
}
interface ToolExecution {
tool: string;
input: string;
result: ToolResult | null;
isRunning: boolean;
}
export function AgentToolsView() {
const { currentProject } = useAppStore();
const api = getElectronAPI();

View File

@@ -63,7 +63,6 @@ export function AgentView() {
sendMessage,
clearHistory,
stopExecution,
error: agentError,
serverQueue,
addToServerQueue,
removeFromServerQueue,

View File

@@ -1,5 +1,5 @@
// @ts-nocheck
import { useEffect, useState, useCallback, useMemo, useRef } from 'react';
// @ts-nocheck - dnd-kit type incompatibilities with collision detection and complex state management
import { useEffect, useState, useCallback, useMemo } from 'react';
import { createLogger } from '@automaker/utils/logger';
import {
DndContext,
@@ -29,16 +29,13 @@ class DialogAwarePointerSensor extends PointerSensor {
import { useAppStore, Feature } from '@/store/app-store';
import { getElectronAPI } from '@/lib/electron';
import { getHttpApiClient } from '@/lib/http-api-client';
import type { AutoModeEvent } from '@/types/electron';
import type { ModelAlias, CursorModelId, BacklogPlanResult } from '@automaker/types';
import type { BacklogPlanResult } from '@automaker/types';
import { pathsEqual } from '@/lib/utils';
import { toast } from 'sonner';
import { getBlockingDependencies } from '@automaker/dependency-resolver';
import { BoardBackgroundModal } from '@/components/dialogs/board-background-modal';
import { Spinner } from '@/components/ui/spinner';
import { useShallow } from 'zustand/react/shallow';
import { useAutoMode } from '@/hooks/use-auto-mode';
import { useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts';
import { useWindowState } from '@/hooks/use-window-state';
// Board-view specific imports
import { BoardHeader } from './board-view/board-header';
@@ -97,8 +94,6 @@ const logger = createLogger('Board');
export function BoardView() {
const {
currentProject,
maxConcurrency: legacyMaxConcurrency,
setMaxConcurrency: legacySetMaxConcurrency,
defaultSkipTests,
specCreatingForProject,
setSpecCreatingForProject,
@@ -109,9 +104,6 @@ export function BoardView() {
setCurrentWorktree,
getWorktrees,
setWorktrees,
useWorktrees,
enableDependencyBlocking,
skipVerificationInAutoMode,
planUseSelectedWorktreeBranch,
addFeatureUseSelectedWorktreeBranch,
isPrimaryWorktreeBranch,
@@ -120,8 +112,6 @@ export function BoardView() {
} = useAppStore(
useShallow((state) => ({
currentProject: state.currentProject,
maxConcurrency: state.maxConcurrency,
setMaxConcurrency: state.setMaxConcurrency,
defaultSkipTests: state.defaultSkipTests,
specCreatingForProject: state.specCreatingForProject,
setSpecCreatingForProject: state.setSpecCreatingForProject,
@@ -132,9 +122,6 @@ export function BoardView() {
setCurrentWorktree: state.setCurrentWorktree,
getWorktrees: state.getWorktrees,
setWorktrees: state.setWorktrees,
useWorktrees: state.useWorktrees,
enableDependencyBlocking: state.enableDependencyBlocking,
skipVerificationInAutoMode: state.skipVerificationInAutoMode,
planUseSelectedWorktreeBranch: state.planUseSelectedWorktreeBranch,
addFeatureUseSelectedWorktreeBranch: state.addFeatureUseSelectedWorktreeBranch,
isPrimaryWorktreeBranch: state.isPrimaryWorktreeBranch,
@@ -151,12 +138,9 @@ export function BoardView() {
// Subscribe to worktreePanelVisibleByProject to trigger re-renders when it changes
const worktreePanelVisibleByProject = useAppStore((state) => state.worktreePanelVisibleByProject);
// Subscribe to showInitScriptIndicatorByProject to trigger re-renders when it changes
const showInitScriptIndicatorByProject = useAppStore(
(state) => state.showInitScriptIndicatorByProject
);
useAppStore((state) => state.showInitScriptIndicatorByProject);
const getShowInitScriptIndicator = useAppStore((state) => state.getShowInitScriptIndicator);
const getDefaultDeleteBranch = useAppStore((state) => state.getDefaultDeleteBranch);
const shortcuts = useKeyboardShortcutsConfig();
const {
features: hookFeatures,
isLoading,
@@ -535,8 +519,6 @@ export function BoardView() {
handleMoveBackToInProgress,
handleOpenFollowUp,
handleSendFollowUp,
handleCommitFeature,
handleMergeFeature,
handleCompleteFeature,
handleUnarchiveFeature,
handleViewOutput,

View File

@@ -2,12 +2,7 @@ import { memo, useEffect, useState, useMemo, useRef } from 'react';
import { Feature, ThinkingLevel, ParsedTask } from '@/store/app-store';
import type { ReasoningEffort } from '@automaker/types';
import { getProviderFromModel } from '@/lib/utils';
import {
AgentTaskInfo,
parseAgentContext,
formatModelName,
DEFAULT_MODEL,
} from '@/lib/agent-context-parser';
import { parseAgentContext, formatModelName, DEFAULT_MODEL } from '@/lib/agent-context-parser';
import { cn } from '@/lib/utils';
import type { AutoModeEvent } from '@/types/electron';
import { Brain, ListTodo, Sparkles, Expand, CheckCircle2, Circle, Wrench } from 'lucide-react';

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - optional callback prop typing with feature status narrowing
import { memo } from 'react';
import { Feature } from '@/store/app-store';
import { Button } from '@/components/ui/button';
@@ -36,7 +36,7 @@ interface CardActionsProps {
export const CardActions = memo(function CardActions({
feature,
isCurrentAutoTask,
hasContext,
hasContext: _hasContext,
shortcutKey,
isSelectionMode = false,
onEdit,

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - badge component prop variations with conditional rendering
import { memo, useEffect, useMemo, useState } from 'react';
import { Feature, useAppStore } from '@/store/app-store';
import { cn } from '@/lib/utils';

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - content section prop typing with feature data extraction
import { memo } from 'react';
import { Feature } from '@/store/app-store';
import { GitBranch, GitPullRequest, ExternalLink } from 'lucide-react';

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - header component props with optional handlers and status variants
import { memo, useState } from 'react';
import { Feature } from '@/store/app-store';
import { cn } from '@/lib/utils';

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - dnd-kit draggable/droppable ref combination type incompatibilities
import React, { memo, useLayoutEffect, useState, useCallback } from 'react';
import { useDraggable, useDroppable } from '@dnd-kit/core';
import { cn } from '@/lib/utils';

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - dialog state typing with feature summary extraction
import { Feature } from '@/store/app-store';
import { AgentTaskInfo } from '@/lib/agent-context-parser';
import {

View File

@@ -1,6 +1,4 @@
// TODO: Remove @ts-nocheck after fixing BaseFeature's index signature issue
// The `[key: string]: unknown` in BaseFeature causes property access type errors
// @ts-nocheck
// @ts-nocheck - BaseFeature index signature causes property access type errors
import { memo, useCallback, useState, useEffect } from 'react';
import { cn } from '@/lib/utils';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';

View File

@@ -8,7 +8,7 @@ import type { PipelineConfig, FeatureStatusWithPipeline } from '@automaker/types
import { ListHeader } from './list-header';
import { ListRow, sortFeatures } from './list-row';
import { createRowActionHandlers, type RowActionHandlers } from './row-actions';
import { getStatusLabel, getStatusOrder } from './status-badge';
import { getStatusOrder } from './status-badge';
import { getColumnsWithPipeline } from '../../constants';
import type { SortConfig, SortColumn } from '../../hooks/use-list-view-state';

View File

@@ -1,6 +1,5 @@
// @ts-nocheck
// @ts-nocheck - feature data building with conditional fields and model type inference
import { useState, useEffect, useRef } from 'react';
import { createLogger } from '@automaker/utils/logger';
import {
Dialog,
DialogContent,
@@ -27,18 +26,10 @@ import { useNavigate } from '@tanstack/react-router';
import { toast } from 'sonner';
import { cn } from '@/lib/utils';
import { modelSupportsThinking } from '@/lib/utils';
import {
useAppStore,
ModelAlias,
ThinkingLevel,
FeatureImage,
PlanningMode,
Feature,
} from '@/store/app-store';
import { useAppStore, ThinkingLevel, FeatureImage, PlanningMode, Feature } from '@/store/app-store';
import type { ReasoningEffort, PhaseModelEntry, AgentModel } from '@automaker/types';
import { supportsReasoningEffort } from '@automaker/types';
import {
TestingTabContent,
PrioritySelector,
WorkModeSelector,
PlanningModeSelect,
@@ -57,8 +48,6 @@ import {
type AncestorContext,
} from '@automaker/dependency-resolver';
const logger = createLogger('AddFeatureDialog');
/**
* Determines the default work mode based on global settings and current worktree selection.
*

View File

@@ -282,7 +282,7 @@ export function AgentOutputModal({
}
if (newContent) {
setOutput((prev) => `${prev}${newContent}`);
setStreamedContent((prev) => prev + newContent);
}
});

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - completed features filtering and grouping with status transitions
import {
Dialog,
DialogContent,

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - dependency tree visualization with recursive feature relationships
import { useState, useEffect } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Feature } from '@/store/app-store';

View File

@@ -1,6 +1,5 @@
// @ts-nocheck
// @ts-nocheck - form state management with partial feature updates and validation
import { useState, useEffect } from 'react';
import { createLogger } from '@automaker/utils/logger';
import {
Dialog,
DialogContent,
@@ -26,11 +25,10 @@ import { GitBranch, Cpu, FolderKanban, Settings2 } from 'lucide-react';
import { useNavigate } from '@tanstack/react-router';
import { toast } from 'sonner';
import { cn, modelSupportsThinking } from '@/lib/utils';
import { Feature, ModelAlias, ThinkingLevel, useAppStore, PlanningMode } from '@/store/app-store';
import { Feature, ModelAlias, ThinkingLevel, PlanningMode } from '@/store/app-store';
import type { ReasoningEffort, PhaseModelEntry, DescriptionHistoryEntry } from '@automaker/types';
import { migrateModelId } from '@automaker/types';
import {
TestingTabContent,
PrioritySelector,
WorkModeSelector,
PlanningModeSelect,
@@ -45,8 +43,6 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
import { DependencyTreeDialog } from './dependency-tree-dialog';
import { supportsReasoningEffort } from '@automaker/types';
const logger = createLogger('EditFeatureDialog');
interface EditFeatureDialogProps {
feature: Feature | null;
onClose: () => void;

View File

@@ -1,5 +1,3 @@
import { useState } from 'react';
import { createLogger } from '@automaker/utils/logger';
import {
Dialog,
DialogContent,
@@ -18,14 +16,7 @@ import {
} from '@/components/ui/description-image-dropzone';
import { MessageSquare } from 'lucide-react';
import { Feature } from '@/store/app-store';
import {
EnhanceWithAI,
EnhancementHistoryButton,
type EnhancementMode,
type BaseHistoryEntry,
} from '../shared';
const logger = createLogger('FollowUpDialog');
import { EnhanceWithAI, EnhancementHistoryButton, type BaseHistoryEntry } from '../shared';
/**
* A single entry in the follow-up prompt history

View File

@@ -11,7 +11,6 @@ import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { AlertCircle } from 'lucide-react';
import { modelSupportsThinking } from '@/lib/utils';
import { Feature, ModelAlias, ThinkingLevel, PlanningMode } from '@/store/app-store';
import {
TestingTabContent,
@@ -22,7 +21,7 @@ import {
} from '../shared';
import type { WorkMode } from '../shared';
import { PhaseModelSelector } from '@/components/views/settings-view/model-defaults/phase-model-selector';
import { isCursorModel, type PhaseModelEntry } from '@automaker/types';
import type { PhaseModelEntry } from '@automaker/types';
import { cn } from '@/lib/utils';
interface MassEditDialogProps {
@@ -240,8 +239,6 @@ export function MassEditDialog({
};
const hasAnyApply = Object.values(applyState).some(Boolean);
const isCurrentModelCursor = isCursorModel(model);
const modelAllowsThinking = !isCurrentModelCursor && modelSupportsThinking(model);
return (
<Dialog open={open} onOpenChange={(open) => !open && onClose()}>

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - feature update logic with partial updates and image/file handling
import { useCallback } from 'react';
import {
Feature,

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - column filtering logic with dependency resolution and status mapping
import { useMemo, useCallback } from 'react';
import { Feature, useAppStore } from '@/store/app-store';
import {
@@ -51,7 +51,6 @@ export function useBoardColumnFeatures({
// Determine the effective worktree path and branch for filtering
// If currentWorktreePath is null, we're on the main worktree
const effectiveWorktreePath = currentWorktreePath || projectPath;
// Use the branch name from the selected worktree
// If we're selecting main (currentWorktreePath is null), currentWorktreeBranch
// should contain the main branch's actual name, defaulting to "main"

View File

@@ -23,7 +23,7 @@ interface UseBoardDragDropProps {
export function useBoardDragDrop({
features,
currentProject,
currentProject: _currentProject,
runningAutoTasks,
persistFeatureUpdate,
handleStartImplementation,

View File

@@ -1,4 +1,3 @@
import type { ModelAlias } from '@/store/app-store';
import type { ModelProvider, ThinkingLevel, ReasoningEffort } from '@automaker/types';
import {
CURSOR_MODEL_MAP,

View File

@@ -1,13 +1,12 @@
// @ts-nocheck
// @ts-nocheck - model selector with provider-specific model options and validation
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { Brain, AlertTriangle } from 'lucide-react';
import { AnthropicIcon, CursorIcon, OpenAIIcon } from '@/components/ui/provider-icon';
import { cn } from '@/lib/utils';
import type { ModelAlias } from '@/store/app-store';
import { useAppStore } from '@/store/app-store';
import { useSetupStore } from '@/store/setup-store';
import { getModelProvider, PROVIDER_PREFIXES, stripProviderPrefix } from '@automaker/types';
import { getModelProvider } from '@automaker/types';
import type { ModelProvider } from '@automaker/types';
import { CLAUDE_MODELS, CURSOR_MODELS, ModelOption } from './model-constants';
import { useEffect } from 'react';

View File

@@ -12,7 +12,6 @@ import {
GitBranch,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { cn } from '@/lib/utils';
import { XtermLogViewer, type XtermLogViewerRef } from '@/components/ui/xterm-log-viewer';
import { useDevServerLogs } from '../hooks/use-dev-server-logs';
import type { WorktreeInfo } from '../types';

View File

@@ -161,7 +161,7 @@ export function WorktreeActionsDropdown({
: null;
// Get available terminals for the "Open In Terminal" submenu
const { terminals, hasExternalTerminals } = useAvailableTerminals();
const { terminals } = useAvailableTerminals();
// Use shared hook for effective default terminal (null = integrated terminal)
const effectiveDefaultTerminal = useEffectiveDefaultTerminal(terminals);

View File

@@ -514,7 +514,7 @@ export function WorktreePanel({
} else {
toast.error(result.error || 'Failed to push changes');
}
} catch (error) {
} catch {
toast.error('Failed to push changes');
}
},

View File

@@ -4,7 +4,7 @@ import { useAppStore } from '@/store/app-store';
import { getElectronAPI } from '@/lib/electron';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { File, Folder, FolderOpen, ChevronRight, ChevronDown, Code } from 'lucide-react';
import { File, Folder, FolderOpen, ChevronRight, ChevronDown, Code, RefreshCw } from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { cn } from '@/lib/utils';

View File

@@ -103,12 +103,6 @@ export function ContextView() {
// File input ref for import
const fileInputRef = useRef<HTMLInputElement>(null);
// Get images directory path
const getImagesPath = useCallback(() => {
if (!currentProject) return null;
return `${currentProject.path}/.automaker/images`;
}, [currentProject]);
// Keyboard shortcuts for this view
const contextShortcuts: KeyboardShortcut[] = useMemo(
() => [

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - GitHub issues view with issue selection and feature creation flow
import { useState, useCallback, useMemo } from 'react';
import { createLogger } from '@automaker/utils/logger';
import { CircleDot, RefreshCw, SearchX } from 'lucide-react';
@@ -43,9 +43,6 @@ export function GitHubIssuesView() {
// Model override for validation
const validationModelOverride = useModelOverride({ phase: 'validationModel' });
// Extract model string for API calls (backward compatibility)
const validationModelString = validationModelOverride.effectiveModel;
const { openIssues, closedIssues, loading, refreshing, error, refresh } = useGithubIssues();
const { validatingIssues, cachedValidations, handleValidateIssue, handleViewCachedValidation } =

View File

@@ -1,7 +1,6 @@
import { CircleDot, RefreshCw } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { cn } from '@/lib/utils';
import type { IssuesStateFilter } from '../types';
import { IssuesFilterControls } from './issues-filter-controls';

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - GitHub issue validation with Electron API integration and async state
import { useState, useEffect, useCallback, useRef } from 'react';
import { createLogger } from '@automaker/utils/logger';
import {
@@ -17,17 +17,6 @@ import { useValidateIssue, useMarkValidationViewed } from '@/hooks/mutations';
const logger = createLogger('IssueValidation');
/**
* Extract model string from PhaseModelEntry or string (handles both formats)
*/
function extractModel(entry: PhaseModelEntry | string | undefined): ModelId | undefined {
if (!entry) return undefined;
if (typeof entry === 'string') {
return entry as ModelId;
}
return entry.model;
}
interface UseIssueValidationOptions {
selectedIssue: GitHubIssue | null;
showValidationDialog: boolean;

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - graph view page with feature filtering and visualization state
import { useState, useCallback, useMemo, useEffect } from 'react';
import { useAppStore, Feature } from '@/store/app-store';
import { useShallow } from 'zustand/react/shallow';
@@ -9,12 +9,7 @@ import {
AgentOutputModal,
BacklogPlanDialog,
} from './board-view/dialogs';
import {
useBoardFeatures,
useBoardActions,
useBoardBackground,
useBoardPersistence,
} from './board-view/hooks';
import { useBoardFeatures, useBoardActions, useBoardPersistence } from './board-view/hooks';
import { useWorktrees } from './board-view/worktree-panel/hooks';
import { useAutoMode } from '@/hooks/use-auto-mode';
import { pathsEqual } from '@/lib/utils';
@@ -242,7 +237,7 @@ export function GraphViewPage() {
const [followUpFeature, setFollowUpFeature] = useState<Feature | null>(null);
const [followUpPrompt, setFollowUpPrompt] = useState('');
const [followUpImagePaths, setFollowUpImagePaths] = useState<any[]>([]);
const [followUpPreviewMap, setFollowUpPreviewMap] = useState<Map<string, string>>(new Map());
const [, setFollowUpPreviewMap] = useState<Map<string, string>>(new Map());
// In-progress features for shortcuts
const inProgressFeaturesForShortcuts = useMemo(() => {

View File

@@ -1,16 +1,7 @@
import { useReactFlow, Panel } from '@xyflow/react';
import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import {
ZoomIn,
ZoomOut,
Maximize2,
Lock,
Unlock,
GitBranch,
ArrowRight,
ArrowDown,
} from 'lucide-react';
import { ZoomIn, ZoomOut, Maximize2, Lock, Unlock, ArrowRight, ArrowDown } from 'lucide-react';
import { cn } from '@/lib/utils';
interface GraphControlsProps {

View File

@@ -175,9 +175,7 @@ function GraphCanvasInner({
mql.addEventListener('change', update);
return () => mql.removeEventListener('change', update);
}
// eslint-disable-next-line deprecation/deprecation
mql.addListener(update);
// eslint-disable-next-line deprecation/deprecation
return () => mql.removeListener(update);
}, [effectiveTheme]);

View File

@@ -1,6 +1,5 @@
import { useCallback, useMemo, useRef } from 'react';
import dagre from 'dagre';
import { Node, Edge } from '@xyflow/react';
import { TaskNode, DependencyEdge } from './use-graph-nodes';
const NODE_WIDTH = 280;

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - interview flow state machine with dynamic question handling
import { useState, useCallback, useRef, useEffect } from 'react';
import { createLogger } from '@automaker/utils/logger';
import { useAppStore, Feature } from '@/store/app-store';

View File

@@ -2,13 +2,13 @@
* Notifications View - Full page view for all notifications
*/
import { useEffect, useCallback } from 'react';
import { useCallback } from 'react';
import { useAppStore } from '@/store/app-store';
import { useNotificationsStore } from '@/store/notifications-store';
import { useLoadNotifications, useNotificationEvents } from '@/hooks/use-notification-events';
import { getHttpApiClient } from '@/lib/http-api-client';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Card, CardContent, CardDescription, CardTitle } from '@/components/ui/card';
import { Bell, Check, CheckCheck, Trash2, ExternalLink } from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { useNavigate } from '@tanstack/react-router';
@@ -42,8 +42,6 @@ export function NotificationsView() {
unreadCount,
isLoading,
error,
setNotifications,
setUnreadCount,
markAsRead,
dismissNotification,
markAllAsRead,

View File

@@ -9,10 +9,8 @@ import { useNavigate } from '@tanstack/react-router';
import { useAppStore } from '@/store/app-store';
import { initializeProject } from '@/lib/project-init';
import { toast } from 'sonner';
import { cn } from '@/lib/utils';
import type { ProjectStatus } from '@automaker/types';
import { Bot, Activity, GitBranch, ArrowRight } from 'lucide-react';
import { Button } from '@/components/ui/button';
interface RunningAgentsPanelProps {
projects: ProjectStatus[];

View File

@@ -1,5 +1,4 @@
import { useState, useEffect, useCallback, type KeyboardEvent } from 'react';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Terminal, Save, RotateCcw, Info, X, Play, FlaskConical } from 'lucide-react';

View File

@@ -97,7 +97,7 @@ export function ProjectIdentitySection({ project }: ProjectIdentitySectionProps)
description: result.error || 'Please try again.',
});
}
} catch (error) {
} catch {
toast.error('Failed to upload icon', {
description: 'Network error. Please try again.',
});

View File

@@ -86,8 +86,6 @@ const MEMORY_TASKS: PhaseConfig[] = [
},
];
const ALL_PHASES = [...QUICK_TASKS, ...VALIDATION_TASKS, ...GENERATION_TASKS, ...MEMORY_TASKS];
/**
* Default feature model override section for per-project settings.
*/

View File

@@ -12,7 +12,6 @@ import { Spinner } from '@/components/ui/spinner';
import { getElectronAPI, type RunningAgent } from '@/lib/electron';
import { useAppStore } from '@/store/app-store';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import { useNavigate } from '@tanstack/react-router';
import { AgentOutputModal } from './board-view/dialogs/agent-output-modal';
import { useRunningAgents } from '@/hooks/queries';

View File

@@ -58,8 +58,6 @@ export function SettingsView() {
setDefaultRequirePlanApproval,
defaultFeatureModel,
setDefaultFeatureModel,
autoLoadClaudeMd,
setAutoLoadClaudeMd,
promptCustomization,
setPromptCustomization,
skipSandboxWarning,

View File

@@ -14,8 +14,7 @@ import { toast } from 'sonner';
export function ApiKeysSection() {
const { apiKeys, setApiKeys } = useAppStore();
const { claudeAuthStatus, setClaudeAuthStatus, codexAuthStatus, setCodexAuthStatus } =
useSetupStore();
const { claudeAuthStatus, setClaudeAuthStatus, setCodexAuthStatus } = useSetupStore();
const [isDeletingAnthropicKey, setIsDeletingAnthropicKey] = useState(false);
const [isDeletingOpenaiKey, setIsDeletingOpenaiKey] = useState(false);
@@ -45,7 +44,7 @@ export function ApiKeysSection() {
} else {
toast.error(result.error || 'Failed to delete API key');
}
} catch (error) {
} catch {
toast.error('Failed to delete API key');
} finally {
setIsDeletingAnthropicKey(false);
@@ -73,7 +72,7 @@ export function ApiKeysSection() {
} else {
toast.error(result.error || 'Failed to delete API key');
}
} catch (error) {
} catch {
toast.error('Failed to delete API key');
} finally {
setIsDeletingOpenaiKey(false);

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - API key management state with validation and persistence
import { useState, useEffect } from 'react';
import { createLogger } from '@automaker/utils/logger';
import { useAppStore } from '@/store/app-store';

View File

@@ -12,7 +12,6 @@ import { cn } from '@/lib/utils';
import { useAppStore } from '@/store/app-store';
import { FontSelector } from '@/components/shared';
import type { Theme } from '../shared/types';
import type { SidebarStyle } from '@automaker/types';
interface AppearanceSectionProps {
effectiveTheme: Theme;

View File

@@ -1,7 +1,7 @@
import { Button } from '@/components/ui/button';
import { SkeletonPulse } from '@/components/ui/skeleton';
import { Spinner } from '@/components/ui/spinner';
import { CheckCircle2, AlertCircle, RefreshCw, Key } from 'lucide-react';
import { CheckCircle2, AlertCircle, RefreshCw } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { CliStatus } from '../shared/types';
import { GeminiIcon } from '@/components/ui/provider-icon';

View File

@@ -3,7 +3,7 @@ import { ChevronDown, ChevronRight, X } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import type { Project } from '@/lib/electron';
import type { NavigationItem, NavigationGroup } from '../config/navigation';
import type { NavigationItem } from '../config/navigation';
import { GLOBAL_NAV_GROUPS } from '../config/navigation';
import type { SettingsViewId } from '../hooks/use-settings-view';
import { useAppStore } from '@/store/app-store';
@@ -189,7 +189,7 @@ function NavItemWithSubItems({
export function SettingsNavigation({
activeSection,
currentProject,
currentProject: _currentProject,
onNavigate,
isOpen = true,
onClose,

View File

@@ -1,4 +1,4 @@
import { useState, useCallback, useEffect } from 'react';
import { useState, useCallback } from 'react';
import { useCursorPermissionsQuery, type CursorPermissionsData } from '@/hooks/queries';
import { useApplyCursorProfile, useCopyCursorConfig } from '@/hooks/mutations';

View File

@@ -1,7 +1,6 @@
import { Plug, RefreshCw, Download, Code, FileJson, Plus } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { cn } from '@/lib/utils';
interface MCPServerHeaderProps {
isRefreshing: boolean;

View File

@@ -27,7 +27,7 @@ export function SecurityWarningDialog({
onOpenChange,
onConfirm,
serverType,
serverName,
_serverName,
command,
args,
url,

View File

@@ -16,7 +16,6 @@ import type {
ClaudeModelAlias,
} from '@automaker/types';
import {
stripProviderPrefix,
STANDALONE_CURSOR_MODELS,
getModelGroup,
isGroupSelected,
@@ -567,7 +566,7 @@ export function PhaseModelSelector({
const isCopilotDisabled = disabledProviders.includes('copilot');
// Group models (filtering out disabled providers)
const { favorites, claude, cursor, codex, gemini, copilot, opencode } = useMemo(() => {
const { favorites, claude, codex, gemini, copilot, opencode } = useMemo(() => {
const favs: typeof CLAUDE_MODELS = [];
const cModels: typeof CLAUDE_MODELS = [];
const curModels: typeof CURSOR_MODELS = [];
@@ -651,7 +650,6 @@ export function PhaseModelSelector({
return {
favorites: favs,
claude: cModels,
cursor: curModels,
codex: codModels,
gemini: gemModels,
copilot: copModels,
@@ -2117,7 +2115,7 @@ export function PhaseModelSelector({
{opencodeSections.length > 0 && (
<CommandGroup heading={OPENCODE_CLI_GROUP_LABEL}>
{opencodeSections.map((section, sectionIndex) => (
{opencodeSections.map((section, _sectionIndex) => (
<Fragment key={section.key}>
<div className="px-2 pt-2 text-xs font-medium text-muted-foreground">
{section.label}

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - Claude settings form with CLI status and authentication state
import { useAppStore } from '@/store/app-store';
import { useSetupStore } from '@/store/setup-store';
import { useCliStatus } from '../hooks/use-cli-status';

View File

@@ -24,7 +24,6 @@ export function SubagentsSection() {
const {
subagentsWithScope,
isLoading: isLoadingAgents,
hasProject,
refreshFilesystemAgents,
} = useSubagents();
const {

View File

@@ -16,18 +16,13 @@ const logger = createLogger('CodexSettings');
export function CodexSettingsTab() {
const {
codexAutoLoadAgents,
codexSandboxMode,
codexApprovalPolicy,
codexEnableWebSearch,
codexEnableImages,
enabledCodexModels,
codexDefaultModel,
setCodexAutoLoadAgents,
setCodexSandboxMode,
setCodexApprovalPolicy,
setCodexEnableWebSearch,
setCodexEnableImages,
setEnabledCodexModels,
setCodexDefaultModel,
toggleCodexModel,
} = useAppStore();

View File

@@ -44,7 +44,7 @@ export function CursorSettingsTab() {
try {
setCursorDefaultModel(model);
toast.success('Default model updated');
} catch (error) {
} catch {
toast.error('Failed to update default model');
} finally {
setIsSaving(false);
@@ -55,7 +55,7 @@ export function CursorSettingsTab() {
setIsSaving(true);
try {
toggleCursorModel(model, enabled);
} catch (error) {
} catch {
toast.error('Failed to update models');
} finally {
setIsSaving(false);

View File

@@ -23,13 +23,8 @@ import { OPENCODE_MODELS, OPENCODE_MODEL_CONFIG_MAP } from '@automaker/types';
import type { OpenCodeProviderInfo } from '../cli-status/opencode-cli-status';
import {
OpenCodeIcon,
DeepSeekIcon,
QwenIcon,
NovaIcon,
AnthropicIcon,
OpenRouterIcon,
MistralIcon,
MetaIcon,
GeminiIcon,
OpenAIIcon,
GrokIcon,
@@ -226,8 +221,6 @@ export function OpencodeModelConfiguration({
const selectableStaticModelIds = allStaticModelIds.filter(
(modelId) => modelId !== opencodeDefaultModel
);
const allDynamicModelIds = dynamicModels.map((model) => model.id);
const hasDynamicModels = allDynamicModelIds.length > 0;
const staticSelectState = getSelectionState(selectableStaticModelIds, enabledOpencodeModels);
// Order: Free tier first, then Claude, then others

View File

@@ -38,11 +38,6 @@ interface ClaudeSetupStepProps {
onSkip: () => void;
}
interface ClaudeSetupContentProps {
/** Hide header and navigation for embedded use */
embedded?: boolean;
}
type VerificationStatus = 'idle' | 'verifying' | 'verified' | 'error';
// Claude Setup Step
@@ -272,12 +267,6 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
const isApiKeyVerified = apiKeyVerificationStatus === 'verified';
const isReady = isCliVerified || isApiKeyVerified;
const getAuthMethodLabel = () => {
if (isApiKeyVerified) return 'API Key';
if (isCliVerified) return 'Claude CLI';
return null;
};
// Helper to get status badge for CLI
const getCliStatusBadge = () => {
if (cliVerificationStatus === 'verified') {

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - CLI setup wizard with step validation and setup store state
import { useState, useEffect, useCallback } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - Codex setup wizard with Electron API integration
import { useMemo, useCallback } from 'react';
import { useSetupStore } from '@/store/setup-store';
import { getElectronAPI } from '@/lib/electron';

View File

@@ -229,8 +229,6 @@ function ClaudeContent() {
claudeAuthStatus?.method === 'api_key_env';
const isCliAuthenticated = claudeAuthStatus?.method === 'cli_authenticated';
const isApiKeyAuthenticated =
claudeAuthStatus?.method === 'api_key' || claudeAuthStatus?.method === 'api_key_env';
const isReady = claudeCliStatus?.installed && claudeAuthStatus?.authenticated;
return (
@@ -803,7 +801,6 @@ function CodexContent() {
};
const isReady = codexCliStatus?.installed && codexAuthStatus?.authenticated;
const hasApiKey = !!apiKeys.openai || codexAuthStatus?.method === 'api_key';
return (
<Card className="bg-card border-border">

View File

@@ -32,6 +32,7 @@ function featureToInternal(feature: Feature): FeatureWithId {
}
function internalToFeature(internal: FeatureWithId): Feature {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { _id, _locationIds, ...feature } = internal;
return feature;
}

View File

@@ -27,6 +27,7 @@ function phaseToInternal(phase: RoadmapPhase): PhaseWithId {
}
function internalToPhase(internal: PhaseWithId): RoadmapPhase {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { _id, ...phase } = internal;
return phase;
}

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useNavigate } from '@tanstack/react-router';
import { createLogger } from '@automaker/utils/logger';
import {
@@ -58,7 +58,7 @@ import {
defaultDropAnimationSideEffects,
} from '@dnd-kit/core';
import { cn } from '@/lib/utils';
import { apiFetch, apiGet, apiPost, apiDeleteRaw, getAuthHeaders } from '@/lib/api-fetch';
import { apiFetch, apiGet, apiPost, apiDeleteRaw } from '@/lib/api-fetch';
import { getApiKey } from '@/lib/http-api-client';
const logger = createLogger('Terminal');
@@ -244,7 +244,6 @@ export function TerminalView({ initialCwd, initialBranch, initialMode, nonce }:
reorderTerminalTabs,
moveTerminalToTab,
setTerminalPanelFontSize,
setTerminalTabLayout,
toggleTerminalMaximized,
saveTerminalLayout,
getPersistedTerminalLayout,

View File

@@ -45,7 +45,6 @@ import { matchesShortcutWithCode } from '@/hooks/use-keyboard-shortcuts';
import {
getTerminalTheme,
TERMINAL_FONT_OPTIONS,
DEFAULT_TERMINAL_FONT,
getTerminalFontFamily,
} from '@/config/terminal-themes';
import { DEFAULT_FONT_VALUE } from '@/config/ui-font-options';
@@ -102,7 +101,6 @@ interface TerminalPanelProps {
type XTerminal = InstanceType<typeof import('@xterm/xterm').Terminal>;
type XFitAddon = InstanceType<typeof import('@xterm/addon-fit').FitAddon>;
type XSearchAddon = InstanceType<typeof import('@xterm/addon-search').SearchAddon>;
type XWebLinksAddon = InstanceType<typeof import('@xterm/addon-web-links').WebLinksAddon>;
export function TerminalPanel({
sessionId,
@@ -285,8 +283,8 @@ export function TerminalPanel({
// - CSI sequences: \x1b[...letter
// - OSC sequences: \x1b]...ST
// - Other escape sequences: \x1b followed by various characters
// eslint-disable-next-line no-control-regex
return text.replace(
// eslint-disable-next-line no-control-regex
/\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\x1b[>=<]|\x1b[78HM]|\x1b#[0-9]|\x1b./g,
''
);
@@ -670,8 +668,6 @@ export function TerminalPanel({
while ((match = filePathRegex.exec(lineText)) !== null) {
const fullMatch = match[1];
const filePath = match[2];
const lineNum = match[3] ? parseInt(match[3], 10) : undefined;
const colNum = match[4] ? parseInt(match[4], 10) : undefined;
// Skip common false positives (URLs, etc.)
if (

View File

@@ -45,8 +45,6 @@ interface ValidateIssueInput {
* ```
*/
export function useValidateIssue(projectPath: string) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (input: ValidateIssueInput) => {
const { issue, model, thinkingLevel, reasoningEffort, comments, linkedPRs } = input;

View File

@@ -93,7 +93,7 @@ export function useCommitWorktree() {
}
return result.result;
},
onSuccess: (_, { worktreePath }) => {
onSuccess: (_, { worktreePath: _worktreePath }) => {
// Invalidate all worktree queries since we don't know the project path
queryClient.invalidateQueries({ queryKey: ['worktrees'] });
toast.success('Changes committed');

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - Electron IPC boundary typing with stream events and message queuing
import { useState, useEffect, useCallback, useRef } from 'react';
import type { Message, StreamEvent } from '@/types/electron';
import { useMessageQueue } from './use-message-queue';
@@ -161,16 +161,15 @@ export function useElectronAgent({
);
// Message queue for queuing messages when agent is busy
const { queuedMessages, isProcessingQueue, addToQueue, clearQueue, processNext } =
useMessageQueue({
onProcessNext: async (queuedMessage) => {
await sendMessageDirectly(
queuedMessage.content,
queuedMessage.images,
queuedMessage.textFiles
);
},
});
const { queuedMessages, isProcessingQueue, clearQueue, processNext } = useMessageQueue({
onProcessNext: async (queuedMessage) => {
await sendMessageDirectly(
queuedMessage.content,
queuedMessage.images,
queuedMessage.textFiles
);
},
});
// Initialize connection and load history
useEffect(() => {

View File

@@ -6,7 +6,7 @@
* through WebSocket (indicating the connection is healthy).
*/
import { useEffect, useCallback } from 'react';
import { useCallback } from 'react';
import { create } from 'zustand';
/**

View File

@@ -1,4 +1,4 @@
// @ts-nocheck
// @ts-nocheck - responsive breakpoint logic with layout state calculations
import { useState, useEffect, useLayoutEffect, useCallback, useRef } from 'react';
import { useAppStore } from '@/store/app-store';

View File

@@ -53,17 +53,6 @@ interface MigrationState {
error: string | null;
}
/**
* localStorage keys that may contain settings to migrate
*/
const LOCALSTORAGE_KEYS = [
'automaker-storage',
'automaker-setup',
'worktree-panel-collapsed',
'file-browser-recent-folders',
'automaker:lastProjectDir',
] as const;
// NOTE: We intentionally do NOT clear any localStorage keys after migration.
// This allows users to switch back to older versions of Automaker that relied on localStorage.
// The `localStorageMigrated` flag in server settings prevents re-migration on subsequent app loads.
@@ -136,7 +125,7 @@ export function parseLocalStorageSettings(): Partial<GlobalSettings> | null {
const cacheProjectCount = cached?.projects?.length ?? 0;
logger.info(`[CACHE_LOADED] projects=${cacheProjectCount}, theme=${cached?.theme}`);
return cached;
} catch (e) {
} catch {
logger.warn('Failed to parse settings cache, falling back to old storage');
}
} else {

View File

@@ -34,7 +34,6 @@ import {
migratePhaseModelEntry,
type GlobalSettings,
type CursorModelId,
type OpencodeModelId,
type CodexModelId,
type GeminiModelId,
type CopilotModelId,

View File

@@ -1037,7 +1037,8 @@ if (typeof window !== 'undefined') {
}
// Mock API for development/fallback when no backend is available
const getMockElectronAPI = (): ElectronAPI => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _getMockElectronAPI = (): ElectronAPI => {
return {
ping: async () => 'pong (mock)',
@@ -1456,7 +1457,7 @@ function createMockSetupAPI(): SetupAPI {
};
},
storeApiKey: async (provider: string, apiKey: string) => {
storeApiKey: async (provider: string, _apiKey: string) => {
console.log('[Mock] Storing API key for:', provider);
// In mock mode, we just pretend to store it (it's already in the app store)
return { success: true };
@@ -1511,12 +1512,12 @@ function createMockSetupAPI(): SetupAPI {
};
},
onInstallProgress: (callback) => {
onInstallProgress: (_callback) => {
// Mock progress events
return () => {};
},
onAuthProgress: (callback) => {
onAuthProgress: (_callback) => {
// Mock auth events
return () => {};
},
@@ -1955,7 +1956,7 @@ function createMockWorktreeAPI(): WorktreeAPI {
};
},
onDevServerLogEvent: (callback) => {
onDevServerLogEvent: (_callback) => {
console.log('[Mock] Subscribing to dev server log events');
// Return unsubscribe function
return () => {
@@ -2007,7 +2008,7 @@ function createMockWorktreeAPI(): WorktreeAPI {
};
},
onInitScriptEvent: (callback) => {
onInitScriptEvent: (_callback) => {
console.log('[Mock] Subscribing to init script events');
// Return unsubscribe function
return () => {
@@ -2067,7 +2068,7 @@ function createMockWorktreeAPI(): WorktreeAPI {
};
},
onTestRunnerEvent: (callback) => {
onTestRunnerEvent: (_callback) => {
console.log('[Mock] Subscribing to test runner events');
// Return unsubscribe function
return () => {
@@ -2212,7 +2213,7 @@ function createMockAutoModeAPI(): AutoModeAPI {
return { success: true, passes: true };
},
resumeFeature: async (projectPath: string, featureId: string, useWorktrees?: boolean) => {
resumeFeature: async (projectPath: string, featureId: string, _useWorktrees?: boolean) => {
if (mockRunningFeatures.has(featureId)) {
return {
success: false,
@@ -2348,7 +2349,7 @@ function createMockAutoModeAPI(): AutoModeAPI {
featureId: string,
prompt: string,
imagePaths?: string[],
useWorktrees?: boolean
_useWorktrees?: boolean
) => {
if (mockRunningFeatures.has(featureId)) {
return {
@@ -2703,7 +2704,7 @@ function emitSpecRegenerationEvent(event: SpecRegenerationEvent) {
async function simulateSpecCreation(
projectPath: string,
projectOverview: string,
generateFeatures = true
_generateFeatures = true
) {
mockSpecRegenerationPhase = 'initialization';
emitSpecRegenerationEvent({

View File

@@ -62,7 +62,7 @@ export async function openDirectoryPicker(): Promise<DirectoryPickerResult | nul
}
};
input.addEventListener('change', (e) => {
input.addEventListener('change', () => {
changeEventFired = true;
if (focusTimeout) {
clearTimeout(focusTimeout);

View File

@@ -1,7 +1,6 @@
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
import type { ModelAlias, ModelProvider } from '@/store/app-store';
import { CODEX_MODEL_CONFIG_MAP, codexModelHasThinking } from '@automaker/types';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));

View File

@@ -28,8 +28,6 @@ import {
// Electron app bundle operations
setElectronAppPaths,
electronAppExists,
electronAppReadFileSync,
electronAppStatSync,
electronAppStat,
electronAppReadFile,
// System path operations
@@ -108,10 +106,6 @@ async function findAvailablePort(preferredPort: number): Promise<number> {
// Calculation: 4 columns × 280px + 3 gaps × 20px + 40px padding = 1220px board content
// With sidebar expanded (288px): 1220 + 288 = 1508px
// Minimum window dimensions - reduced to allow smaller windows since kanban now supports horizontal scrolling
const SIDEBAR_EXPANDED = 288;
const SIDEBAR_COLLAPSED = 64;
const MIN_WIDTH_EXPANDED = 800; // Reduced - horizontal scrolling handles overflow
const MIN_WIDTH_COLLAPSED = 600; // Reduced - horizontal scrolling handles overflow
const MIN_HEIGHT = 500; // Reduced to allow more flexibility
const DEFAULT_WIDTH = 1600;

View File

@@ -185,14 +185,10 @@ function RootLayoutContent() {
// Load project settings when switching projects
useProjectSettingsLoader();
// Check if we're in compact mode (< 1240px)
const isCompact = useIsCompact();
const isSetupRoute = location.pathname === '/setup';
const isLoginRoute = location.pathname === '/login';
const isLoggedOutRoute = location.pathname === '/logged-out';
const isDashboardRoute = location.pathname === '/dashboard';
const isBoardRoute = location.pathname === '/board';
const isRootRoute = location.pathname === '/';
const [autoOpenStatus, setAutoOpenStatus] = useState<AutoOpenStatus>(AUTO_OPEN_STATUS.idle);
const autoOpenCandidate = selectAutoOpenProject(currentProject, projects, projectHistory);
@@ -259,11 +255,8 @@ function RootLayoutContent() {
// Get effective theme and fonts for the current project
// Note: theme/fontFamilySans/fontFamilyMono are destructured above to ensure re-renders when they change
// eslint-disable-next-line @typescript-eslint/no-unused-vars
void theme; // Used for subscription
// eslint-disable-next-line @typescript-eslint/no-unused-vars
void fontFamilySans; // Used for subscription
// eslint-disable-next-line @typescript-eslint/no-unused-vars
void fontFamilyMono; // Used for subscription
const effectiveFontSans = getEffectiveFontSans();
const effectiveFontMono = getEffectiveFontMono();

View File

@@ -1731,7 +1731,7 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
},
upsertAndSetCurrentProject: (path, name, theme) => {
const { projects, trashedProjects, currentProject, theme: globalTheme } = get();
const { projects, trashedProjects } = get();
const existingProject = projects.find((p) => p.path === path);
let project: Project;
@@ -2108,6 +2108,7 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
let newOverrides: typeof currentOverrides;
if (entry === null) {
// Remove the override (use global)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [phase]: _, ...rest } = currentOverrides;
newOverrides = rest;
} else {
@@ -4367,6 +4368,7 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
clearInitScriptState: (projectPath, branch) => {
const key = `${projectPath}::${branch}`;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [key]: _, ...rest } = get().initScriptState;
set({ initScriptState: rest });
},

View File

@@ -62,7 +62,7 @@ const initialState: NotificationsState = {
// ============================================================================
export const useNotificationsStore = create<NotificationsState & NotificationsActions>(
(set, get) => ({
(set, _get) => ({
...initialState,
// Data management

View File

@@ -155,6 +155,7 @@ export const useTestRunnersStore = create<TestRunnersState & TestRunnersActions>
const finishedAt = new Date().toISOString();
// Remove from active sessions since it's no longer running
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [session.worktreePath]: _, ...remainingActive } = state.activeSessionByWorktree;
return {

View File

@@ -62,19 +62,6 @@ test.describe('Feature Manual Review Flow', () => {
const featureDir = path.join(automakerDir, 'features', featureId);
fs.mkdirSync(featureDir, { recursive: true });
const feature = {
id: featureId,
description: 'Test feature for manual review flow',
category: 'test',
status: 'waiting_approval',
skipTests: true,
model: 'sonnet',
thinkingLevel: 'none',
createdAt: new Date().toISOString(),
branchName: '',
priority: 2,
};
// Note: Feature is created via HTTP API in the test itself, not in beforeAll
// This ensures the feature exists when the board view loads it
});

View File

@@ -6,14 +6,12 @@
import { test, expect } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';
import {
createTempDirPath,
cleanupTempDir,
setupWelcomeView,
authenticateForTests,
handleLoginScreenIfPresent,
waitForNetworkIdle,
} from '../utils';
const TEST_TEMP_DIR = createTempDirPath('project-creation-test');

View File

@@ -17,7 +17,6 @@ import {
setupWelcomeView,
authenticateForTests,
handleLoginScreenIfPresent,
waitForNetworkIdle,
} from '../utils';
// Create unique temp dir for this test run

View File

@@ -620,7 +620,7 @@ export async function setupMockMultipleProjects(
projectCount: number = 3
): Promise<void> {
await page.addInitScript((count: number) => {
const mockProjects = [];
const mockProjects: TestProject[] = [];
for (let i = 0; i < count; i++) {
mockProjects.push({
id: `test-project-${i + 1}`,