From fcc114e846b8e6a7b1f7bd31c7a04f336d229d70 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:10:01 +0100 Subject: [PATCH 01/18] docs(plans): add inline type extraction plan for 28 findings across 13 files --- .../plans/2026-03-18-InlineTypeExtraction.md | 346 ++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 .claude/plans/2026-03-18-InlineTypeExtraction.md diff --git a/.claude/plans/2026-03-18-InlineTypeExtraction.md b/.claude/plans/2026-03-18-InlineTypeExtraction.md new file mode 100644 index 00000000..00c1116d --- /dev/null +++ b/.claude/plans/2026-03-18-InlineTypeExtraction.md @@ -0,0 +1,346 @@ +# Inline Type Extraction Plan + +Extract 28 inline type annotations into named interfaces across 13 files. +Branch: `fix/inline-types` (from master, `--no-track`) + +## Principles + +- **Type placement**: module-internal types at top of same file; shared types in existing `types.ts` files +- **One commit per file** (or per logical group of related files) +- **Verify after each change**: `tsgo --noEmit` scoped to the changed file(s) +- **No functional changes** -- pure type extractions only + +--- + +## Task 1: `src/ask/utils/cli.ts` (3 extractions) + +- [ ] Read file, verify findings at lines 160, 245, 265 +- [ ] Add at top of file (after imports): + ```ts + interface ValidationResult { + valid: boolean; + errors: string[]; + } + + interface OutputFormatResult { + type: OutputFormat; + filename?: string; + } + ``` +- [ ] Replace `validateOptions` return type (line 160): `{ valid: boolean; errors: string[] }` -> `ValidationResult` +- [ ] Replace `parseOutputFormat` return type (line 245): `{ type: OutputFormat; filename?: string } | undefined` -> `OutputFormatResult | undefined` +- [ ] Replace `getOutputFormat` return type (line 265): same -> `OutputFormatResult | undefined` +- [ ] Run: `tsgo --noEmit | rg "src/ask/utils/cli"` +- [ ] Commit: `refactor(ask): extract ValidationResult and OutputFormatResult interfaces` + +## Task 2: `src/ask/AIChat.ts` (1 extraction) + +- [ ] Read file, verify finding at line 244 +- [ ] Add at top of file (after imports): + ```ts + interface EngineWithRestore { + engine: ChatEngine; + restore: () => void; + } + ``` +- [ ] Replace `_getEngine` return type (line 244): `{ engine: ChatEngine; restore: () => void }` -> `EngineWithRestore` +- [ ] Run: `tsgo --noEmit | rg "src/ask/AIChat"` +- [ ] Commit: `refactor(ask): extract EngineWithRestore interface` + +## Task 3: `src/ask/utils/websearch.ts` (1 extraction) + +- [ ] Read file, verify finding at line 178 +- [ ] Add at top of file (after imports): + ```ts + interface WebSearchParams { + query: string; + numResults?: number; + safeSearch?: string; + } + ``` +- [ ] Replace inline callback parameter type (line 178): `(params: { query: string; numResults?: number; safeSearch?: string })` -> `(params: WebSearchParams)` +- [ ] Run: `tsgo --noEmit | rg "src/ask/utils/websearch"` +- [ ] Commit: `refactor(ask): extract WebSearchParams interface` + +## Task 4: `src/ask/providers/ProviderManager.ts` (1 extraction) + +- [ ] Read file, verify finding at line 375 +- [ ] Add at top of file (after imports): + ```ts + interface ModelMetadata { + id: string; + description?: string; + } + ``` +- [ ] Replace `parseCapabilities` parameter type (line 375): `(model: { id: string; description?: string })` -> `(model: ModelMetadata)` +- [ ] Run: `tsgo --noEmit | rg "src/ask/providers/ProviderManager"` +- [ ] Commit: `refactor(ask): extract ModelMetadata interface` + +## Task 5: `src/mcp-manager/utils/command.utils.ts` (2 extractions) + +- [ ] Read file, verify findings at lines 104 and 121 +- [ ] Add at top of file (after imports): + ```ts + interface ParsedCommand { + command: string; + args: string[]; + } + + interface KeyValuePair { + key: string; + value: string; + } + ``` +- [ ] Replace `parseCommandString` return type (line 104): `{ command: string; args: string[] }` -> `ParsedCommand` +- [ ] Replace `parseSinglePair` return type (line 121): `{ key: string; value: string } | null` -> `KeyValuePair | null` +- [ ] Run: `tsgo --noEmit | rg "src/mcp-manager/utils/command.utils"` +- [ ] Commit: `refactor(mcp-manager): extract ParsedCommand and KeyValuePair interfaces` + +## Task 6: `src/mcp-tsc/LspWorker.ts` (2 extractions) + +- [ ] Read file, verify findings at lines 278 and 900 +- [ ] Add at top of file (after imports): + ```ts + interface LspDiagnosticsNotification { + uri: string; + diagnostics: LspDiagnostic[]; + } + + interface QueueStats { + length: number; + isProcessing: boolean; + } + ``` +- [ ] Replace diagnostics callback parameter type (line 278): `(params: { uri: string; diagnostics: LspDiagnostic[] })` -> `(params: LspDiagnosticsNotification)` +- [ ] Replace `getQueueStats` return type (line 900): `{ length: number; isProcessing: boolean }` -> `QueueStats` +- [ ] Run: `tsgo --noEmit | rg "src/mcp-tsc/LspWorker"` +- [ ] Commit: `refactor(mcp-tsc): extract LspDiagnosticsNotification and QueueStats interfaces` + +## Task 7: `src/github-release-notes/index.ts` (1 extraction) + +- [ ] Read file, verify finding at line 127 +- [ ] Add at top of file (after imports): + ```ts + interface RepoIdentity { + owner: string; + repo: string; + } + ``` +- [ ] Replace `parseRepoArg` return type (line 127): `{ owner: string; repo: string } | null` -> `RepoIdentity | null` +- [ ] Run: `tsgo --noEmit | rg "src/github-release-notes/index"` +- [ ] Commit: `refactor(github-release-notes): extract RepoIdentity interface` + +## Task 8: `src/telegram/lib/TGClient.ts` (1 extraction) + +- [ ] Read file, verify finding at line 95 +- [ ] Add at top of file (after imports): + ```ts + interface StopHandle { + stop: () => void; + } + ``` +- [ ] Replace `startTypingLoop` return type (line 95): `{ stop: () => void }` -> `StopHandle` +- [ ] Run: `tsgo --noEmit | rg "src/telegram/lib/TGClient"` +- [ ] Commit: `refactor(telegram): extract StopHandle interface` + +## Task 9: `src/macos-resources/index.tsx` (4 extractions) + +- [ ] Read file, verify findings at lines 150, 176, 185, 207 +- [ ] Add at top of file (after imports). Note: these are React component prop types, so use explicit prop interfaces: + ```ts + interface MemoizedHeaderProps { + children: React.ReactNode; + sortBy: "cpu" | "pid" | "files"; + } + + interface MemoizedCellProps { + children: React.ReactNode; + column: number; + } + + interface MemoizedNotificationsPanelProps { + notifications: Notification[]; + } + + interface MemoizedCommandPanelProps { + commandHistory: CommandPerformance[]; + } + ``` +- [ ] Replace `MemoizedHeader` inline props (line 150): `({ children, sortBy }: { children: React.ReactNode; sortBy: "cpu" | "pid" | "files" })` -> `({ children, sortBy }: MemoizedHeaderProps)` +- [ ] Replace `MemoizedCell` inline props (line 176): `({ children, column }: { children: React.ReactNode; column: number })` -> `({ children, column }: MemoizedCellProps)` +- [ ] Replace `MemoizedNotificationsPanel` inline props (line 185): `({ notifications }: { notifications: Notification[] })` -> `({ notifications }: MemoizedNotificationsPanelProps)` +- [ ] Replace `MemoizedCommandPanel` inline props (line 207): `({ commandHistory }: { commandHistory: CommandPerformance[] })` -> `({ commandHistory }: MemoizedCommandPanelProps)` +- [ ] Run: `tsgo --noEmit | rg "src/macos-resources/index"` +- [ ] Commit: `refactor(macos-resources): extract React component prop interfaces` + +## Task 10: `src/claude-history-dashboard/src/integrations/tanstack-query/root-provider.tsx` (1 extraction) + +- [ ] Read file, verify finding at line 10 +- [ ] Add at top of file (after imports): + ```ts + interface ProviderProps { + children: React.ReactNode; + queryClient: QueryClient; + } + ``` +- [ ] Replace `Provider` inline props (line 10): `({ children, queryClient }: { children: React.ReactNode; queryClient: QueryClient })` -> `({ children, queryClient }: ProviderProps)` +- [ ] Run: `tsgo --noEmit | rg "root-provider"` +- [ ] Commit: `refactor(claude-history-dashboard): extract ProviderProps interface` + +## Task 11: `src/markdown-cli/index.ts` (1 extraction) + +- [ ] Read file, verify finding at line 22 +- [ ] Add at top of file (after imports): + ```ts + interface MarkdownCLIOptions { + watch?: boolean; + width?: number; + theme?: string; + color?: boolean; + } + ``` +- [ ] Replace `.action()` inline options type (line 22): `(file?: string, opts?: { watch?: boolean; width?: number; theme?: string; color?: boolean })` -> `(file?: string, opts?: MarkdownCLIOptions)` +- [ ] Run: `tsgo --noEmit | rg "src/markdown-cli/index"` +- [ ] Commit: `refactor(markdown-cli): extract MarkdownCLIOptions interface` + +## Task 12: `src/azure-devops/commands/timelog/prepare-import.ts` (4 extractions) + +- [ ] Read file, verify findings at lines 86, 190, 210, 279 +- [ ] Add at top of file (after imports): + ```ts + interface TimelogAddOptions { + from?: string; + to?: string; + name?: string; + entry: string; + } + + interface TimelogRemoveOptions { + name: string; + id: string; + } + + interface TimelogListOptions { + name: string; + format?: string; + } + + interface TimelogClearOptions { + name: string; + } + ``` +- [ ] Replace `handleAdd` parameter type (line 86): `(options: { from?: string; to?: string; name?: string; entry: string })` -> `(options: TimelogAddOptions)` +- [ ] Replace `handleRemove` parameter type (line 190): `(options: { name: string; id: string })` -> `(options: TimelogRemoveOptions)` +- [ ] Replace `handleList` parameter type (line 210): `(options: { name: string; format?: string })` -> `(options: TimelogListOptions)` +- [ ] Replace `handleClear` parameter type (line 279): `(options: { name: string })` -> `(options: TimelogClearOptions)` +- [ ] Run: `tsgo --noEmit | rg "src/azure-devops/commands/timelog/prepare-import"` +- [ ] Commit: `refactor(azure-devops): extract timelog prepare-import option interfaces` + +## Task 13: `src/automate/lib/builtins.ts` (3 extractions) + +The `{ result: StepResult; jumpTo?: string }` pattern is used by `executeBuiltin` (line 23), `handleIf` (line 43), `handlePrompt` (line 79), `handleShell` (line 111), `step-runner.ts:executeStep` (line 21). The `{ result: StepResult }` subset is used by `handleLog` (line 63), `handleSet` (line 165). + +- [ ] Read `src/automate/lib/types.ts`, add to it: + ```ts + /** Result from a step handler, with optional jump target for branching */ + interface StepHandlerResult { + result: StepResult; + jumpTo?: string; + } + ``` + Note: `{ result: StepResult }` is a subset of `StepHandlerResult` (jumpTo is already optional), so all three handler return types can use `StepHandlerResult`. +- [ ] In `src/automate/lib/builtins.ts`: + - Update import to include `StepHandlerResult` + - Replace `executeBuiltin` return type (line 23): `Promise<{ result: StepResult; jumpTo?: string }>` -> `Promise` + - Replace `handleIf` return type (line 43): `{ result: StepResult; jumpTo?: string }` -> `StepHandlerResult` + - Replace `handleLog` return type (line 63): `{ result: StepResult }` -> `StepHandlerResult` + - Replace `handlePrompt` return type (line 79): `Promise<{ result: StepResult }>` -> `Promise` + - Replace `handleShell` return type (line 111): `Promise<{ result: StepResult }>` -> `Promise` + - Replace `handleSet` return type (line 165): `{ result: StepResult }` -> `StepHandlerResult` +- [ ] In `src/automate/lib/step-runner.ts`: + - Update import to include `StepHandlerResult` + - Replace `executeStep` return type (line 21): `Promise<{ result: StepResult; jumpTo?: string }>` -> `Promise` +- [ ] In `src/automate/lib/engine.ts`: + - Update import to include `StepHandlerResult` (check if it uses the same pattern) + - Replace any matching inline types +- [ ] Run: `tsgo --noEmit | rg "src/automate/lib/"` +- [ ] Commit: `refactor(automate): extract StepHandlerResult to shared types` + +## Task 14: `src/utils/markdown/index.ts` (1 extraction) + +- [ ] Read file, verify finding at line 152 +- [ ] Add at top of file (after imports): + ```ts + interface ParsedTableTokens { + data: TableData; + endIdx: number; + } + ``` +- [ ] Replace `parseTableTokens` return type (line 152): `{ data: TableData; endIdx: number }` -> `ParsedTableTokens` +- [ ] Run: `tsgo --noEmit | rg "src/utils/markdown/index"` +- [ ] Commit: `refactor(utils): extract ParsedTableTokens interface` + +## Task 15: `src/mcp-web-reader/utils/tokens.ts` (1 extraction) + +- [ ] Read file, verify finding at line 12 +- [ ] Add at top of file (after imports): + ```ts + interface TokenLimitResult { + text: string; + tokens: number; + truncated: boolean; + } + ``` +- [ ] Replace `limitToTokens` return type (line 12): `{ text: string; tokens: number; truncated: boolean }` -> `TokenLimitResult` +- [ ] Run: `tsgo --noEmit | rg "src/mcp-web-reader/utils/tokens"` +- [ ] Commit: `refactor(mcp-web-reader): extract TokenLimitResult interface` + +## Task 16: `src/Internal/LoggerLib/Logger.ts` (1 extraction) + +- [ ] Read file, verify finding at line 710 +- [ ] Add at top of file (after imports) or near the `fileTransport` function: + ```ts + interface FileTransportOptions { + filePath: string; + append?: boolean; + encoding?: string; + } + ``` +- [ ] Replace `fileTransport` parameter type (line 710): `(options: { filePath: string; append?: boolean; encoding?: string })` -> `(options: FileTransportOptions)` +- [ ] Run: `tsgo --noEmit | rg "src/Internal/LoggerLib/Logger"` +- [ ] Commit: `refactor(internal): extract FileTransportOptions interface` + +--- + +## Task 17: Final validation and PR + +- [ ] Run full type check: `tsgo --noEmit` (no filter -- whole project) +- [ ] Verify all 28 extractions are done: `git log --oneline fix/inline-types ^master` +- [ ] Push: `git push -u origin fix/inline-types` +- [ ] Create PR to `master`: + - Title: `refactor: extract 28 inline type annotations into named interfaces` + - Body: summary of changes by category, link to this plan + +--- + +## File-to-Task Index + +| File | Task | Extractions | +|------|------|-------------| +| `src/ask/utils/cli.ts` | 1 | 3 | +| `src/ask/AIChat.ts` | 2 | 1 | +| `src/ask/utils/websearch.ts` | 3 | 1 | +| `src/ask/providers/ProviderManager.ts` | 4 | 1 | +| `src/mcp-manager/utils/command.utils.ts` | 5 | 2 | +| `src/mcp-tsc/LspWorker.ts` | 6 | 2 | +| `src/github-release-notes/index.ts` | 7 | 1 | +| `src/telegram/lib/TGClient.ts` | 8 | 1 | +| `src/macos-resources/index.tsx` | 9 | 4 | +| `src/claude-history-dashboard/.../root-provider.tsx` | 10 | 1 | +| `src/markdown-cli/index.ts` | 11 | 1 | +| `src/azure-devops/commands/timelog/prepare-import.ts` | 12 | 4 | +| `src/automate/lib/builtins.ts` + `types.ts` + `step-runner.ts` + `engine.ts` | 13 | 3 | +| `src/utils/markdown/index.ts` | 14 | 1 | +| `src/mcp-web-reader/utils/tokens.ts` | 15 | 1 | +| `src/Internal/LoggerLib/Logger.ts` | 16 | 1 | +| **Total** | | **28** | From e9a60cc55c8176c86d5d1be2ce8d1a0766a7eb91 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:11:57 +0100 Subject: [PATCH 02/18] refactor(ask): extract ValidationResult and OutputFormatResult interfaces --- src/ask/utils/cli.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ask/utils/cli.ts b/src/ask/utils/cli.ts index 5cd09188..5187b823 100644 --- a/src/ask/utils/cli.ts +++ b/src/ask/utils/cli.ts @@ -3,6 +3,16 @@ import { SafeJSON } from "@app/utils/json"; import type { Args, CLIOptions, OutputFormat } from "@ask/types"; import { Command } from "commander"; +interface ValidationResult { + valid: boolean; + errors: string[]; +} + +interface OutputFormatResult { + type: OutputFormat; + filename?: string; +} + export function parseCLIArguments(): Args { const program = new Command() .name("ask") @@ -162,7 +172,7 @@ export function showVersion(): void { console.log("Multi-provider LLM chat application for GenesisTools"); } -export function validateOptions(options: CLIOptions): { valid: boolean; errors: string[] } { +export function validateOptions(options: CLIOptions): ValidationResult { const errors: string[] = []; // Validate temperature @@ -253,7 +263,7 @@ export function shouldShowVersion(options: CLIOptions): boolean { * -f json → json to stdout * -f markdown -o out.md → markdown written to file */ -export function getOutputFormat(options: CLIOptions): { type: OutputFormat; filename?: string } | undefined { +export function getOutputFormat(options: CLIOptions): OutputFormatResult | undefined { // -o implies file output if (options.output) { return { type: "file", filename: options.output }; From cab9ce1ee3c376177ed267b8923688d91b709ff8 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:12:22 +0100 Subject: [PATCH 03/18] refactor(ask): extract EngineWithRestore interface --- src/ask/AIChat.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ask/AIChat.ts b/src/ask/AIChat.ts index 3f169af4..f63f7ef9 100644 --- a/src/ask/AIChat.ts +++ b/src/ask/AIChat.ts @@ -19,6 +19,11 @@ import { providerManager } from "@ask/providers/ProviderManager"; import type { ChatConfig } from "@ask/types"; import { getLanguageModel } from "@ask/types"; +interface EngineWithRestore { + engine: ChatEngine; + restore: () => void; +} + const DEFAULT_SESSION_DIR = resolve(homedir(), ".genesis-tools/ai-chat/sessions"); export class AIChat { @@ -241,7 +246,7 @@ export class AIChat { /** Get a ChatEngine instance with optional per-call overrides. * Returns a restore function that resets the engine to its previous state. */ - private _getEngine(override?: SendOptions["override"]): { engine: ChatEngine; restore: () => void } { + private _getEngine(override?: SendOptions["override"]): EngineWithRestore { if (!this._engine) { throw new Error("AIChat not initialized"); } From 4b412da5ceed3e8d3133f3293a13f67a01ad3b30 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:12:46 +0100 Subject: [PATCH 04/18] refactor(ask): extract WebSearchParams interface --- src/ask/utils/websearch.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ask/utils/websearch.ts b/src/ask/utils/websearch.ts index 1f3669ca..06390fa0 100644 --- a/src/ask/utils/websearch.ts +++ b/src/ask/utils/websearch.ts @@ -1,6 +1,12 @@ import logger from "@app/logger"; import type { SearchResult, WebSearchOptions } from "@ask/types"; +interface WebSearchParams { + query: string; + numResults?: number; + safeSearch?: string; +} + export class WebSearchTool { private apiKey?: string; private baseURL = "https://api.search.brave.com/res/v1"; @@ -175,7 +181,7 @@ export class WebSearchTool { optional: true, }, }, - execute: async (params: { query: string; numResults?: number; safeSearch?: string }) => { + execute: async (params: WebSearchParams) => { try { const results = await this.searchWeb(params.query, { numResults: params.numResults, From ca5206eb615062bb273e63b57732c425879ecfff Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:13:22 +0100 Subject: [PATCH 05/18] refactor(ask): extract ModelMetadata interface --- src/ask/providers/ProviderManager.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ask/providers/ProviderManager.ts b/src/ask/providers/ProviderManager.ts index 23adbfe3..b6a5c20f 100644 --- a/src/ask/providers/ProviderManager.ts +++ b/src/ask/providers/ProviderManager.ts @@ -18,6 +18,11 @@ import { getLanguageModel } from "@ask/types"; import type { AskConfig } from "@ask/types/config"; import { generateText } from "ai"; +interface ModelMetadata { + id: string; + description?: string; +} + export class ProviderManager { private detectedProviders: Map = new Map(); private initialized = false; @@ -598,7 +603,7 @@ export class ProviderManager { }; } - private parseCapabilities(model: { id: string; description?: string }): string[] { + private parseCapabilities(model: ModelMetadata): string[] { const capabilities: string[] = ["chat"]; if (model.description?.toLowerCase().includes("vision") || model.id.toLowerCase().includes("vision")) { From 20cfe2960c4210cd8bf837f8734b9f03b38541ca Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:13:50 +0100 Subject: [PATCH 06/18] refactor(mcp-manager): extract ParsedCommand and KeyValuePair interfaces --- src/mcp-manager/utils/command.utils.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/mcp-manager/utils/command.utils.ts b/src/mcp-manager/utils/command.utils.ts index 6f0e399d..661c7c10 100644 --- a/src/mcp-manager/utils/command.utils.ts +++ b/src/mcp-manager/utils/command.utils.ts @@ -4,6 +4,16 @@ import { ExitPromptError } from "@inquirer/core"; import { checkbox } from "@inquirer/prompts"; import type { MCPProvider, UnifiedMCPConfig } from "./providers/types.js"; +interface ParsedCommand { + command: string; + args: string[]; +} + +interface KeyValuePair { + key: string; + value: string; +} + /** * Show help message for the mcp-manager tool */ @@ -101,7 +111,7 @@ Non-Interactive Examples (for scripts and AI assistants): * Parse a command string into command and args. * Example: "npx -y @modelcontextprotocol/server-github" -> { command: "npx", args: ["-y", "@modelcontextprotocol/server-github"] } */ -export function parseCommandString(commandString: string): { command: string; args: string[] } { +export function parseCommandString(commandString: string): ParsedCommand { const parts = commandString.trim().split(/\s+/); if (parts.length === 0) { throw new Error("Command string cannot be empty"); @@ -118,7 +128,7 @@ export function parseCommandString(commandString: string): { command: string; ar * @param separator - The separator character (e.g., ":" or "=") * @returns The key-value pair, or null if invalid format */ -function parseSinglePair(input: string, separator: string): { key: string; value: string } | null { +function parseSinglePair(input: string, separator: string): KeyValuePair | null { const str = input.trim(); if (!str) { return null; From afe33b2870eeecf79850348d5baddf819993aae4 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:14:39 +0100 Subject: [PATCH 07/18] refactor(mcp-tsc): extract LspDiagnosticsNotification and QueueStats interfaces --- src/mcp-tsc/LspWorker.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/mcp-tsc/LspWorker.ts b/src/mcp-tsc/LspWorker.ts index 271cfd80..0ac093fb 100644 --- a/src/mcp-tsc/LspWorker.ts +++ b/src/mcp-tsc/LspWorker.ts @@ -64,6 +64,16 @@ interface LspDiagnostic { message: string; } +interface LspDiagnosticsNotification { + uri: string; + diagnostics: LspDiagnostic[]; +} + +interface QueueStats { + length: number; + isProcessing: boolean; +} + // Error types for classification export class LspError extends Error { constructor( @@ -275,7 +285,7 @@ export class LspWorker { // Handle diagnostics notifications this.endpoint.on( "textDocument/publishDiagnostics", - (params: { uri: string; diagnostics: LspDiagnostic[] }) => { + (params: LspDiagnosticsNotification) => { this.handleDiagnosticsNotification(params); } ); @@ -897,7 +907,7 @@ export class LspWorker { } // For testing/debugging - getQueueStats(): { length: number; isProcessing: boolean } { + getQueueStats(): QueueStats { return { length: this.requestQueue.length, isProcessing: this.requestQueue.isProcessing, From 288250ec5ceac97f8659655b52b2a52f79edf4e1 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:15:08 +0100 Subject: [PATCH 08/18] refactor(github-release-notes): extract RepoIdentity interface --- src/github-release-notes/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/github-release-notes/index.ts b/src/github-release-notes/index.ts index 2b285975..60418d06 100644 --- a/src/github-release-notes/index.ts +++ b/src/github-release-notes/index.ts @@ -16,6 +16,11 @@ interface GitHubRelease { html_url: string; } +interface RepoIdentity { + owner: string; + repo: string; +} + interface ScriptOptions { owner: string; repo: string; @@ -124,7 +129,7 @@ function generateMarkdown(releases: GitHubRelease[], owner: string, repo: string return headerContent + releasesContent; } -function parseRepoArg(repoArg: string): { owner: string; repo: string } | null { +function parseRepoArg(repoArg: string): RepoIdentity | null { // Accepts owner/repo or full github.com URL if (!repoArg) { return null; From 9727494e1cf2bc73d0ed98a739827c72eccf80ee Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:15:37 +0100 Subject: [PATCH 09/18] refactor(telegram): extract StopHandle interface --- src/telegram/lib/TGClient.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/telegram/lib/TGClient.ts b/src/telegram/lib/TGClient.ts index 65ea0b1b..d2c1e23d 100644 --- a/src/telegram/lib/TGClient.ts +++ b/src/telegram/lib/TGClient.ts @@ -14,6 +14,10 @@ export interface AuthCallbacks { password: () => Promise; } +interface StopHandle { + stop: () => void; +} + export class TGClient { private client: TelegramClient; @@ -92,7 +96,7 @@ export class TGClient { ); } - startTypingLoop(userId: string, username?: string): { stop: () => void } { + startTypingLoop(userId: string, username?: string): StopHandle { let stopped = false; const tick = async () => { From bd96a404847f211046943eaa792456f0b80cd465 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:16:33 +0100 Subject: [PATCH 10/18] refactor(macos-resources): extract React component prop interfaces --- src/macos-resources/index.tsx | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/macos-resources/index.tsx b/src/macos-resources/index.tsx index 76f887d1..d527cd96 100644 --- a/src/macos-resources/index.tsx +++ b/src/macos-resources/index.tsx @@ -111,6 +111,24 @@ interface CommandPerformance { timestamp: Date; } +interface MemoizedHeaderProps { + children: React.ReactNode; + sortBy: "cpu" | "pid" | "files"; +} + +interface MemoizedCellProps { + children: React.ReactNode; + column: number; +} + +interface MemoizedNotificationsPanelProps { + notifications: Notification[]; +} + +interface MemoizedCommandPanelProps { + commandHistory: CommandPerformance[]; +} + // Custom Table component using Ink's Box and Text // const Table: React.FC<{ // data: Array>; @@ -147,7 +165,7 @@ const generateTableData = (processes: ProcessInfo[], selectedIndex: number) => { // Memoized header component const MemoizedHeader = React.memo( - ({ children, sortBy }: { children: React.ReactNode; sortBy: "cpu" | "pid" | "files" }) => { + ({ children, sortBy }: MemoizedHeaderProps) => { const headerText = String(children); let sortIndicator = ""; let color = "blue"; @@ -173,7 +191,7 @@ const MemoizedHeader = React.memo( ); // Memoized cell component -const MemoizedCell = React.memo(({ children, column }: { children: React.ReactNode; column: number }) => { +const MemoizedCell = React.memo(({ children, column }: MemoizedCellProps) => { return ( {children} @@ -182,7 +200,7 @@ const MemoizedCell = React.memo(({ children, column }: { children: React.ReactNo }); // Memoized notifications panel -const MemoizedNotificationsPanel = React.memo(({ notifications }: { notifications: Notification[] }) => { +const MemoizedNotificationsPanel = React.memo(({ notifications }: MemoizedNotificationsPanelProps) => { return ( @@ -204,7 +222,7 @@ const MemoizedNotificationsPanel = React.memo(({ notifications }: { notification }); // Memoized command performance panel -const MemoizedCommandPanel = React.memo(({ commandHistory }: { commandHistory: CommandPerformance[] }) => { +const MemoizedCommandPanel = React.memo(({ commandHistory }: MemoizedCommandPanelProps) => { return ( From d8ac489a70404590cc8c66fdaf59bdfc1fdab58f Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:17:01 +0100 Subject: [PATCH 11/18] refactor(claude-history-dashboard): extract ProviderProps interface --- .../src/integrations/tanstack-query/root-provider.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/claude-history-dashboard/src/integrations/tanstack-query/root-provider.tsx b/src/claude-history-dashboard/src/integrations/tanstack-query/root-provider.tsx index 9ac5e853..63a93c82 100644 --- a/src/claude-history-dashboard/src/integrations/tanstack-query/root-provider.tsx +++ b/src/claude-history-dashboard/src/integrations/tanstack-query/root-provider.tsx @@ -1,5 +1,10 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +interface ProviderProps { + children: React.ReactNode; + queryClient: QueryClient; +} + export function getContext() { const queryClient = new QueryClient(); return { @@ -7,6 +12,6 @@ export function getContext() { }; } -export function Provider({ children, queryClient }: { children: React.ReactNode; queryClient: QueryClient }) { +export function Provider({ children, queryClient }: ProviderProps) { return {children}; } From 68f64f777802eda0c2aa6b7420869167f386859d Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:17:35 +0100 Subject: [PATCH 12/18] refactor(markdown-cli): extract MarkdownCLIOptions interface --- src/markdown-cli/index.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/markdown-cli/index.ts b/src/markdown-cli/index.ts index c2f0b86b..1120aa18 100644 --- a/src/markdown-cli/index.ts +++ b/src/markdown-cli/index.ts @@ -5,6 +5,13 @@ import { type MarkdownRenderOptions, renderMarkdownToCli } from "@app/utils/mark import chokidar from "chokidar"; import { Command, Option } from "commander"; +interface MarkdownCLIOptions { + watch?: boolean; + width?: number; + theme?: string; + color?: boolean; +} + const program = new Command(); program @@ -19,7 +26,7 @@ program .default("dark") ) .option("--no-color", "Strip ANSI color codes from output") - .action((file?: string, opts?: { watch?: boolean; width?: number; theme?: string; color?: boolean }) => { + .action((file?: string, opts?: MarkdownCLIOptions) => { const renderOpts: MarkdownRenderOptions = { width: opts?.width && !Number.isNaN(opts.width) ? opts.width : undefined, theme: (opts?.theme as MarkdownRenderOptions["theme"]) || "dark", From b525013187ad78c3bc343cd386357e45a95d8981 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:18:43 +0100 Subject: [PATCH 13/18] refactor(azure-devops): extract timelog prepare-import option interfaces --- .../commands/timelog/prepare-import.ts | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/azure-devops/commands/timelog/prepare-import.ts b/src/azure-devops/commands/timelog/prepare-import.ts index a5cf8d90..3b17988b 100644 --- a/src/azure-devops/commands/timelog/prepare-import.ts +++ b/src/azure-devops/commands/timelog/prepare-import.ts @@ -42,6 +42,27 @@ interface PrepareImportFile { entries: StoredEntry[]; } +interface TimelogAddOptions { + from?: string; + to?: string; + name?: string; + entry: string; +} + +interface TimelogRemoveOptions { + name: string; + id: string; +} + +interface TimelogListOptions { + name: string; + format?: string; +} + +interface TimelogClearOptions { + name: string; +} + // ============= Helpers ============= const storage = new Storage("azure-devops"); @@ -83,7 +104,7 @@ function printEntry(entry: StoredEntry): void { // ============= Subcommand Actions ============= -async function handleAdd(options: { from?: string; to?: string; name?: string; entry: string }): Promise { +async function handleAdd(options: TimelogAddOptions): Promise { const fileName = resolveFileName(options); // Parse and validate entry JSON @@ -187,7 +208,7 @@ async function handleAdd(options: { from?: string; to?: string; name?: string; e printEntry(storedEntry); } -async function handleRemove(options: { name: string; id: string }): Promise { +async function handleRemove(options: TimelogRemoveOptions): Promise { const key = cacheKey(options.name); const updated = await storage.atomicUpdate(key, (current) => { @@ -207,7 +228,7 @@ async function handleRemove(options: { name: string; id: string }): Promise { +async function handleList(options: TimelogListOptions): Promise { const key = cacheKey(options.name); const data = await storage.getCacheFile(key, "30 days"); @@ -276,7 +297,7 @@ async function handleList(options: { name: string; format?: string }): Promise { +async function handleClear(options: TimelogClearOptions): Promise { const key = cacheKey(options.name); await storage.deleteCacheFile(key); console.log(`Prepare-import file "${options.name}" cleared.`); From 24513b117591b26a58288ab67642da0680d9f5fd Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:20:10 +0100 Subject: [PATCH 14/18] refactor(automate): extract StepHandlerResult to shared types --- src/automate/lib/builtins.ts | 14 +++++++------- src/automate/lib/step-runner.ts | 4 ++-- src/automate/lib/types.ts | 6 ++++++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/automate/lib/builtins.ts b/src/automate/lib/builtins.ts index 99816197..678a9a60 100644 --- a/src/automate/lib/builtins.ts +++ b/src/automate/lib/builtins.ts @@ -3,7 +3,7 @@ import { SafeJSON } from "@app/utils/json"; import * as p from "@clack/prompts"; import { resolveExpression, resolveParams } from "./expressions.ts"; -import type { ExecutionContext, PresetStep, StepResult } from "./types.ts"; +import type { ExecutionContext, PresetStep, StepHandlerResult, StepResult } from "./types.ts"; /** The set of built-in action names that are handled directly (not via Bun.spawn) */ export const BUILTIN_ACTIONS = new Set(["if", "log", "prompt", "shell", "set"]); @@ -20,7 +20,7 @@ export function isBuiltinAction(action: string): boolean { export async function executeBuiltin( step: PresetStep, ctx: ExecutionContext -): Promise<{ result: StepResult; jumpTo?: string }> { +): Promise { const start = Date.now(); switch (step.action) { @@ -40,7 +40,7 @@ export async function executeBuiltin( } /** if -- evaluate condition expression, return jumpTo target step ID */ -function handleIf(step: PresetStep, ctx: ExecutionContext, start: number): { result: StepResult; jumpTo?: string } { +function handleIf(step: PresetStep, ctx: ExecutionContext, start: number): StepHandlerResult { if (!step.condition) { throw new Error(`Step "${step.id}": "if" action requires a "condition" field`); } @@ -60,7 +60,7 @@ function handleIf(step: PresetStep, ctx: ExecutionContext, start: number): { res } /** log -- print a resolved message to console via @clack/prompts */ -function handleLog(step: PresetStep, ctx: ExecutionContext, start: number): { result: StepResult } { +function handleLog(step: PresetStep, ctx: ExecutionContext, start: number): StepHandlerResult { const params = step.params ? resolveParams(step.params as Record, ctx) : {}; const message = String(params.message ?? ""); @@ -76,7 +76,7 @@ function handleLog(step: PresetStep, ctx: ExecutionContext, start: number): { re } /** prompt -- ask user a question interactively, store answer as output */ -async function handlePrompt(step: PresetStep, ctx: ExecutionContext, start: number): Promise<{ result: StepResult }> { +async function handlePrompt(step: PresetStep, ctx: ExecutionContext, start: number): Promise { const params = step.params ? resolveParams(step.params as Record, ctx) : {}; const message = String(params.message ?? "Enter value:"); const defaultValue = params.default != null ? String(params.default) : undefined; @@ -108,7 +108,7 @@ async function handlePrompt(step: PresetStep, ctx: ExecutionContext, start: numb } /** shell -- run a raw shell command via bash, capture stdout/stderr */ -async function handleShell(step: PresetStep, ctx: ExecutionContext, start: number): Promise<{ result: StepResult }> { +async function handleShell(step: PresetStep, ctx: ExecutionContext, start: number): Promise { const params = step.params ? resolveParams(step.params as Record, ctx) : {}; const command = String(params.command ?? params.cmd ?? ""); @@ -162,7 +162,7 @@ async function handleShell(step: PresetStep, ctx: ExecutionContext, start: numbe } /** set -- set key-value pairs into ctx.vars */ -function handleSet(step: PresetStep, ctx: ExecutionContext, start: number): { result: StepResult } { +function handleSet(step: PresetStep, ctx: ExecutionContext, start: number): StepHandlerResult { const params = step.params ? resolveParams(step.params as Record, ctx) : {}; for (const [key, value] of Object.entries(params)) { diff --git a/src/automate/lib/step-runner.ts b/src/automate/lib/step-runner.ts index 5ea76103..69e6fec9 100644 --- a/src/automate/lib/step-runner.ts +++ b/src/automate/lib/step-runner.ts @@ -5,7 +5,7 @@ import { executeBuiltin, isBuiltinAction } from "./builtins.ts"; import { resolveExpression, resolveParams } from "./expressions.ts"; import type { StepContext } from "./registry.ts"; import { resolveStepHandler } from "./registry.ts"; -import type { ExecutionContext, PresetStep, StepResult } from "./types.ts"; +import type { ExecutionContext, PresetStep, StepHandlerResult, StepResult } from "./types.ts"; /** * Execute a single step. @@ -18,7 +18,7 @@ export async function executeStep( step: PresetStep, ctx: ExecutionContext, options: { dryRun?: boolean; verbose?: boolean } -): Promise<{ result: StepResult; jumpTo?: string }> { +): Promise { // Dispatch built-in actions if (isBuiltinAction(step.action)) { if (options.dryRun) { diff --git a/src/automate/lib/types.ts b/src/automate/lib/types.ts index e36cb4b4..b66fb555 100644 --- a/src/automate/lib/types.ts +++ b/src/automate/lib/types.ts @@ -75,6 +75,12 @@ export interface StepResult { error?: string; } +/** Result from a step handler, with optional jump target for branching */ +export interface StepHandlerResult { + result: StepResult; + jumpTo?: string; +} + /** Run options from CLI flags */ export interface RunOptions { dryRun?: boolean; From ceb1418979873fb7949069a5c1161c66349f31a8 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:20:36 +0100 Subject: [PATCH 15/18] refactor(utils): extract ParsedTableTokens interface --- src/utils/markdown/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/markdown/index.ts b/src/utils/markdown/index.ts index be754cd9..6253bbfe 100644 --- a/src/utils/markdown/index.ts +++ b/src/utils/markdown/index.ts @@ -149,7 +149,12 @@ interface TableData { rows: string[][]; } -function parseTableTokens(tokens: Token[], startIdx: number): { data: TableData; endIdx: number } { +interface ParsedTableTokens { + data: TableData; + endIdx: number; +} + +function parseTableTokens(tokens: Token[], startIdx: number): ParsedTableTokens { const data: TableData = { headers: [], alignments: [], rows: [] }; let idx = startIdx; From 750687b0f2943626da78f007f4ef37ec93abd4c7 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:21:04 +0100 Subject: [PATCH 16/18] refactor(mcp-web-reader): extract TokenLimitResult interface --- src/mcp-web-reader/utils/tokens.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mcp-web-reader/utils/tokens.ts b/src/mcp-web-reader/utils/tokens.ts index c9ac96b8..09fb8692 100644 --- a/src/mcp-web-reader/utils/tokens.ts +++ b/src/mcp-web-reader/utils/tokens.ts @@ -1,5 +1,11 @@ import { decode, encode } from "gpt-3-encoder"; +interface TokenLimitResult { + text: string; + tokens: number; + truncated: boolean; +} + export function countTokens(text: string): number { try { return encode(text).length; @@ -9,7 +15,7 @@ export function countTokens(text: string): number { } } -export function limitToTokens(text: string, maxTokens?: number): { text: string; tokens: number; truncated: boolean } { +export function limitToTokens(text: string, maxTokens?: number): TokenLimitResult { const tokens = countTokens(text); if (!maxTokens || tokens <= maxTokens) { From 54b8433729f20705979d3d31d697917da31718c7 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 02:21:33 +0100 Subject: [PATCH 17/18] refactor(internal): extract FileTransportOptions interface --- src/Internal/LoggerLib/Logger.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Internal/LoggerLib/Logger.ts b/src/Internal/LoggerLib/Logger.ts index 75769486..c191d531 100644 --- a/src/Internal/LoggerLib/Logger.ts +++ b/src/Internal/LoggerLib/Logger.ts @@ -707,7 +707,13 @@ export const consoleTransport: ITransport = { }, }; -export const fileTransport = (options: { filePath: string; append?: boolean; encoding?: string }): ITransport => ({ +interface FileTransportOptions { + filePath: string; + append?: boolean; + encoding?: string; +} + +export const fileTransport = (options: FileTransportOptions): ITransport => ({ log(props) { // Here you would implement file writing logic // Using appropriate React Native or Node.js APIs From 333f2ebc7e938ba1b390e95737b821c61e06ec7d Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Mar 2026 16:03:22 +0100 Subject: [PATCH 18/18] chore: remove completed inline type extraction plan --- .../plans/2026-03-18-InlineTypeExtraction.md | 346 ------------------ 1 file changed, 346 deletions(-) delete mode 100644 .claude/plans/2026-03-18-InlineTypeExtraction.md diff --git a/.claude/plans/2026-03-18-InlineTypeExtraction.md b/.claude/plans/2026-03-18-InlineTypeExtraction.md deleted file mode 100644 index 00c1116d..00000000 --- a/.claude/plans/2026-03-18-InlineTypeExtraction.md +++ /dev/null @@ -1,346 +0,0 @@ -# Inline Type Extraction Plan - -Extract 28 inline type annotations into named interfaces across 13 files. -Branch: `fix/inline-types` (from master, `--no-track`) - -## Principles - -- **Type placement**: module-internal types at top of same file; shared types in existing `types.ts` files -- **One commit per file** (or per logical group of related files) -- **Verify after each change**: `tsgo --noEmit` scoped to the changed file(s) -- **No functional changes** -- pure type extractions only - ---- - -## Task 1: `src/ask/utils/cli.ts` (3 extractions) - -- [ ] Read file, verify findings at lines 160, 245, 265 -- [ ] Add at top of file (after imports): - ```ts - interface ValidationResult { - valid: boolean; - errors: string[]; - } - - interface OutputFormatResult { - type: OutputFormat; - filename?: string; - } - ``` -- [ ] Replace `validateOptions` return type (line 160): `{ valid: boolean; errors: string[] }` -> `ValidationResult` -- [ ] Replace `parseOutputFormat` return type (line 245): `{ type: OutputFormat; filename?: string } | undefined` -> `OutputFormatResult | undefined` -- [ ] Replace `getOutputFormat` return type (line 265): same -> `OutputFormatResult | undefined` -- [ ] Run: `tsgo --noEmit | rg "src/ask/utils/cli"` -- [ ] Commit: `refactor(ask): extract ValidationResult and OutputFormatResult interfaces` - -## Task 2: `src/ask/AIChat.ts` (1 extraction) - -- [ ] Read file, verify finding at line 244 -- [ ] Add at top of file (after imports): - ```ts - interface EngineWithRestore { - engine: ChatEngine; - restore: () => void; - } - ``` -- [ ] Replace `_getEngine` return type (line 244): `{ engine: ChatEngine; restore: () => void }` -> `EngineWithRestore` -- [ ] Run: `tsgo --noEmit | rg "src/ask/AIChat"` -- [ ] Commit: `refactor(ask): extract EngineWithRestore interface` - -## Task 3: `src/ask/utils/websearch.ts` (1 extraction) - -- [ ] Read file, verify finding at line 178 -- [ ] Add at top of file (after imports): - ```ts - interface WebSearchParams { - query: string; - numResults?: number; - safeSearch?: string; - } - ``` -- [ ] Replace inline callback parameter type (line 178): `(params: { query: string; numResults?: number; safeSearch?: string })` -> `(params: WebSearchParams)` -- [ ] Run: `tsgo --noEmit | rg "src/ask/utils/websearch"` -- [ ] Commit: `refactor(ask): extract WebSearchParams interface` - -## Task 4: `src/ask/providers/ProviderManager.ts` (1 extraction) - -- [ ] Read file, verify finding at line 375 -- [ ] Add at top of file (after imports): - ```ts - interface ModelMetadata { - id: string; - description?: string; - } - ``` -- [ ] Replace `parseCapabilities` parameter type (line 375): `(model: { id: string; description?: string })` -> `(model: ModelMetadata)` -- [ ] Run: `tsgo --noEmit | rg "src/ask/providers/ProviderManager"` -- [ ] Commit: `refactor(ask): extract ModelMetadata interface` - -## Task 5: `src/mcp-manager/utils/command.utils.ts` (2 extractions) - -- [ ] Read file, verify findings at lines 104 and 121 -- [ ] Add at top of file (after imports): - ```ts - interface ParsedCommand { - command: string; - args: string[]; - } - - interface KeyValuePair { - key: string; - value: string; - } - ``` -- [ ] Replace `parseCommandString` return type (line 104): `{ command: string; args: string[] }` -> `ParsedCommand` -- [ ] Replace `parseSinglePair` return type (line 121): `{ key: string; value: string } | null` -> `KeyValuePair | null` -- [ ] Run: `tsgo --noEmit | rg "src/mcp-manager/utils/command.utils"` -- [ ] Commit: `refactor(mcp-manager): extract ParsedCommand and KeyValuePair interfaces` - -## Task 6: `src/mcp-tsc/LspWorker.ts` (2 extractions) - -- [ ] Read file, verify findings at lines 278 and 900 -- [ ] Add at top of file (after imports): - ```ts - interface LspDiagnosticsNotification { - uri: string; - diagnostics: LspDiagnostic[]; - } - - interface QueueStats { - length: number; - isProcessing: boolean; - } - ``` -- [ ] Replace diagnostics callback parameter type (line 278): `(params: { uri: string; diagnostics: LspDiagnostic[] })` -> `(params: LspDiagnosticsNotification)` -- [ ] Replace `getQueueStats` return type (line 900): `{ length: number; isProcessing: boolean }` -> `QueueStats` -- [ ] Run: `tsgo --noEmit | rg "src/mcp-tsc/LspWorker"` -- [ ] Commit: `refactor(mcp-tsc): extract LspDiagnosticsNotification and QueueStats interfaces` - -## Task 7: `src/github-release-notes/index.ts` (1 extraction) - -- [ ] Read file, verify finding at line 127 -- [ ] Add at top of file (after imports): - ```ts - interface RepoIdentity { - owner: string; - repo: string; - } - ``` -- [ ] Replace `parseRepoArg` return type (line 127): `{ owner: string; repo: string } | null` -> `RepoIdentity | null` -- [ ] Run: `tsgo --noEmit | rg "src/github-release-notes/index"` -- [ ] Commit: `refactor(github-release-notes): extract RepoIdentity interface` - -## Task 8: `src/telegram/lib/TGClient.ts` (1 extraction) - -- [ ] Read file, verify finding at line 95 -- [ ] Add at top of file (after imports): - ```ts - interface StopHandle { - stop: () => void; - } - ``` -- [ ] Replace `startTypingLoop` return type (line 95): `{ stop: () => void }` -> `StopHandle` -- [ ] Run: `tsgo --noEmit | rg "src/telegram/lib/TGClient"` -- [ ] Commit: `refactor(telegram): extract StopHandle interface` - -## Task 9: `src/macos-resources/index.tsx` (4 extractions) - -- [ ] Read file, verify findings at lines 150, 176, 185, 207 -- [ ] Add at top of file (after imports). Note: these are React component prop types, so use explicit prop interfaces: - ```ts - interface MemoizedHeaderProps { - children: React.ReactNode; - sortBy: "cpu" | "pid" | "files"; - } - - interface MemoizedCellProps { - children: React.ReactNode; - column: number; - } - - interface MemoizedNotificationsPanelProps { - notifications: Notification[]; - } - - interface MemoizedCommandPanelProps { - commandHistory: CommandPerformance[]; - } - ``` -- [ ] Replace `MemoizedHeader` inline props (line 150): `({ children, sortBy }: { children: React.ReactNode; sortBy: "cpu" | "pid" | "files" })` -> `({ children, sortBy }: MemoizedHeaderProps)` -- [ ] Replace `MemoizedCell` inline props (line 176): `({ children, column }: { children: React.ReactNode; column: number })` -> `({ children, column }: MemoizedCellProps)` -- [ ] Replace `MemoizedNotificationsPanel` inline props (line 185): `({ notifications }: { notifications: Notification[] })` -> `({ notifications }: MemoizedNotificationsPanelProps)` -- [ ] Replace `MemoizedCommandPanel` inline props (line 207): `({ commandHistory }: { commandHistory: CommandPerformance[] })` -> `({ commandHistory }: MemoizedCommandPanelProps)` -- [ ] Run: `tsgo --noEmit | rg "src/macos-resources/index"` -- [ ] Commit: `refactor(macos-resources): extract React component prop interfaces` - -## Task 10: `src/claude-history-dashboard/src/integrations/tanstack-query/root-provider.tsx` (1 extraction) - -- [ ] Read file, verify finding at line 10 -- [ ] Add at top of file (after imports): - ```ts - interface ProviderProps { - children: React.ReactNode; - queryClient: QueryClient; - } - ``` -- [ ] Replace `Provider` inline props (line 10): `({ children, queryClient }: { children: React.ReactNode; queryClient: QueryClient })` -> `({ children, queryClient }: ProviderProps)` -- [ ] Run: `tsgo --noEmit | rg "root-provider"` -- [ ] Commit: `refactor(claude-history-dashboard): extract ProviderProps interface` - -## Task 11: `src/markdown-cli/index.ts` (1 extraction) - -- [ ] Read file, verify finding at line 22 -- [ ] Add at top of file (after imports): - ```ts - interface MarkdownCLIOptions { - watch?: boolean; - width?: number; - theme?: string; - color?: boolean; - } - ``` -- [ ] Replace `.action()` inline options type (line 22): `(file?: string, opts?: { watch?: boolean; width?: number; theme?: string; color?: boolean })` -> `(file?: string, opts?: MarkdownCLIOptions)` -- [ ] Run: `tsgo --noEmit | rg "src/markdown-cli/index"` -- [ ] Commit: `refactor(markdown-cli): extract MarkdownCLIOptions interface` - -## Task 12: `src/azure-devops/commands/timelog/prepare-import.ts` (4 extractions) - -- [ ] Read file, verify findings at lines 86, 190, 210, 279 -- [ ] Add at top of file (after imports): - ```ts - interface TimelogAddOptions { - from?: string; - to?: string; - name?: string; - entry: string; - } - - interface TimelogRemoveOptions { - name: string; - id: string; - } - - interface TimelogListOptions { - name: string; - format?: string; - } - - interface TimelogClearOptions { - name: string; - } - ``` -- [ ] Replace `handleAdd` parameter type (line 86): `(options: { from?: string; to?: string; name?: string; entry: string })` -> `(options: TimelogAddOptions)` -- [ ] Replace `handleRemove` parameter type (line 190): `(options: { name: string; id: string })` -> `(options: TimelogRemoveOptions)` -- [ ] Replace `handleList` parameter type (line 210): `(options: { name: string; format?: string })` -> `(options: TimelogListOptions)` -- [ ] Replace `handleClear` parameter type (line 279): `(options: { name: string })` -> `(options: TimelogClearOptions)` -- [ ] Run: `tsgo --noEmit | rg "src/azure-devops/commands/timelog/prepare-import"` -- [ ] Commit: `refactor(azure-devops): extract timelog prepare-import option interfaces` - -## Task 13: `src/automate/lib/builtins.ts` (3 extractions) - -The `{ result: StepResult; jumpTo?: string }` pattern is used by `executeBuiltin` (line 23), `handleIf` (line 43), `handlePrompt` (line 79), `handleShell` (line 111), `step-runner.ts:executeStep` (line 21). The `{ result: StepResult }` subset is used by `handleLog` (line 63), `handleSet` (line 165). - -- [ ] Read `src/automate/lib/types.ts`, add to it: - ```ts - /** Result from a step handler, with optional jump target for branching */ - interface StepHandlerResult { - result: StepResult; - jumpTo?: string; - } - ``` - Note: `{ result: StepResult }` is a subset of `StepHandlerResult` (jumpTo is already optional), so all three handler return types can use `StepHandlerResult`. -- [ ] In `src/automate/lib/builtins.ts`: - - Update import to include `StepHandlerResult` - - Replace `executeBuiltin` return type (line 23): `Promise<{ result: StepResult; jumpTo?: string }>` -> `Promise` - - Replace `handleIf` return type (line 43): `{ result: StepResult; jumpTo?: string }` -> `StepHandlerResult` - - Replace `handleLog` return type (line 63): `{ result: StepResult }` -> `StepHandlerResult` - - Replace `handlePrompt` return type (line 79): `Promise<{ result: StepResult }>` -> `Promise` - - Replace `handleShell` return type (line 111): `Promise<{ result: StepResult }>` -> `Promise` - - Replace `handleSet` return type (line 165): `{ result: StepResult }` -> `StepHandlerResult` -- [ ] In `src/automate/lib/step-runner.ts`: - - Update import to include `StepHandlerResult` - - Replace `executeStep` return type (line 21): `Promise<{ result: StepResult; jumpTo?: string }>` -> `Promise` -- [ ] In `src/automate/lib/engine.ts`: - - Update import to include `StepHandlerResult` (check if it uses the same pattern) - - Replace any matching inline types -- [ ] Run: `tsgo --noEmit | rg "src/automate/lib/"` -- [ ] Commit: `refactor(automate): extract StepHandlerResult to shared types` - -## Task 14: `src/utils/markdown/index.ts` (1 extraction) - -- [ ] Read file, verify finding at line 152 -- [ ] Add at top of file (after imports): - ```ts - interface ParsedTableTokens { - data: TableData; - endIdx: number; - } - ``` -- [ ] Replace `parseTableTokens` return type (line 152): `{ data: TableData; endIdx: number }` -> `ParsedTableTokens` -- [ ] Run: `tsgo --noEmit | rg "src/utils/markdown/index"` -- [ ] Commit: `refactor(utils): extract ParsedTableTokens interface` - -## Task 15: `src/mcp-web-reader/utils/tokens.ts` (1 extraction) - -- [ ] Read file, verify finding at line 12 -- [ ] Add at top of file (after imports): - ```ts - interface TokenLimitResult { - text: string; - tokens: number; - truncated: boolean; - } - ``` -- [ ] Replace `limitToTokens` return type (line 12): `{ text: string; tokens: number; truncated: boolean }` -> `TokenLimitResult` -- [ ] Run: `tsgo --noEmit | rg "src/mcp-web-reader/utils/tokens"` -- [ ] Commit: `refactor(mcp-web-reader): extract TokenLimitResult interface` - -## Task 16: `src/Internal/LoggerLib/Logger.ts` (1 extraction) - -- [ ] Read file, verify finding at line 710 -- [ ] Add at top of file (after imports) or near the `fileTransport` function: - ```ts - interface FileTransportOptions { - filePath: string; - append?: boolean; - encoding?: string; - } - ``` -- [ ] Replace `fileTransport` parameter type (line 710): `(options: { filePath: string; append?: boolean; encoding?: string })` -> `(options: FileTransportOptions)` -- [ ] Run: `tsgo --noEmit | rg "src/Internal/LoggerLib/Logger"` -- [ ] Commit: `refactor(internal): extract FileTransportOptions interface` - ---- - -## Task 17: Final validation and PR - -- [ ] Run full type check: `tsgo --noEmit` (no filter -- whole project) -- [ ] Verify all 28 extractions are done: `git log --oneline fix/inline-types ^master` -- [ ] Push: `git push -u origin fix/inline-types` -- [ ] Create PR to `master`: - - Title: `refactor: extract 28 inline type annotations into named interfaces` - - Body: summary of changes by category, link to this plan - ---- - -## File-to-Task Index - -| File | Task | Extractions | -|------|------|-------------| -| `src/ask/utils/cli.ts` | 1 | 3 | -| `src/ask/AIChat.ts` | 2 | 1 | -| `src/ask/utils/websearch.ts` | 3 | 1 | -| `src/ask/providers/ProviderManager.ts` | 4 | 1 | -| `src/mcp-manager/utils/command.utils.ts` | 5 | 2 | -| `src/mcp-tsc/LspWorker.ts` | 6 | 2 | -| `src/github-release-notes/index.ts` | 7 | 1 | -| `src/telegram/lib/TGClient.ts` | 8 | 1 | -| `src/macos-resources/index.tsx` | 9 | 4 | -| `src/claude-history-dashboard/.../root-provider.tsx` | 10 | 1 | -| `src/markdown-cli/index.ts` | 11 | 1 | -| `src/azure-devops/commands/timelog/prepare-import.ts` | 12 | 4 | -| `src/automate/lib/builtins.ts` + `types.ts` + `step-runner.ts` + `engine.ts` | 13 | 3 | -| `src/utils/markdown/index.ts` | 14 | 1 | -| `src/mcp-web-reader/utils/tokens.ts` | 15 | 1 | -| `src/Internal/LoggerLib/Logger.ts` | 16 | 1 | -| **Total** | | **28** |