Summary
cleanBody in @dualmark/core replaces configured HTML-ish tags (e.g. <Highlighted>…</Highlighted> to **…**, plus any custom htmlTagReplacements) with a regex that has no dotAll flag. . does not match newlines, so a tag whose content spans multiple lines is never matched, and its raw markup is left in the output that AI clients consume.
Where
packages/core/src/text.ts:73
const re = new RegExp(`<${tag}>(.*?)<\/${tag}>`, "g");
Reproduction
import { cleanBody } from "@dualmark/core";
cleanBody("see <Highlighted>hi</Highlighted> end");
// "see **hi** end" (single line, correct)
cleanBody("see <Highlighted>multi\nline</Highlighted> end");
// "see <Highlighted>multi\nline</Highlighted> end" (BUG: raw tags leak)
The single-line case is covered by a test (text.test.ts), so the behavior is inconsistent: the same tag is converted on one line but leaks across two.
Proposed fix
Add the s (dotAll) flag to the regex. The quantifier stays lazy (.*?), so it still stops at the first closing tag and does not merge adjacent tags. PR incoming.
Summary
cleanBodyin@dualmark/corereplaces configured HTML-ish tags (e.g.<Highlighted>…</Highlighted>to**…**, plus any customhtmlTagReplacements) with a regex that has no dotAll flag..does not match newlines, so a tag whose content spans multiple lines is never matched, and its raw markup is left in the output that AI clients consume.Where
packages/core/src/text.ts:73Reproduction
The single-line case is covered by a test (
text.test.ts), so the behavior is inconsistent: the same tag is converted on one line but leaks across two.Proposed fix
Add the
s(dotAll) flag to the regex. The quantifier stays lazy (.*?), so it still stops at the first closing tag and does not merge adjacent tags. PR incoming.