RELEASE_NOTES.md
RELEASE_NOTES.md
Fixed a deterministic multi-day V8 heap OOM (Ineffective mark-compacts near heap limit) in the vector-RAG text chunkers β and closed the last failing test (cross-test mock contamination) in tests/webResearchTools.test.ts.
src/tools/vectorRagTools.ts): chunkText, chunkDocxText, and chunkPdfText could loop forever when a partial final chunk was shorter than the overlap word budget β for certain text lengths the window start reached a fixed point (startIndex === endIndex). All three now enforce strict forward progress: startIndex = Math.max(endIndex, startIndex + 1).tests/vectorRagTools.ragWebContent.test.ts): the oversized-page spec exercises the poison-remainder path end-to-end; heading assertion aligned with html-to-text's default heading uppercasing (case-insensitive).tests/webResearchTools.test.ts): shared mocks are now reset in beforeEach and re-seeded explicitly β no more state leaking between tests.npm test).npm run build; bundles carry no version strings).Versioning: stays at v1.9.10 (no bump) β maintainer decision 25.08.
Eliminated a class of plugin-host crashes (JavaScript heap out of memory) caused by unbounded page-body buffering in the web tools.
fetch_web_content: previously buffered the full page with response.text() and only then checked its 50 KB cap β oversized pages exhausted the host's heap first. The cap is now enforced while streaming; the socket is cancelled the moment the budget trips.Page too large (β¦) β¦ Use searxng_search + summary_only).Eliminated silent auto-registration of wrong/stale project paths without user confirmation.
Prior to this fix, the silent auto-registration bug occurred because:
register_project tool call with confirmed pathEliminated all synchronous file writes from the codebase; introduced shared crash-resilient atomic write utility with randomized temp filenames and rollback-on-failure protection.
crypto.randomBytes(9) for unique temp file names β prevents collisions even under rapid concurrent writes, eliminates stale temp files from prior crashesatomicWriteBinaryFile() function uses raw buffer writes with no text encoding β preserves exact binary content for image processing and other non-text operationsAll previously synchronous file-write tools converted to async with shared atomicWrite:
| Module | Tools Affected | Previous State | New State |
|---|---|---|---|
| lineOperations.ts | delete_lines, line_operations | Sync writes via fs.writeFileSync | Async β atomicWrite |
| refactorCodeTools.ts | rename_identifier, move_function, extract_function, unused_import_cleanup | Sync writes | Async β atomicWrite + rollback-on-failure |
| utilityTools.ts | ~25 utility tools (backup, chart, line ops) | Mixed sync/async | All async β atomicWrite |
| dataVisualizationTools.ts | generate_chart | Sync PNG write | Async β atomicWriteBinaryFile |
| imageProcessingTools.ts | describe_image, compare_images output saves | Sync writes | Async β atomicWriteBinaryFile |
| markdownPreviewTools.ts | markdown_preview HTML save | Sync write | Async β atomicWrite |
| browserAutomationTools.ts | screenshot_desktop PNG save | Sync write | Async β atomicWriteBinaryFile |
| uiGenerationTools.ts | UI component saves | Sync writes | Async β atomicWrite |
| recodeEngine.ts (recodeTool/) | AST transformation output | Sync writes | Async β atomicWrite + rollback-on-failure |
.bak backup before returning error β prevents corrupted source filesReplaced all child_process.exec() calls with explicit shell spawning via spawn(cmd.exe /c, ...) in gitGithubTools.ts. Zero behavioral changes; zero breaking changes.
import { spawn } from 'child_process'cmd.exe /c (Windows) or /bin/sh -c (Unix/macOS) β never uses { shell: true }, avoiding Node.js DEP0190 warningFixed the checkpoint warning that was generated but never surfaced in chat; restored confirm-first working-directory switching and added German JA/NEIN reply support.
A Step 0.7 refactor silently switched the working directory on project-keyword match β burying the pending checkpoint warning (logs: "THRESHOLD PROMPT GENERATED"; chat: nothing) and bypassed Step 0.6 reply handling. Reply detection accepted only English YES/NO, and transitionTo() cleared pending warnings on any state change.
promptPreprocessor.ts): confirm-first banner β no CWD change on detection; one-shot switch only after an explicit YES/JA reply in a later message, then resetspromptPreprocessor.ts): JA/NEIN normalized onto canonical YES/NO FSM inputs for checkpoint repliesautoTracker.ts): transitionTo() no longer clears pendingCheckpointWarning on unrelated state changes; warning injected into all preprocessor return paths while pendingEliminated the "ai-toolbox not found" clarification loop by adding Step 0.7 project keyword detection in promptPreprocessor.ts and _syncFromSessionMemory() lazy registry sync.
When users mentioned a registered project name (e.g., "switch to ai-toolbox"), the AI would:
search_projects(query="ai-toolbox") β empty results (stale registry)Root Cause: The cross-project registry was never synced from session memory decisions. Projects detected via keyword matching in Step 0.7 were registered once but not auto-synced when search_projects was called later.
| Tool | Sync Trigger | Purpose |
|---|---|---|
| search_projects | _syncFromSessionMemory() before query | Ensures registry includes projects from past decisions |
| get_project_info | _syncFromSessionMemory() before lookup | Same β prevents stale registry entries |
Resolved TypeScript compilation errors and ESLint warnings through ESM conversion and proper type assertions.
require('../attachmentManager.js') (CommonJS) with static ESM import β eliminates @typescript-eslint/no-require-imports warningSynchronized version references and added missing module documentation across project files.
Fixed a deterministic multi-day V8 heap OOM (Ineffective mark-compacts near heap limit) in the vector-RAG text chunkers β and closed the last failing test (cross-test mock contamination) in tests/webResearchTools.test.ts.
src/tools/vectorRagTools.ts): chunkText, chunkDocxText, and chunkPdfText could loop forever when a partial final chunk was shorter than the overlap word budget β for certain text lengths the window start reached a fixed point (startIndex === endIndex). All three now enforce strict forward progress: startIndex = Math.max(endIndex, startIndex + 1).tests/vectorRagTools.ragWebContent.test.ts): the oversized-page spec exercises the poison-remainder path end-to-end; heading assertion aligned with html-to-text's default heading uppercasing (case-insensitive).tests/webResearchTools.test.ts): shared mocks are now reset in beforeEach and re-seeded explicitly β no more state leaking between tests.npm test).npm run build; bundles carry no version strings).Versioning: stays at v1.9.10 (no bump) β maintainer decision 25.08.
Eliminated a class of plugin-host crashes (JavaScript heap out of memory) caused by unbounded page-body buffering in the web tools.
fetch_web_content: previously buffered the full page with response.text() and only then checked its 50 KB cap β oversized pages exhausted the host's heap first. The cap is now enforced while streaming; the socket is cancelled the moment the budget trips.Page too large (β¦) β¦ Use searxng_search + summary_only).Eliminated silent auto-registration of wrong/stale project paths without user confirmation.
Prior to this fix, the silent auto-registration bug occurred because:
register_project tool call with confirmed pathEliminated all synchronous file writes from the codebase; introduced shared crash-resilient atomic write utility with randomized temp filenames and rollback-on-failure protection.
crypto.randomBytes(9) for unique temp file names β prevents collisions even under rapid concurrent writes, eliminates stale temp files from prior crashesatomicWriteBinaryFile() function uses raw buffer writes with no text encoding β preserves exact binary content for image processing and other non-text operationsAll previously synchronous file-write tools converted to async with shared atomicWrite:
| Module | Tools Affected | Previous State | New State |
|---|---|---|---|
| lineOperations.ts | delete_lines, line_operations | Sync writes via fs.writeFileSync | Async β atomicWrite |
| refactorCodeTools.ts | rename_identifier, move_function, extract_function, unused_import_cleanup | Sync writes | Async β atomicWrite + rollback-on-failure |
| utilityTools.ts | ~25 utility tools (backup, chart, line ops) | Mixed sync/async | All async β atomicWrite |
| dataVisualizationTools.ts | generate_chart | Sync PNG write | Async β atomicWriteBinaryFile |
| imageProcessingTools.ts | describe_image, compare_images output saves | Sync writes | Async β atomicWriteBinaryFile |
| markdownPreviewTools.ts | markdown_preview HTML save | Sync write | Async β atomicWrite |
| browserAutomationTools.ts | screenshot_desktop PNG save | Sync write | Async β atomicWriteBinaryFile |
| uiGenerationTools.ts | UI component saves | Sync writes | Async β atomicWrite |
| recodeEngine.ts (recodeTool/) | AST transformation output | Sync writes | Async β atomicWrite + rollback-on-failure |
.bak backup before returning error β prevents corrupted source filesReplaced all child_process.exec() calls with explicit shell spawning via spawn(cmd.exe /c, ...) in gitGithubTools.ts. Zero behavioral changes; zero breaking changes.
import { spawn } from 'child_process'cmd.exe /c (Windows) or /bin/sh -c (Unix/macOS) β never uses { shell: true }, avoiding Node.js DEP0190 warningFixed the checkpoint warning that was generated but never surfaced in chat; restored confirm-first working-directory switching and added German JA/NEIN reply support.
A Step 0.7 refactor silently switched the working directory on project-keyword match β burying the pending checkpoint warning (logs: "THRESHOLD PROMPT GENERATED"; chat: nothing) and bypassed Step 0.6 reply handling. Reply detection accepted only English YES/NO, and transitionTo() cleared pending warnings on any state change.
promptPreprocessor.ts): confirm-first banner β no CWD change on detection; one-shot switch only after an explicit YES/JA reply in a later message, then resetspromptPreprocessor.ts): JA/NEIN normalized onto canonical YES/NO FSM inputs for checkpoint repliesautoTracker.ts): transitionTo() no longer clears pendingCheckpointWarning on unrelated state changes; warning injected into all preprocessor return paths while pendingEliminated the "ai-toolbox not found" clarification loop by adding Step 0.7 project keyword detection in promptPreprocessor.ts and _syncFromSessionMemory() lazy registry sync.
When users mentioned a registered project name (e.g., "switch to ai-toolbox"), the AI would:
search_projects(query="ai-toolbox") β empty results (stale registry)Root Cause: The cross-project registry was never synced from session memory decisions. Projects detected via keyword matching in Step 0.7 were registered once but not auto-synced when search_projects was called later.
| Tool | Sync Trigger | Purpose |
|---|---|---|
| search_projects | _syncFromSessionMemory() before query | Ensures registry includes projects from past decisions |
| get_project_info | _syncFromSessionMemory() before lookup | Same β prevents stale registry entries |
Resolved TypeScript compilation errors and ESLint warnings through ESM conversion and proper type assertions.
require('../attachmentManager.js') (CommonJS) with static ESM import β eliminates @typescript-eslint/no-require-imports warningSynchronized version references and added missing module documentation across project files.
rag_web_content (vectorRAG): previously a raw, uncapped, unbounded fetch plus ~5β10Γ memory amplification in chunking. Now bounded to 500 KB and routed through the shared timeout/retry helper.fetchWithRetry paths: every attempt is now time-bounded (30 s AbortController timeout), matching the existing http_* tools' convention β slow or stalled transfers can no longer hang indefinitely.writeFileSync blocking the event loop during LLM tool chainsatomicWriteBinaryFile() uses raw buffer writes β image processing and chart generation preserve exact binary contentrag_web_content (vectorRAG): previously a raw, uncapped, unbounded fetch plus ~5β10Γ memory amplification in chunking. Now bounded to 500 KB and routed through the shared timeout/retry helper.fetchWithRetry paths: every attempt is now time-bounded (30 s AbortController timeout), matching the existing http_* tools' convention β slow or stalled transfers can no longer hang indefinitely.writeFileSync blocking the event loop during LLM tool chainsatomicWriteBinaryFile() uses raw buffer writes β image processing and chart generation preserve exact binary content