From 0031cd7f2607f233bc5b8ceff48d112e31c3f9e2 Mon Sep 17 00:00:00 2001 From: Manas Raghuwanshi Date: Tue, 4 Aug 2026 23:36:27 +0530 Subject: [PATCH] chore: remove unused imports and dead ui plumbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tsconfig sets noUnusedLocals and noUnusedParameters to false and verify.ts has no rule for unused imports, so nothing in the gate ever complains about dead code. Running tsc with both flags as a one-off probe surfaced ~70 hits; this removes the ones that are genuinely dead rather than the parameters that exist for interface conformance. The load-bearing ones: runtime/loop.ts imported classifyCommand, commandOf and toolEffect and read none of them; two tools imported the TUI store they never touch, which is also the wrong direction architecturally. useBootAnimation carried a logoText state whose setter was never called, so it was permanently the empty string while BootScreen hardcoded the word it actually renders. HomeScreenData.provider existed only to hold the result of a getModelDisplayName() call that nothing rendered — app.tsx already derives the model name from the store — and removing it lets buildHomeScreen drop a parameter. isThinking was threaded from app.tsx through ConversationViewport into Timeline and read at none of them; the store field and the tests that assert on it are untouched, only the render plumbing is gone. Comments were left alone except for three cases that document nothing: an eslint-disable directive in a repo with no ESLint config, and restatement-only JSDoc in config/paths.ts ("Get the path to models.json"). The long "why" comments throughout providers/ and runtime/ are documentation and stay. One trap worth recording: getConfigDir() is not a pure getter, it mkdirSyncs the directory. Dropping the unused configDir local in initializeConfig() is only safe because the next line calls getProvidersConfigPath(), which calls getConfigDir() again. Two dead props were found and deliberately left: CommandPreview.query and Prompt.providerName are declared and passed by callers but never read. Removing them means editing prop interfaces plus call sites, which is a wider change than this one is scoped to. Co-Authored-By: Claude Opus 5 --- commands/agent.tsx | 13 +++------- config/paths.ts | 24 ++++++------------- onboarding/setupWizard.tsx | 3 +-- packages/tests/e2e/chat.e2e.test.ts | 6 +---- .../tests/runtime/agentController.test.ts | 2 +- packages/tests/runtime/agentLoop.test.ts | 2 +- packages/tests/slash/handler.test.ts | 1 - runtime/loop.ts | 1 - tools/runTests.ts | 1 - tools/terminal.ts | 1 - tui/src/app.overlay.test.tsx | 3 --- tui/src/app.planmode.test.tsx | 3 --- tui/src/app.tsx | 7 ++---- tui/src/components/BootScreen.tsx | 2 +- tui/src/components/HomeScreen.tsx | 5 ---- tui/src/components/MessageRenderer.tsx | 2 +- tui/src/components/PromptCard.tsx | 1 - tui/src/components/TurnFooter.tsx | 1 - tui/src/hooks/useBootAnimation.ts | 10 +++----- tui/src/hooks/useCancelKey.test.tsx | 3 --- tui/src/prompt.shape.test.tsx | 1 - tui/src/timeline.tsx | 3 +-- 22 files changed, 22 insertions(+), 73 deletions(-) diff --git a/commands/agent.tsx b/commands/agent.tsx index ab8bd40..07424a7 100644 --- a/commands/agent.tsx +++ b/commands/agent.tsx @@ -4,7 +4,7 @@ import type { AgentCallbacks, TurnSummary } from "../config/types"; import { App, store } from "../tui/src"; import { render } from "ink"; import { AgentController } from "./agentController"; -import { ACTIVE_PROVIDER_MODELS, DEFAULT_MODEL_ID, getModelDisplayName } from "../providers/client"; +import { DEFAULT_MODEL_ID } from "../providers/client"; import type { HomeScreenData } from "../tui/src/components/HomeScreen"; import { ensureProviderConfigured } from "../onboarding"; import { registerCommands } from "./slash"; @@ -317,7 +317,7 @@ async function runInteractive(modelOverride?: string) { }; const controller = new AgentController(provider, apiKey, selectedModel, callbacks); await controller.initialize(); - const homeScreen = await buildHomeScreen(provider, selectedModel); + const homeScreen = await buildHomeScreen(provider); const customStdin = new PassThrough() as any; customStdin.ref = () => { @@ -437,9 +437,7 @@ async function runInteractive(modelOverride?: string) { }); } -async function buildHomeScreen(provider: string, model: string): Promise { - const repository = - process.cwd().split("/").filter(Boolean).at(-1) ?? "workspace"; +async function buildHomeScreen(provider: string): Promise { const branch = await getBranch(); const providerLabel = provider === "google" ? "Gemini" : titleCase(provider); @@ -464,13 +462,8 @@ async function buildHomeScreen(provider: string, model: string): Promise { - const configDir = getConfigDir(); const providersPath = getProvidersConfigPath(); const conversationPath = getConversationPath(); - + // Create default providers.json if it doesn't exist if (!existsSync(providersPath)) { const defaultProviders = { @@ -92,7 +82,7 @@ export async function initializeConfig(): Promise { } } }; - + await Bun.write(providersPath, JSON.stringify(defaultProviders, null, 2)); } else { await removeRetiredProviders(providersPath); diff --git a/onboarding/setupWizard.tsx b/onboarding/setupWizard.tsx index 468428f..818171b 100644 --- a/onboarding/setupWizard.tsx +++ b/onboarding/setupWizard.tsx @@ -1,8 +1,7 @@ -import React, { useState } from "react"; +import { useState } from "react"; import { Box, Text, useInput } from "ink"; import TextInput from "ink-text-input"; import Spinner from "ink-spinner"; -import chalk from "chalk"; import { getEnabledProviders, type ProviderInfo } from "../providers/providerRegistry"; import { loginProvider } from "../config/authProvider"; import { getConfig, saveConfig } from "../config/config"; diff --git a/packages/tests/e2e/chat.e2e.test.ts b/packages/tests/e2e/chat.e2e.test.ts index 756261d..05a5007 100644 --- a/packages/tests/e2e/chat.e2e.test.ts +++ b/packages/tests/e2e/chat.e2e.test.ts @@ -1,11 +1,7 @@ import { describe, test, expect, beforeEach } from "bun:test"; import { AgentController } from "../../../commands/agentController"; import { MockProviderClient, CallbackSpy } from "../shared/mocks"; -import { - createTextEvent, - createDoneEvent, - createUserMessage, -} from "../shared/factories"; +import { createTextEvent, createDoneEvent } from "../shared/factories"; /** * End-to-End Chat Workflow Tests diff --git a/packages/tests/runtime/agentController.test.ts b/packages/tests/runtime/agentController.test.ts index 636e64b..4a943b8 100644 --- a/packages/tests/runtime/agentController.test.ts +++ b/packages/tests/runtime/agentController.test.ts @@ -1,4 +1,4 @@ -import { describe, test, expect, beforeEach, afterEach, afterAll, mock } from "bun:test"; +import { describe, test, expect, beforeEach, afterAll, mock } from "bun:test"; import { AgentController } from "../../../commands/agentController"; import type { Message } from "../../../config/types"; import { diff --git a/packages/tests/runtime/agentLoop.test.ts b/packages/tests/runtime/agentLoop.test.ts index 90f5b2f..62d0de1 100644 --- a/packages/tests/runtime/agentLoop.test.ts +++ b/packages/tests/runtime/agentLoop.test.ts @@ -14,7 +14,7 @@ import { createDoneEvent, generateLargeText, } from "../shared/factories"; -import { clone, extractAssistantText, getLastMessage } from "../shared/helpers"; +import { getLastMessage } from "../shared/helpers"; // Mock the getTool function from tools module const mockToolRegistry = new MockToolRegistry(); diff --git a/packages/tests/slash/handler.test.ts b/packages/tests/slash/handler.test.ts index ad21a5b..f0af4ae 100644 --- a/packages/tests/slash/handler.test.ts +++ b/packages/tests/slash/handler.test.ts @@ -1,6 +1,5 @@ import { test, expect } from "bun:test"; import { handleSlashCommand } from "../../../commands/slash/handler"; -import { registry } from "../../../commands/slash/registry"; import { registerCommands } from "../../../commands/slash/commands"; import type { SlashCommandContext } from "../../../commands/slash/types"; diff --git a/runtime/loop.ts b/runtime/loop.ts index f0e4098..51441f3 100644 --- a/runtime/loop.ts +++ b/runtime/loop.ts @@ -1,5 +1,4 @@ import { getTool, toolRegistry } from "../tools"; -import { classifyCommand, commandOf, toolEffect } from "./toolEffects"; import { blockedInPlanMode, planModeRefusal, planModeTools } from "./planMode"; import { isRetryableError } from "./retry"; import { compactToolHistory, toolHistoryBudget } from "./compaction"; diff --git a/tools/runTests.ts b/tools/runTests.ts index 71bd9c2..7ae49c8 100644 --- a/tools/runTests.ts +++ b/tools/runTests.ts @@ -1,5 +1,4 @@ import type { Tool } from "../config/types"; -import { store } from "../tui/src/store/ui-store"; import { formatCommandResult, runCommand } from "./command"; import { requestCommandApproval } from "./approval"; diff --git a/tools/terminal.ts b/tools/terminal.ts index d0f2771..6c59599 100644 --- a/tools/terminal.ts +++ b/tools/terminal.ts @@ -1,5 +1,4 @@ import type { Tool } from "../config/types"; -import { store } from "../tui/src/store/ui-store"; import { formatCommandResult, runCommand } from "./command"; import { requestCommandApproval } from "./approval"; diff --git a/tui/src/app.overlay.test.tsx b/tui/src/app.overlay.test.tsx index 04b05a1..259de00 100644 --- a/tui/src/app.overlay.test.tsx +++ b/tui/src/app.overlay.test.tsx @@ -1,5 +1,4 @@ import { describe, expect, test, beforeEach } from "bun:test"; -import React from "react"; import chalk from "chalk"; import { render } from "ink"; import { Writable } from "node:stream"; @@ -70,10 +69,8 @@ const homeScreen: HomeScreenData = { subtitle: "AI software engineering agent", promptExamples: ["Explain this repository"], capabilities: ["Build"], - repository: "woop-code", branch: "main", providerName: "Gemini", - provider: "Gemini 2.5 Flash Lite", }; const controller = { diff --git a/tui/src/app.planmode.test.tsx b/tui/src/app.planmode.test.tsx index 6fdc714..61f1dfe 100644 --- a/tui/src/app.planmode.test.tsx +++ b/tui/src/app.planmode.test.tsx @@ -1,5 +1,4 @@ import { describe, expect, test, beforeEach } from "bun:test"; -import React from "react"; import chalk from "chalk"; import { render } from "ink"; import { Writable } from "node:stream"; @@ -96,10 +95,8 @@ const homeScreen: HomeScreenData = { subtitle: "AI software engineering agent", promptExamples: ["Explain this repository"], capabilities: ["Build", "Plan"], - repository: "woop-code", branch: "main", providerName: "Gemini", - provider: "Gemini 2.5 Flash Lite", }; /** Only the surface the composer touches, with the mode it actually holds. */ diff --git a/tui/src/app.tsx b/tui/src/app.tsx index 03643ad..81505ba 100644 --- a/tui/src/app.tsx +++ b/tui/src/app.tsx @@ -14,7 +14,7 @@ import { ContinueTurn } from "./components/ContinueTurn"; import { QuestionDialog } from "./components/QuestionDialog"; import type { AgentController } from "../../commands/agentController"; import type { ActiveTurn, TimeLineItem } from "./types"; -import { useEffect, useRef, useState, type ReactNode } from "react"; +import { useEffect, useRef, useState } from "react"; import { useTerminalSize } from "./hooks/useTerminalSize"; import { useCancelKey } from "./hooks/useCancelKey"; import { planLayout } from "./layout"; @@ -116,7 +116,6 @@ export function App({ controller, onExit, homeScreen }: AppProps) { ) : ( - + {/* This viewport is bottom-anchored — its offset counts up from the last diff --git a/tui/src/components/BootScreen.tsx b/tui/src/components/BootScreen.tsx index 238d4ed..49511e4 100644 --- a/tui/src/components/BootScreen.tsx +++ b/tui/src/components/BootScreen.tsx @@ -9,7 +9,7 @@ interface BootScreenProps { } export function BootScreen({ onComplete }: BootScreenProps) { - const { logoText, loadingStep, doneSteps, phase } = useBootAnimation(onComplete); + const { loadingStep, doneSteps, phase } = useBootAnimation(onComplete); return ( diff --git a/tui/src/components/HomeScreen.tsx b/tui/src/components/HomeScreen.tsx index 0cd062e..604104a 100644 --- a/tui/src/components/HomeScreen.tsx +++ b/tui/src/components/HomeScreen.tsx @@ -13,10 +13,8 @@ export interface HomeScreenData { subtitle: string; promptExamples: readonly string[]; capabilities: readonly string[]; - repository: string; branch: string; providerName: string; - provider: string; } export interface HomeScreenProps extends HomeScreenData { @@ -35,9 +33,6 @@ export function HomeScreen({ subtitle, promptExamples, capabilities, - repository, - branch, - provider, renderPrompt, paletteOpen = false, }: HomeScreenProps) { diff --git a/tui/src/components/MessageRenderer.tsx b/tui/src/components/MessageRenderer.tsx index a0da9ac..26b7ccb 100644 --- a/tui/src/components/MessageRenderer.tsx +++ b/tui/src/components/MessageRenderer.tsx @@ -1,5 +1,5 @@ import { useMemo } from "react"; -import { Box, Text } from "ink"; +import { Box } from "ink"; import type { Token } from "marked"; import { lexMarkdown } from "../markdown-lexer"; import { Markdown } from "./Markdown"; diff --git a/tui/src/components/PromptCard.tsx b/tui/src/components/PromptCard.tsx index 34946ab..b428333 100644 --- a/tui/src/components/PromptCard.tsx +++ b/tui/src/components/PromptCard.tsx @@ -1,7 +1,6 @@ import { Box } from "ink"; import { useEffect, useState } from "react"; import type { ReactNode } from "react"; -import { colors } from "../styles/theme"; const PLACEHOLDER_ROTATION_MS = 3500; const TYPEWRITER_FRAME_MS = 24; diff --git a/tui/src/components/TurnFooter.tsx b/tui/src/components/TurnFooter.tsx index 101f3e9..3b4e63c 100644 --- a/tui/src/components/TurnFooter.tsx +++ b/tui/src/components/TurnFooter.tsx @@ -93,7 +93,6 @@ function RunningTurnFooter(props: TurnFooterProps) { function TurnFooterRow({ agent, model, - endedAt, outcome, elapsed, pulseFrame, diff --git a/tui/src/hooks/useBootAnimation.ts b/tui/src/hooks/useBootAnimation.ts index 7162f22..529f7ca 100644 --- a/tui/src/hooks/useBootAnimation.ts +++ b/tui/src/hooks/useBootAnimation.ts @@ -3,13 +3,11 @@ import { useState, useEffect } from "react"; export type BootPhase = "logo" | "steps" | "launching" | "done"; export interface BootAnimationState { - logoText: string; loadingStep: number; // index of the currently-spinning step (-1 = none) doneSteps: Set; phase: BootPhase; } -const LOGO = "Woopcode"; const STEPS = ["Runtime", "Provider", "Tool Registry", "Repository Context"]; const LOGO_DURATION_MS = 600; // duration of LogoReveal animation @@ -18,10 +16,9 @@ const STEP_GAP_MS = 220; // gap between steps starting (must be > STEP_HOLD const LAUNCH_MS = 350; // "Launching..." shown for this long before onComplete export function useBootAnimation(onComplete: () => void): BootAnimationState { - const [logoText, setLogoText] = useState(""); const [loadingStep, setLoadingStep] = useState(-1); - const [doneSteps, setDoneSteps] = useState>(new Set()); - const [phase, setPhase] = useState("logo"); + const [doneSteps, setDoneSteps] = useState>(new Set()); + const [phase, setPhase] = useState("logo"); useEffect(() => { const timers: ReturnType[] = []; @@ -58,10 +55,9 @@ export function useBootAnimation(onComplete: () => void): BootAnimationState { return () => timers.forEach(clearTimeout); // onComplete is stable (comes from useState setter reference in agent.tsx) - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - return { logoText, loadingStep, doneSteps, phase }; + return { loadingStep, doneSteps, phase }; } export { STEPS }; diff --git a/tui/src/hooks/useCancelKey.test.tsx b/tui/src/hooks/useCancelKey.test.tsx index 672f379..8362b2a 100644 --- a/tui/src/hooks/useCancelKey.test.tsx +++ b/tui/src/hooks/useCancelKey.test.tsx @@ -1,5 +1,4 @@ import { describe, expect, test, beforeEach } from "bun:test"; -import React from "react"; import { render } from "ink"; import { Writable } from "node:stream"; import { EventEmitter } from "node:events"; @@ -60,10 +59,8 @@ const homeScreen: HomeScreenData = { subtitle: "AI software engineering agent", promptExamples: ["Explain this repository"], capabilities: ["Build"], - repository: "woop-code", branch: "main", providerName: "Gemini", - provider: "Gemini 2.5 Flash Lite", }; function mountApp({ busy }: { busy: boolean }) { diff --git a/tui/src/prompt.shape.test.tsx b/tui/src/prompt.shape.test.tsx index 366cef5..8854448 100644 --- a/tui/src/prompt.shape.test.tsx +++ b/tui/src/prompt.shape.test.tsx @@ -1,5 +1,4 @@ import { describe, expect, test, beforeEach } from "bun:test"; -import React from "react"; import chalk from "chalk"; import { render } from "ink"; import { Writable } from "node:stream"; diff --git a/tui/src/timeline.tsx b/tui/src/timeline.tsx index 8a2f30e..42a253b 100644 --- a/tui/src/timeline.tsx +++ b/tui/src/timeline.tsx @@ -17,7 +17,6 @@ import { TodoList } from "./components/TodoList"; interface TimelineProps { items: TimeLineItem[]; - isThinking: boolean; activeTurn: ActiveTurn | null; } @@ -33,7 +32,7 @@ interface TimelineProps { */ const MAX_RENDERED_ITEMS = 300; -export function Timeline({ items, isThinking, activeTurn }: TimelineProps) { +export function Timeline({ items, activeTurn }: TimelineProps) { return (