diff --git a/src/auth/auth-commands.ts b/src/auth/auth-commands.ts index 374c0d6c..1b671e27 100644 --- a/src/auth/auth-commands.ts +++ b/src/auth/auth-commands.ts @@ -352,7 +352,7 @@ class AuthCommands { const files = fs.readdirSync(sessionsDir); sessionCount = files.filter((f) => f.endsWith('.json')).length; } - } catch (e) { + } catch (_e) { // Ignore errors counting sessions } @@ -421,7 +421,7 @@ class AuthCommands { const files = fs.readdirSync(sessionsDir); sessionCount = files.filter((f) => f.endsWith('.json')).length; } - } catch (e) { + } catch (_e) { // Ignore errors counting sessions } diff --git a/src/auth/profile-detector.ts b/src/auth/profile-detector.ts index ea3c2381..3108feba 100644 --- a/src/auth/profile-detector.ts +++ b/src/auth/profile-detector.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import { findSimilarStrings } from '../utils/helpers'; -import { Config } from '../types'; +import { Config, Settings, ProfileMetadata } from '../types'; export type ProfileType = 'settings' | 'account' | 'default'; @@ -17,7 +17,7 @@ export interface ProfileDetectionResult { type: ProfileType; name: string; settingsPath?: string; - profile?: any; + profile?: Settings | ProfileMetadata; message?: string; } @@ -65,7 +65,7 @@ class ProfileDetector { /** * Read account-based profiles (profiles.json) */ - private readProfiles(): { profiles: Record; default?: string } { + private readProfiles(): { profiles: Record; default?: string } { if (!fs.existsSync(this.profilesPath)) { return { profiles: {}, default: undefined }; } diff --git a/src/delegation/headless-executor.ts b/src/delegation/headless-executor.ts index 6625a557..0d76c578 100644 --- a/src/delegation/headless-executor.ts +++ b/src/delegation/headless-executor.ts @@ -7,6 +7,35 @@ import * as fs from 'fs'; import { SessionManager } from './session-manager'; import { SettingsParser } from './settings-parser'; +// Type definitions for delegation responses +interface ClaudeMessage { + type: string; + content?: string; + thinking?: string; + tool_use?: { + id: string; + name: string; + input: Record; + }; + tool_result?: { + tool_use_id: string; + content: string; + }; +} + +interface PermissionDenial { + tool_name: string; + reason: string; +} + +interface ExecutionError { + message?: string; + error?: string; + type?: string; + tool_name?: string; + [key: string]: unknown; +} + interface ExecutionOptions { cwd?: string; timeout?: number; @@ -26,7 +55,7 @@ interface ExecutionResult { duration: number; timedOut: boolean; success: boolean; - messages: any[]; + messages: ClaudeMessage[]; sessionId?: string; totalCost?: number; numTurns?: number; @@ -34,8 +63,8 @@ interface ExecutionResult { type?: string | null; subtype?: string; durationApi?: number; - permissionDenials?: any[]; - errors?: any[]; + permissionDenials?: PermissionDenial[]; + errors?: ExecutionError[]; content?: string; } @@ -45,7 +74,7 @@ interface StreamMessage { content?: Array<{ type: string; name?: string; - input?: any; + input?: Record; }>; }; session_id?: string; @@ -54,8 +83,8 @@ interface StreamMessage { is_error?: boolean; result?: string; duration_api_ms?: number; - permission_denials?: any[]; - errors?: any[]; + permission_denials?: PermissionDenial[]; + errors?: ExecutionError[]; subtype?: string; } @@ -282,10 +311,8 @@ export class HeadlessExecutor { case 'Bash': if (toolInput.command) { // Truncate long commands - const cmd = - toolInput.command.length > 80 - ? toolInput.command.substring(0, 77) + '...' - : toolInput.command; + const command = toolInput.command as string; + const cmd = command.length > 80 ? command.substring(0, 77) + '...' : command; verboseMsg += `: ${cmd}`; } break; @@ -330,10 +357,9 @@ export class HeadlessExecutor { if (toolInput.description) { verboseMsg += `: ${toolInput.description}`; } else if (toolInput.prompt) { + const promptText = toolInput.prompt as string; const prompt = - toolInput.prompt.length > 60 - ? toolInput.prompt.substring(0, 57) + '...' - : toolInput.prompt; + promptText.length > 60 ? promptText.substring(0, 57) + '...' : promptText; verboseMsg += `: ${prompt}`; } break; @@ -342,7 +368,7 @@ export class HeadlessExecutor { if (toolInput.todos && Array.isArray(toolInput.todos)) { // Show in_progress task instead of just count const inProgressTask = toolInput.todos.find( - (t: any) => t.status === 'in_progress' + (t: { status: string; activeForm?: string }) => t.status === 'in_progress' ); if (inProgressTask && inProgressTask.activeForm) { verboseMsg += `: ${inProgressTask.activeForm}`; @@ -564,7 +590,7 @@ export class HeadlessExecutor { try { const result = execSync('command -v claude', { encoding: 'utf8' }); return result.trim(); - } catch (error) { + } catch (_error) { return null; } } @@ -683,7 +709,7 @@ export class HeadlessExecutor { timeout: 10000, }); return result.success; - } catch (error) { + } catch (_error) { return false; } } diff --git a/src/delegation/result-formatter.ts b/src/delegation/result-formatter.ts index 1e476bf0..b0c9b6c1 100644 --- a/src/delegation/result-formatter.ts +++ b/src/delegation/result-formatter.ts @@ -33,14 +33,14 @@ interface PermissionDenial { tool_input?: { command?: string; description?: string; - [key: string]: any; + [key: string]: unknown; }; } interface ErrorInfo { message?: string; error?: string; - [key: string]: any; + [key: string]: unknown; } interface FileChanges { @@ -223,7 +223,7 @@ class ResultFormatter { modified.push(fullPath); } } - } catch (statError) { + } catch (_statError) { // If stat fails, default to created (since we're in fallback mode) if (!created.includes(fullPath) && !modified.includes(fullPath)) { created.push(fullPath); diff --git a/src/glmt/delta-accumulator.ts b/src/glmt/delta-accumulator.ts index 399ba80d..4988c9e8 100644 --- a/src/glmt/delta-accumulator.ts +++ b/src/glmt/delta-accumulator.ts @@ -15,7 +15,7 @@ */ interface ThinkingConfig { - [key: string]: any; + [key: string]: unknown; } interface DeltaAccumulatorOptions { diff --git a/src/glmt/glmt-proxy.ts b/src/glmt/glmt-proxy.ts index c47fbdc9..b9083b57 100644 --- a/src/glmt/glmt-proxy.ts +++ b/src/glmt/glmt-proxy.ts @@ -106,7 +106,7 @@ export class GlmtProxy { // Bind to 127.0.0.1:0 (random port for security + avoid conflicts) this.server.listen(0, '127.0.0.1', () => { - const address = this.server!.address(); + const address = this.server?.address(); this.port = typeof address === 'object' && address ? address.port : 0; // Signal parent process console.log(`PROXY_READY:${this.port}`); @@ -446,7 +446,9 @@ export class GlmtProxy { } const parser = new SSEParser(); - const accumulator = new DeltaAccumulator(thinkingConfig); + const accumulator = new DeltaAccumulator( + thinkingConfig as unknown as Record + ); upstreamRes.on('data', (chunk: Buffer) => { try { @@ -454,7 +456,8 @@ export class GlmtProxy { events.forEach((event) => { // Transform OpenAI delta → Anthropic events - const anthropicEvents = this.transformer.transformDelta(event, accumulator); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const anthropicEvents = this.transformer.transformDelta(event as any, accumulator); // Forward to Claude CLI with immediate flush anthropicEvents.forEach((evt) => { diff --git a/src/glmt/glmt-transformer.ts b/src/glmt/glmt-transformer.ts index 70ff1825..dd038f6f 100644 --- a/src/glmt/glmt-transformer.ts +++ b/src/glmt/glmt-transformer.ts @@ -796,9 +796,10 @@ export class GlmtTransformer { } accumulator.addDelta(delta.reasoning_content); - events.push( - this.createThinkingDeltaEvent(accumulator.getCurrentBlock()!, delta.reasoning_content) - ); + const currentThinkingBlock = accumulator.getCurrentBlock(); + if (currentThinkingBlock) { + events.push(this.createThinkingDeltaEvent(currentThinkingBlock, delta.reasoning_content)); + } } // Text content delta @@ -822,7 +823,10 @@ export class GlmtTransformer { } accumulator.addDelta(delta.content); - events.push(this.createTextDeltaEvent(accumulator.getCurrentBlock()!, delta.content)); + const currentTextBlock = accumulator.getCurrentBlock(); + if (currentTextBlock) { + events.push(this.createTextDeltaEvent(currentTextBlock, delta.content)); + } } // Check for planning loop diff --git a/src/glmt/sse-parser.ts b/src/glmt/sse-parser.ts index 970fad90..eaeb00dd 100644 --- a/src/glmt/sse-parser.ts +++ b/src/glmt/sse-parser.ts @@ -23,7 +23,7 @@ interface SSEParserOptions { interface SSEEvent { event: string; - data: any; + data: unknown; index?: number; id?: string; retry?: number; diff --git a/src/management/doctor.ts b/src/management/doctor.ts index 1b61feff..952e7b40 100644 --- a/src/management/doctor.ts +++ b/src/management/doctor.ts @@ -26,7 +26,7 @@ let ora: (text: string) => Spinner; try { const oraModule = require('ora'); ora = oraModule.default || oraModule; -} catch (e) { +} catch (_e) { // ora not available, create fallback spinner that uses console.log ora = function (text: string): Spinner { return { @@ -211,7 +211,7 @@ class Doctor { status: 'OK', info: `v${version} (${claudeCli})`, }); - } catch (err) { + } catch (_err) { spinner.fail( ` ${'Claude CLI'.padEnd(26)}${colored('[X]', 'red')} Not found or not working` ); @@ -537,7 +537,7 @@ class Doctor { status: 'OK', info: 'Write access verified', }); - } catch (e) { + } catch (_e) { spinner.fail( ` ${'Permissions'.padEnd(26)}${colored('[X]', 'red')} Cannot write to ~/.ccs/` ); @@ -696,7 +696,7 @@ class Doctor { if (resolved !== sharedSettings) { broken++; } - } catch (err) { + } catch (_err) { broken++; } } diff --git a/src/management/recovery-manager.ts b/src/management/recovery-manager.ts index 58cb8abf..9f5fc2f3 100644 --- a/src/management/recovery-manager.ts +++ b/src/management/recovery-manager.ts @@ -46,7 +46,7 @@ class RecoveryManager { const content = fs.readFileSync(configPath, 'utf8'); JSON.parse(content); // Validate JSON return false; // No recovery needed - } catch (e) { + } catch (_e) { // Corrupted - backup and recreate const backupPath = `${configPath}.backup.${Date.now()}`; fs.renameSync(configPath, backupPath); diff --git a/src/management/shared-manager.ts b/src/management/shared-manager.ts index 0c4dec67..40640fe8 100644 --- a/src/management/shared-manager.ts +++ b/src/management/shared-manager.ts @@ -64,7 +64,7 @@ class SharedManager { console.log(`[!] Circular symlink detected: ${target} → ${resolvedTarget}`); return true; } - } catch (err) { + } catch (_err) { // If can't read, assume not circular return false; } @@ -120,7 +120,7 @@ class SharedManager { continue; // Already correct } } - } catch (err) { + } catch (_err) { // Continue to recreate } @@ -136,7 +136,7 @@ class SharedManager { try { const symlinkType = item.type === 'directory' ? 'dir' : 'file'; fs.symlinkSync(claudePath, sharedPath, symlinkType); - } catch (err) { + } catch (_err) { // Windows fallback: copy if (process.platform === 'win32') { if (item.type === 'directory') { @@ -148,7 +148,7 @@ class SharedManager { `[!] Symlink failed for ${item.name}, copied instead (enable Developer Mode)` ); } else { - throw err; + throw _err; } } } @@ -177,7 +177,7 @@ class SharedManager { try { const symlinkType = item.type === 'directory' ? 'dir' : 'file'; fs.symlinkSync(targetPath, linkPath, symlinkType); - } catch (err) { + } catch (_err) { // Windows fallback if (process.platform === 'win32') { if (item.type === 'directory') { @@ -189,7 +189,7 @@ class SharedManager { `[!] Symlink failed for ${item.name}, copied instead (enable Developer Mode)` ); } else { - throw err; + throw _err; } } } @@ -207,7 +207,7 @@ class SharedManager { if (fs.lstatSync(commandsPath).isSymbolicLink()) { return; // Already migrated } - } catch (err) { + } catch (_err) { // Continue with migration } } @@ -268,8 +268,8 @@ class SharedManager { console.log(`[OK] Migrated ${item.name} to ~/.claude/${item.name}`); } } - } catch (err) { - console.log(`[!] Failed to migrate ${item.name}: ${(err as Error).message}`); + } catch (_err) { + console.log(`[!] Failed to migrate ${item.name}: ${(_err as Error).message}`); } } @@ -287,11 +287,11 @@ class SharedManager { if (fs.statSync(instancePath).isDirectory()) { this.linkSharedDirectories(instancePath); } - } catch (err) { - console.log(`[!] Failed to update instance ${instance}: ${(err as Error).message}`); + } catch (_err) { + console.log(`[!] Failed to update instance ${instance}: ${(_err as Error).message}`); } } - } catch (err) { + } catch (_err) { // No instances to update } } @@ -361,18 +361,18 @@ class SharedManager { try { fs.symlinkSync(sharedSettings, instanceSettings, 'file'); migrated++; - } catch (err) { + } catch (_err) { // Windows fallback if (process.platform === 'win32') { fs.copyFileSync(sharedSettings, instanceSettings); console.log(`[!] Symlink failed for ${instance}, copied instead`); migrated++; } else { - throw err; + throw _err; } } - } catch (err) { - console.log(`[!] Failed to migrate ${instance}: ${(err as Error).message}`); + } catch (_err) { + console.log(`[!] Failed to migrate ${instance}: ${(_err as Error).message}`); } } diff --git a/src/utils/claude-detector.ts b/src/utils/claude-detector.ts index a087b160..02d548c8 100644 --- a/src/utils/claude-detector.ts +++ b/src/utils/claude-detector.ts @@ -55,7 +55,7 @@ export function detectClaudeCli(): string | null { return claudePath; } } - } catch (err) { + } catch (_err) { // Command failed - claude not in PATH // Fall through to return null } diff --git a/src/utils/claude-dir-installer.ts b/src/utils/claude-dir-installer.ts index 0d72ce91..58d2cb54 100644 --- a/src/utils/claude-dir-installer.ts +++ b/src/utils/claude-dir-installer.ts @@ -24,7 +24,6 @@ interface OraInstance { // Make ora optional (might not be available during npm install postinstall) let ora: ((text: string) => OraInstance) | null = null; try { - // eslint-disable-next-line @typescript-eslint/no-require-imports const oraModule = require('ora'); ora = oraModule.default || oraModule; } catch { diff --git a/src/utils/claude-symlink-manager.ts b/src/utils/claude-symlink-manager.ts index 08b9f2ee..4011d007 100644 --- a/src/utils/claude-symlink-manager.ts +++ b/src/utils/claude-symlink-manager.ts @@ -33,7 +33,6 @@ interface OraInstance { // Make ora optional (might not be available during npm install postinstall) let ora: ((text: string) => OraInstance) | null = null; try { - // eslint-disable-next-line @typescript-eslint/no-require-imports const oraModule = require('ora'); ora = oraModule.default || oraModule; } catch { diff --git a/src/utils/delegation-validator.ts b/src/utils/delegation-validator.ts index f6f52cb9..4d882673 100644 --- a/src/utils/delegation-validator.ts +++ b/src/utils/delegation-validator.ts @@ -3,6 +3,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; +import { Settings } from '../types'; interface ValidationResult { valid: boolean; @@ -41,7 +42,7 @@ export class DelegationValidator { } // Read and parse settings.json - let settings: any; + let settings: Settings; try { const settingsContent = fs.readFileSync(settingsPath, 'utf8'); settings = JSON.parse(settingsContent); diff --git a/tests/npm/cli.test.js b/tests/npm/cli.test.js index 47d6f2f1..acb31a57 100644 --- a/tests/npm/cli.test.js +++ b/tests/npm/cli.test.js @@ -41,7 +41,7 @@ describe('npm CLI', () => { this.timeout(5000); try { - runCli('-c', { stdio: 'pipe' }); + runCli('-c', { stdio: 'pipe', timeout: 3000 }); } catch (e) { const output = e.stderr?.toString() || e.stdout?.toString() || ''; // Should NOT show "Profile '-c' not found" error @@ -53,7 +53,7 @@ describe('npm CLI', () => { this.timeout(5000); try { - runCli('--verbose', { stdio: 'pipe' }); + runCli('--verbose', { stdio: 'pipe', timeout: 3000 }); } catch (e) { const output = e.stderr?.toString() || e.stdout?.toString() || ''; assert(!output.includes("Profile '--verbose' not found"), 'Should not treat --verbose as profile'); @@ -75,7 +75,7 @@ describe('npm CLI', () => { this.timeout(5000); try { - runCli('-c --verbose', { stdio: 'pipe' }); + runCli('-c --verbose', { stdio: 'pipe', timeout: 3000 }); } catch (e) { const output = e.stderr?.toString() || e.stdout?.toString() || ''; assert(!output.includes("Profile '-c' not found"), 'Should not treat flags as profiles'); @@ -112,7 +112,7 @@ describe('npm CLI', () => { this.timeout(5000); try { - runCli('glm -c', { stdio: 'pipe' }); + runCli('glm -c', { stdio: 'pipe', timeout: 3000 }); } catch (e) { const output = e.stderr?.toString() || ''; assert(!output.includes("Profile 'glm' not found"), 'GLM profile should exist');