diff --git a/eslint.config.js b/eslint.config.js index b296596e..4d594b25 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -7,7 +7,7 @@ export default tseslint.config( tseslint.configs.recommended, { rules: { - 'no-console': 'warn', + 'no-console': 'off', 'no-debugger': 'error', // Relax some rules that conflict with existing patterns '@typescript-eslint/no-explicit-any': 'warn', diff --git a/src/ralph-tracker.ts b/src/ralph-tracker.ts index 4d1f5b34..14a9ff9d 100644 --- a/src/ralph-tracker.ts +++ b/src/ralph-tracker.ts @@ -1892,7 +1892,7 @@ export class RalphTracker extends EventEmitter { * @fires phraseValidationWarning - When a risky phrase is detected */ private validateCompletionPhrase(phrase: string): void { - const normalized = phrase.toUpperCase().replace(/[\s_\-\.]+/g, ''); + const normalized = phrase.toUpperCase().replace(/[\s_\-.]+/g, ''); // Generate a suggested unique phrase const uniqueSuffix = Date.now().toString(36).slice(-4).toUpperCase(); @@ -3520,7 +3520,7 @@ export class RalphTracker extends EventEmitter { const tasksHeaderPattern = /^##\s*Tasks/i; // Pattern for todo items - const todoPattern = /^-\s*\[([ x\-])\]\s*(.+)$/; + const todoPattern = /^-\s*\[([ x-])\]\s*(.+)$/; let inCompletedSection = false; diff --git a/src/session-lifecycle-log.ts b/src/session-lifecycle-log.ts index ddab9978..cd33ceb3 100644 --- a/src/session-lifecycle-log.ts +++ b/src/session-lifecycle-log.ts @@ -62,7 +62,7 @@ export class SessionLifecycleLog { } const lines = raw.trim().split('\n').filter(Boolean); - let entries: LifecycleEntry[] = []; + const entries: LifecycleEntry[] = []; // Parse in reverse (newest first) for efficiency with limit for (let i = lines.length - 1; i >= 0 && entries.length < limit; i--) { diff --git a/src/session.ts b/src/session.ts index 46905498..13770108 100644 --- a/src/session.ts +++ b/src/session.ts @@ -80,6 +80,7 @@ const GRACEFUL_SHUTDOWN_DELAY_MS = 100; // Filter out terminal focus escape sequences (focus in/out reports) // ^[[I (focus in), ^[[O (focus out), and the enable/disable sequences +// eslint-disable-next-line no-control-regex const FOCUS_ESCAPE_FILTER = /\x1b\[\?1004[hl]|\x1b\[[IO]/g; // Pattern to match Task tool invocations in terminal output @@ -90,8 +91,10 @@ const TASK_TOOL_PATTERN = /\b(Explore|Task|Bash|Plan|general-purpose)\(([^)]+)\) // Pre-compiled patterns for hot paths (avoid regex compilation per call) /** Pattern to strip leading ANSI escapes and whitespace from terminal buffer */ +// eslint-disable-next-line no-control-regex const LEADING_ANSI_WHITESPACE_PATTERN = /^(\x1b\[\??[\d;]*[A-Za-z]|[\s\r\n])+/; /** Pattern to match Ctrl+L (form feed) characters */ +// eslint-disable-next-line no-control-regex const CTRL_L_PATTERN = /\x0c/g; /** Pattern to split by newlines (CR or LF) */ const NEWLINE_SPLIT_PATTERN = /\r?\n/; diff --git a/src/subagent-watcher.ts b/src/subagent-watcher.ts index cf01b8e7..725b8e90 100644 --- a/src/subagent-watcher.ts +++ b/src/subagent-watcher.ts @@ -894,7 +894,7 @@ export class SubagentWatcher extends EventEmitter { const MAX_LEN = SMART_TITLE_MAX_LENGTH; // Get first line/sentence - let title = text.split('\n')[0].trim(); + const title = text.split('\n')[0].trim(); // If already short enough, use it if (title.length <= MAX_LEN) { diff --git a/src/utils/regex-patterns.ts b/src/utils/regex-patterns.ts index c0b7b24b..590043b1 100644 --- a/src/utils/regex-patterns.ts +++ b/src/utils/regex-patterns.ts @@ -17,8 +17,8 @@ * Use this when you need complete ANSI stripping including OSC sequences. * Note: Has global flag - reset lastIndex before exec() if reusing. */ -export const ANSI_ESCAPE_PATTERN_FULL = - /\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[=>])/g; +// eslint-disable-next-line no-control-regex +export const ANSI_ESCAPE_PATTERN_FULL = /\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[=>])/g; /** * Simple ANSI CSI-only pattern for basic escape code stripping. @@ -27,6 +27,7 @@ export const ANSI_ESCAPE_PATTERN_FULL = * Use this for faster stripping when OSC sequences aren't a concern. * Note: Has global flag - reset lastIndex before exec() if reusing. */ +// eslint-disable-next-line no-control-regex export const ANSI_ESCAPE_PATTERN_SIMPLE = /\x1b\[[0-9;]*[A-Za-z]/g; /** @@ -44,6 +45,7 @@ export const TOKEN_PATTERN = /(\d+(?:\.\d+)?)\s*([kKmM])?\s*tokens/; * Use when you need a pattern without shared lastIndex state. */ export function createAnsiPatternFull(): RegExp { + // eslint-disable-next-line no-control-regex return /\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[=>])/g; } @@ -52,6 +54,7 @@ export function createAnsiPatternFull(): RegExp { * Use when you need a pattern without shared lastIndex state. */ export function createAnsiPatternSimple(): RegExp { + // eslint-disable-next-line no-control-regex return /\x1b\[[0-9;]*[A-Za-z]/g; } @@ -75,4 +78,4 @@ export function stripAnsi(text: string): string { */ export const SPINNER_PATTERN = /[⠋⠙⠹⠸⠼⠴⠦⠧]/; -export const SAFE_PATH_PATTERN = /^[a-zA-Z0-9_\/\-. ~]+$/; +export const SAFE_PATH_PATTERN = /^[a-zA-Z0-9_/\-. ~]+$/; diff --git a/src/utils/stale-expiration-map.ts b/src/utils/stale-expiration-map.ts index 1862d120..f5e35925 100644 --- a/src/utils/stale-expiration-map.ts +++ b/src/utils/stale-expiration-map.ts @@ -245,29 +245,23 @@ export class StaleExpirationMap implements Disposable { /** * Get all keys (non-expired). */ - keys(): IterableIterator { - const self = this; - return (function* () { - for (const [key, entry] of self.entries) { - if (!self.isExpired(entry)) { - yield key; - } + *keys(): IterableIterator { + for (const [key, entry] of this.entries) { + if (!this.isExpired(entry)) { + yield key; } - })(); + } } /** * Get all values (non-expired). */ - values(): IterableIterator { - const self = this; - return (function* () { - for (const [, entry] of self.entries) { - if (!self.isExpired(entry)) { - yield entry.value; - } + *values(): IterableIterator { + for (const [, entry] of this.entries) { + if (!this.isExpired(entry)) { + yield entry.value; } - })(); + } } /** diff --git a/src/utils/string-similarity.ts b/src/utils/string-similarity.ts index 4c26b394..27ea785d 100644 --- a/src/utils/string-similarity.ts +++ b/src/utils/string-similarity.ts @@ -139,7 +139,7 @@ export function isSimilarByDistance(a: string, b: string, maxDistance = 2): bool export function normalizePhrase(phrase: string): string { return phrase .toUpperCase() - .replace(/[\s_\-\.]+/g, '') // Remove whitespace, underscores, hyphens, dots + .replace(/[\s_\-.]+/g, '') // Remove whitespace, underscores, hyphens, dots .trim(); } diff --git a/src/web/server.ts b/src/web/server.ts index 4a76e171..80f9fb19 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -195,7 +195,9 @@ const ITERATION_PAUSE_MS = 2000; // Set high (32KB) to allow effective batching; avg Ink events are ~14KB const BATCH_FLUSH_THRESHOLD = 32 * 1024; // Pre-compiled regex for terminal buffer cleaning (avoids per-request compilation) +// eslint-disable-next-line no-control-regex const CLAUDE_BANNER_PATTERN = /\x1b\[1mClaud/; +// eslint-disable-next-line no-control-regex const CTRL_L_PATTERN = /\x0c/g; const LEADING_WHITESPACE_PATTERN = /^[\s\r\n]+/; @@ -445,7 +447,6 @@ export class WebServer extends EventEmitter { // Flag to prevent new timers during shutdown private _isStopping: boolean = false; // Cached light state for SSE init (avoids rebuilding on every reconnect) - // eslint-disable-next-line @typescript-eslint/no-explicit-any private cachedLightState: { data: Record; timestamp: number } | null = null; private static readonly LIGHT_STATE_CACHE_TTL_MS = 1000; // Cached sessions list for getLightSessionsState() (avoids re-serializing all sessions on every call) @@ -3019,7 +3020,7 @@ export class WebServer extends EventEmitter { status: 'pending' | 'in_progress' | 'completed'; priority: string | null; }> = []; - const todoPattern = /^-\s*\[([ xX\-])\]\s*(.+)$/; + const todoPattern = /^-\s*\[([ xX-])\]\s*(.+)$/; const p0HeaderPattern = /^##\s*(High Priority|Critical|P0|Critical Path)/i; const p1HeaderPattern = /^##\s*(Standard|P1|Medium Priority)/i; const p2HeaderPattern = /^##\s*(Nice to Have|P2|Low Priority)/i; @@ -4040,8 +4041,8 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; .replace(/\n/g, '\\n') .replace(/\r/g, '\\r') .replace(/\t/g, '\\t') - // eslint-disable-next-line no-control-regex .replace( + // eslint-disable-next-line no-control-regex /[\x00-\x1f]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}` )