fix(tools): make claude-memory file operations act on the exact file, literally#1285
Open
abhay-codes07 wants to merge 1 commit into
Open
fix(tools): make claude-memory file operations act on the exact file, literally#1285abhay-codes07 wants to merge 1 commit into
abhay-codes07 wants to merge 1 commit into
Conversation
… literally Three related defects in the Claude memory tool's file operations: - str_replace passed the model-authored replacement to String.replace as a plain string, so JS replacement patterns were expanded: a new_str containing $&, $', $` or $$ silently wrote corrupted content while reporting success (e.g. replacing TODO with "price is $& now" stores "price is TODO now"). Memory files routinely contain literal dollar signs — code, prices, shell snippets. A function replacer keeps the value literal. - readFile (the view command) searched with limit: 1 and then looked for the exact customId match inside that single result — the sibling getFileDocument helper uses limit: 5 precisely so the exact match is findable among semantic near-neighbours. If a similarly-named file ranked first, view returned the wrong file's contents as a success. readFile now goes through getFileDocument, which also removes the duplicated lookup and makes view read the same raw||content the mutating commands edit. - both lookups fell back to results[0] when no exact customId match existed, which let view read — and str_replace/insert/delete/rename modify — a different file than the one requested. The lookup now requires the exact match and reports file-not-found otherwise. Covered with mocked-SDK tests: dollar-sequence literalness for all four patterns, exact-match preference when a neighbour ranks first, and not-found (with no write issued) when only a different file comes back. Six of the seven new tests fail against the previous implementation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Three related defects in the Claude memory tool's file operations (
packages/tools/src/claude-memory.ts):str_replacecorrupts content containing$sequences. The model-authored replacement was passed toString.replaceas a plain string, so JS replacement patterns were expanded: anew_strcontaining$&,$',$`or$$silently wrote corrupted content while reporting success (replaceTODOwithprice is $& now→ storesprice is TODO now). Memory files routinely contain literal dollar signs — code, prices, shell snippets.viewcould return the wrong file as a success.readFilesearched withlimit: 1and then looked for the exact customId match inside that single result — while the siblinggetFileDocumenthelper (used by every mutating command) useslimit: 5precisely so the exact match is findable among semantic near-neighbours. If a similarly-named file ranked first (notes.txtvsnotes_backup.txt),viewreturned the wrong file's contents with line numbers, as a success.Both lookups fell back to
results[0]when no exact match existed — which letviewread, andstr_replace/insert/delete/renamemodify, a different file than the one requested.Fix
originalContent.replace(oldStr, () => newStr)readFilenow goes throughgetFileDocument(removing the duplicated lookup and makingviewread the sameraw || contentthe mutating commands edit)Testing
$&,$',$`,$$), exact-match preference when a neighbour ranks first, and not-found (with no write issued) when only a different file comes back — six of the seven new tests fail against the previous implementationvitest run src/claude-memory.test.ts— 10 passtsc --noEmiterror count unchanged vsmain(148 pre-existing),biome checkclean on touched filescc @MaheshtheDev