Apply LLM-written SEARCH/REPLACE blocks to a file, tolerantly.
Asking a model to edit a large file by re-emitting the whole file is slow and expensive (output tokens dominate the bill). Asking it for small SEARCH/REPLACE blocks is far cheaper, but models are bad at copying the surrounding text character for character: wrong indentation, a tag re-wrapped over two lines, \r\n vs \n. Most appliers just fail on those. This one accepts the near-misses and stays strict where it matters.
- Zero dependencies, one file, TypeScript types included.
- Tolerant matching: exact match → ignore indentation and line endings → same words in the same order.
- Strict on ambiguity: an anchor matching more than one place is refused (
block_N_ambiguous), never guessed. - All-or-nothing, but returns
partialCode(the blocks that did apply) so you can ask the model for only the missing blocks instead of regenerating everything. - Keeps the file's own indentation around the replaced span.
import { applyPatches, hasPatchBlocks, PATCH_INSTRUCTIONS } from "search-replace-patch";
const reply = await callYourModel({
system: "You edit code.\n\n" + PATCH_INSTRUCTIONS,
user: `Current file:\n${code}\n\nChange the price to 6500.`,
});
if (hasPatchBlocks(reply)) {
const r = applyPatches(code, reply);
if (r.ok) {
save(r.code); // r.applied blocks applied
} else if (r.partialCode) {
// some blocks applied: ask the model only for the rest, on r.partialCode
} else {
// nothing applied (reason: "block_1_missing", "block_2_ambiguous", "no_blocks"…)
// escalate to a stronger model, or regenerate the file
}
}Install from GitHub (builds on install):
npm install github:hypesecret/search-replace-patch
<<<<<<< SEARCH
exact lines copied from the current file
=======
lines that replace them
>>>>>>> REPLACE
Empty REPLACE deletes. To insert, use an existing anchor line as SEARCH and repeat it in REPLACE followed by the new code.
Extracted from a prompt-to-app builder. In one benchmark of 8 models × 15 edit requests on a single-file React app (≈100 real calls), the failure causes were: a block whose anchor was not found (missing), an anchor matching several places (ambiguous), and edits that applied but broke compilation. Both anchor failures are reported distinctly so a caller can react differently (repair vs. escalate).
What was NOT measured: the effect of the tolerant matching itself. We never compared "tolerant" against "exact-only" on the same replies, so we make no claim about how many failures the tolerance saves. It is a sample from one app, not a general result: measure on your own files.
- It does not validate the result (compile, lint, render). Do that after applying; if validation fails, that is your escalation trigger.
- It matches text, not syntax trees. A
SEARCHthat is textually unique but semantically the wrong place will still be applied. - Regex-free inputs only:
SEARCHis matched literally (special characters are escaped).
Applique des blocs SEARCH/REPLACE écrits par un LLM sur un fichier, en tolérant l'indentation, les fins de ligne et les balises coupées sur plusieurs lignes, en refusant les ancrages ambigus, et en renvoyant le code partiel (partialCode) quand seuls certains blocs s'appliquent. Sans dépendance, un seul fichier.
npm install
npm test # vitest
npm run typecheck
npm run build
MIT © hypesecret