From d722aca2c700da4eaad2b2874d0c9c36c5d1cfde Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 24 Jan 2026 04:36:18 +0100 Subject: [PATCH] refactor: pre-compile regex patterns and remove dead code - task.ts: Cache completion phrase regex in constructor instead of re-creating on every checkCompletion() call. Add escapeRegex helper for safe RegExp construction from user-provided phrases. - ralph-tracker.ts: Remove commented-out COMPLETION_SIGNAL_PATTERN Co-Authored-By: Claude Opus 4.5 --- src/ralph-tracker.ts | 3 --- src/task.ts | 21 ++++++++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/ralph-tracker.ts b/src/ralph-tracker.ts index 5ad70068..28d40080 100644 --- a/src/ralph-tracker.ts +++ b/src/ralph-tracker.ts @@ -209,9 +209,6 @@ const ALL_COUNT_PATTERN = /all\s+(\d+)\s+(?:tasks?|files?|items?)/i; */ const TASK_DONE_PATTERN = /(?:task|item|todo)\s*(?:#?\d+|"\s*[^"]+\s*")?\s*(?:is\s+)?(?:done|completed?|finished)|(?:completed?|done|finished)\s+(?:task|item)\s*(?:#?\d+)?|marking\s+(?:.*?\s+)?(?:as\s+)?completed?|marked\s+(?:.*?\s+)?(?:as\s+)?completed?/i; -// Generic completion signal pattern - commented out due to false positive risk -// const COMPLETION_SIGNAL_PATTERN = /^(?:done|completed?|finished|all\s+set)!?\s*$/i; - // ---------- Utility Patterns ---------- /** diff --git a/src/task.ts b/src/task.ts index ce1ec312..1b282e70 100644 --- a/src/task.ts +++ b/src/task.ts @@ -10,6 +10,14 @@ import { v4 as uuidv4 } from 'uuid'; import { TaskDefinition, TaskState, TaskStatus } from './types.js'; +/** Pre-compiled pattern for generic promise tag detection */ +const PROMISE_TAG_PATTERN = /[^<]+<\/promise>/; + +/** Escapes special regex characters in a string for safe use in RegExp constructor */ +function escapeRegex(str: string): string { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + /** * Options for creating a new task. */ @@ -45,6 +53,8 @@ export class Task { private _completedAt: number | null = null; private _output: string = ''; private _error: string | null = null; + /** Pre-compiled regex for completion phrase detection (avoids re-creation per check) */ + private readonly _completionPattern: RegExp | null; constructor(options: CreateTaskOptions, id?: string) { this.id = id || uuidv4(); @@ -55,6 +65,9 @@ export class Task { this.completionPhrase = options.completionPhrase; this.timeoutMs = options.timeoutMs; this.createdAt = Date.now(); + this._completionPattern = options.completionPhrase + ? new RegExp(`${escapeRegex(options.completionPhrase)}`) + : null; } get status(): TaskStatus { @@ -190,13 +203,11 @@ export class Task { /** Checks if output contains the completion phrase. */ checkCompletion(output: string): boolean { - if (this.completionPhrase) { - // Check for exact completion phrase in promise tags - const pattern = new RegExp(`${this.completionPhrase}`); - return pattern.test(output); + if (this._completionPattern) { + return this._completionPattern.test(output); } // Default: check for any promise tag completion - return /[^<]+<\/promise>/.test(output); + return PROMISE_TAG_PATTERN.test(output); } /** Returns true if the task has exceeded its timeout. */