{"_id":"@ai-markdown/engine","_rev":"4-7628ecda95e5661e20530746149ea5dc","name":"@ai-markdown/engine","dist-tags":{"latest":"3.0.0","beta":"3.0.0-beta.2","rc":"3.0.0-rc.1"},"versions":{"3.0.0-beta.1":{"name":"@ai-markdown/engine","version":"3.0.0-beta.1","keywords":["markdown","markdown-parser","ai","llm","streaming","incremental","incremental-parsing","prefix-freeze","latex","katex","math","remark","rehype","unified","hast","mdast","footnotes","sanitize","typescript"],"author":{"url":"https://github.com/AIEPhoenix","name":"Brian Lee","email":"aiephoenixbl@gmail.com"},"license":"MIT","_id":"@ai-markdown/engine@3.0.0-beta.1","maintainers":[{"name":"aiephoenix","email":"aiephoenixbl@gmail.com"}],"homepage":"https://github.com/ai-markdown/ai-markdown/tree/main/packages/engine#readme","bugs":{"url":"https://github.com/ai-markdown/ai-markdown/issues"},"dist":{"shasum":"3fcae24b25be3c796ab30871ea115e2e667fa06e","tarball":"https://registry.npmjs.org/@ai-markdown/engine/-/engine-3.0.0-beta.1.tgz","fileCount":14,"integrity":"sha512-vpV+WBpDP0i3jE9Obi2jF5r7/wnKRYqJBWECKqb1Et71c61xbV2EuTajK1teaWSrPzElGYpxB43efJaQF1ZD1w==","signatures":[{"sig":"MEYCIQCo1CTY1gbB9m3jT/1y1MjOm4ex49/EkCQqC0v8qWpLEAIhAKRcaDKiWC4/BEp2VbmxsI/JkQA8od/X/VExH4bxHS1A","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ai-markdown%2fengine@3.0.0-beta.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":11666995},"main":"./dist/index.cjs","type":"module","_from":"file:/home/runner/work/_temp/first-publish-packs/ai-markdown-engine-3.0.0-beta.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":{"import":"./dist/index.d.ts","require":"./dist/index.d.cts"},"import":"./dist/index.js","require":"./dist/index.cjs","development":{"import":"./dist/index.dev.js","require":"./dist/index.dev.cjs"}},"./package.json":"./package.json"},"scripts":{"soak":"../../scripts/soak/soak.sh","test":"vitest --run","build":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsup && node scripts/assert-dist-clean.mjs && node scripts/collect-bundled-licenses.mjs","typecheck":"tsc --noEmit -p tsconfig.json","soak:watch":"../../scripts/soak/soak-watch.sh","fuzz:splice":"vitest --run src/components/incrementalParse/spliceFuzz.test.ts","soak:coverage":"node ../../scripts/soak/assert-coverage-map.mjs","soak:aggregate":"node ../../scripts/soak/soak-aggregate.mjs"},"_npmUser":{"name":"aiephoenix","email":"aiephoenixbl@gmail.com"},"_resolved":"/home/runner/work/_temp/first-publish-packs/ai-markdown-engine-3.0.0-beta.1.tgz","_integrity":"sha512-vpV+WBpDP0i3jE9Obi2jF5r7/wnKRYqJBWECKqb1Et71c61xbV2EuTajK1teaWSrPzElGYpxB43efJaQF1ZD1w==","repository":{"url":"git+https://github.com/ai-markdown/ai-markdown.git","type":"git","directory":"packages/engine"},"_npmVersion":"10.9.8","description":"Framework-independent Markdown parsing, incremental transforms, preprocessing and document registries for ai-markdown.","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","dependencies":{"vfile":"^6.0.3","devlop":"^1.1.0","remend":"^1.3.1","unified":"^11.0.5","remark-gfm":"^4.0.1","@types/hast":"^3.0.5","remark-math":"^6.0.0","@types/mdast":"^4.0.4","rehype-katex":"^7.0.1","remark-emoji":"^5.0.2","remark-pangu":"^2.2.0","remark-parse":"^11.0.0","remark-breaks":"^4.0.0","remark-rehype":"^11.1.2","rehype-sanitize":"^6.0.0","unist-util-visit":"^5.1.0","mdast-util-to-hast":"^13.2.1","remark-smartypants":"^3.0.3","html-url-attributes":"^3.0.1","remark-cjk-friendly":"^2.3.1","rehype-unwrap-images":"^1.0.0","remark-definition-list":"^2.0.0","remark-remove-comments":"^1.1.1","@ai-markdown/rehype-raw":"7.0.3","remark-squeeze-paragraphs":"^6.0.0","micromark-util-sanitize-uri":"^2.0.1","micromark-util-html-tag-name":"^2.0.1","@ai-markdown/remark-mark-highlight":"^1.0.1","micromark-util-normalize-identifier":"^2.0.1","remark-cjk-friendly-gfm-strikethrough":"^2.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lodash-es":"^4.18.0","fast-check":"^4.9.0","hastscript":"^9.0.1","@types/unist":"^3.0.3","@types/lodash-es":"^4.17.12","hast-util-sanitize":"^5.0.2","@stryker-mutator/core":"^9.6.1","@stryker-mutator/vitest-runner":"^9.6.1"},"peerDependencies":{"katex":"^0.16.0 || ^0.17.0"},"peerDependenciesMeta":{"katex":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/engine_3.0.0-beta.1_1788927167329_0.39222824318662664","host":"s3://npm-registry-packages-npm-production"}},"3.0.0-beta.2":{"name":"@ai-markdown/engine","version":"3.0.0-beta.2","keywords":["markdown","markdown-parser","ai","llm","streaming","incremental","incremental-parsing","prefix-freeze","latex","katex","math","remark","rehype","unified","hast","mdast","footnotes","sanitize","typescript"],"author":"Brian Lee <aiephoenixbl@gmail.com> (https://github.com/AIEPhoenix)","license":"MIT","_id":"@ai-markdown/engine@3.0.0-beta.2","maintainers":[{"name":"aiephoenix","email":"aiephoenixbl@gmail.com"}],"homepage":"https://github.com/ai-markdown/ai-markdown/tree/main/packages/engine#readme","bugs":{"url":"https://github.com/ai-markdown/ai-markdown/issues"},"dist":{"shasum":"2e52d000d435a6df2afc79ecb8e4473887ffa06f","tarball":"https://registry.npmjs.org/@ai-markdown/engine/-/engine-3.0.0-beta.2.tgz","fileCount":14,"integrity":"sha512-0IjSTbqr9qMtzV0caCQ+eDSYFgot8eIoTlXiTDfFlH6GO4Mk9wTIcYKT4aJVJtHroYowwSlpEY+hWBJsJpqbKA==","signatures":[{"sig":"MEUCIBFUighyU1+/hVIa149735aTY1e2uRamW2f0x4UK/8U4AiEAwTLVayDAo9bqd3SWyqUxTBPdKUC3zgHUFI2vVgsJCUM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ai-markdown%2fengine@3.0.0-beta.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":11664342},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":{"import":"./dist/index.d.ts","require":"./dist/index.d.cts"},"import":"./dist/index.js","require":"./dist/index.cjs","development":{"import":"./dist/index.dev.js","require":"./dist/index.dev.cjs"}},"./package.json":"./package.json"},"scripts":{"soak":"../../scripts/soak/soak.sh","test":"vitest --run","build":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsup && node scripts/assert-dist-clean.mjs && node scripts/collect-bundled-licenses.mjs","typecheck":"tsc --noEmit -p tsconfig.json","soak:watch":"../../scripts/soak/soak-watch.sh","fuzz:splice":"vitest --run src/components/incrementalParse/spliceFuzz.test.ts","soak:coverage":"node ../../scripts/soak/assert-coverage-map.mjs","soak:aggregate":"node ../../scripts/soak/soak-aggregate.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:501a3298-d58f-44ef-873e-4c428d1bfa8c"}},"repository":{"url":"git+https://github.com/ai-markdown/ai-markdown.git","type":"git","directory":"packages/engine"},"description":"Framework-independent Markdown parsing, incremental transforms, preprocessing and document registries for ai-markdown.","directories":{},"sideEffects":false,"_nodeVersion":"26.0.0","dependencies":{"vfile":"^6.0.3","devlop":"^1.1.0","remend":"^1.3.1","unified":"^11.0.5","remark-gfm":"^4.0.1","@types/hast":"^3.0.5","remark-math":"^6.0.0","@types/mdast":"^4.0.4","rehype-katex":"^7.0.1","remark-emoji":"^5.0.2","remark-pangu":"^2.2.0","remark-parse":"^11.0.0","remark-breaks":"^4.0.0","remark-rehype":"^11.1.2","rehype-sanitize":"^6.0.0","unist-util-visit":"^5.1.0","mdast-util-to-hast":"^13.2.1","remark-smartypants":"^3.0.3","html-url-attributes":"^3.0.1","remark-cjk-friendly":"^2.3.1","rehype-unwrap-images":"^1.0.0","remark-definition-list":"^2.0.0","remark-remove-comments":"^1.1.1","@ai-markdown/rehype-raw":"7.0.3","remark-squeeze-paragraphs":"^6.0.0","micromark-util-sanitize-uri":"^2.0.1","micromark-util-html-tag-name":"^2.0.1","@ai-markdown/remark-mark-highlight":"^1.0.1","micromark-util-normalize-identifier":"^2.0.1","remark-cjk-friendly-gfm-strikethrough":"^2.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lodash-es":"^4.18.0","fast-check":"^4.9.0","hastscript":"^9.0.1","@types/unist":"^3.0.3","@types/lodash-es":"^4.17.12","hast-util-sanitize":"^5.0.2","@stryker-mutator/core":"^9.6.1","@stryker-mutator/vitest-runner":"^9.6.1"},"peerDependencies":{"katex":"^0.16.0 || ^0.17.0"},"peerDependenciesMeta":{"katex":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/engine_3.0.0-beta.2_1788962868119_0.7977555527463178","host":"s3://npm-registry-packages-npm-production"}},"3.0.0-rc.1":{"name":"@ai-markdown/engine","version":"3.0.0-rc.1","keywords":["markdown","markdown-parser","ai","llm","streaming","incremental","incremental-parsing","prefix-freeze","latex","katex","math","remark","rehype","unified","hast","mdast","footnotes","sanitize","typescript"],"author":"Brian Lee <aiephoenixbl@gmail.com> (https://github.com/AIEPhoenix)","license":"MIT","_id":"@ai-markdown/engine@3.0.0-rc.1","maintainers":[{"name":"aiephoenix","email":"aiephoenixbl@gmail.com"}],"homepage":"https://github.com/ai-markdown/ai-markdown/tree/main/packages/engine#readme","bugs":{"url":"https://github.com/ai-markdown/ai-markdown/issues"},"dist":{"shasum":"412accaafb0c04bf20b79cc0d4344e6e2aaeac94","tarball":"https://registry.npmjs.org/@ai-markdown/engine/-/engine-3.0.0-rc.1.tgz","fileCount":14,"integrity":"sha512-LimHcKkWAaShF0gqLBjvF7PlkHTulQdQxgcPkFZOv/85CWbLKOJg2kWEa9ykDNI+dfwDbRzE+zRwf2Be7SoGqw==","signatures":[{"sig":"MEUCIQChkfi5FezVKyd5Rb8NJslwyxEgQ8MUkvDCSI9x0Lxm2wIgQwm1FM0QRAsPs/VMtRYURLx+8gfym6AnXwLxVe6i7do=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ai-markdown%2fengine@3.0.0-rc.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":11663884},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":{"import":"./dist/index.d.ts","require":"./dist/index.d.cts"},"import":"./dist/index.js","require":"./dist/index.cjs","development":{"import":"./dist/index.dev.js","require":"./dist/index.dev.cjs"}},"./package.json":"./package.json"},"scripts":{"soak":"../../scripts/soak/soak.sh","test":"vitest --run","build":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsup && node scripts/assert-dist-clean.mjs && node scripts/collect-bundled-licenses.mjs","typecheck":"tsc --noEmit -p tsconfig.json","soak:watch":"../../scripts/soak/soak-watch.sh","fuzz:splice":"vitest --run src/components/incrementalParse/spliceFuzz.test.ts","soak:coverage":"node ../../scripts/soak/assert-coverage-map.mjs","soak:aggregate":"node ../../scripts/soak/soak-aggregate.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:501a3298-d58f-44ef-873e-4c428d1bfa8c"}},"repository":{"url":"git+https://github.com/ai-markdown/ai-markdown.git","type":"git","directory":"packages/engine"},"description":"Framework-independent Markdown parsing, incremental transforms, preprocessing and document registries for ai-markdown.","directories":{},"sideEffects":false,"_nodeVersion":"26.0.0","dependencies":{"vfile":"^6.0.3","devlop":"^1.1.0","remend":"^1.3.1","unified":"^11.0.5","remark-gfm":"^4.0.1","@types/hast":"^3.0.5","remark-math":"^6.0.0","@types/mdast":"^4.0.4","rehype-katex":"^7.0.1","remark-emoji":"^5.0.2","remark-pangu":"^2.2.0","remark-parse":"^11.0.0","remark-breaks":"^4.0.0","remark-rehype":"^11.1.2","rehype-sanitize":"^6.0.0","unist-util-visit":"^5.1.0","mdast-util-to-hast":"^13.2.1","remark-smartypants":"^3.0.3","html-url-attributes":"^3.0.1","remark-cjk-friendly":"^2.3.1","rehype-unwrap-images":"^1.0.0","remark-definition-list":"^2.0.0","remark-remove-comments":"^1.1.1","@ai-markdown/rehype-raw":"7.0.3","remark-squeeze-paragraphs":"^6.0.0","micromark-util-sanitize-uri":"^2.0.1","micromark-util-html-tag-name":"^2.0.1","@ai-markdown/remark-mark-highlight":"^1.0.2","micromark-util-normalize-identifier":"^2.0.1","remark-cjk-friendly-gfm-strikethrough":"^2.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lodash-es":"^4.18.0","fast-check":"^4.9.0","hastscript":"^9.0.1","@types/unist":"^3.0.3","@types/lodash-es":"^4.17.12","hast-util-sanitize":"^5.0.2","@stryker-mutator/core":"^9.6.1","@stryker-mutator/vitest-runner":"^9.6.1"},"peerDependencies":{"katex":"^0.16.0 || ^0.17.0"},"peerDependenciesMeta":{"katex":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/engine_3.0.0-rc.1_1789052533818_0.13739557094978472","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@ai-markdown/engine","version":"3.0.0","description":"Framework-independent Markdown parsing, incremental transforms, preprocessing and document registries for ai-markdown.","publishConfig":{"access":"public"},"type":"module","license":"MIT","engines":{"node":"^20.19.0 || >=22.12.0"},"author":"Brian Lee <aiephoenixbl@gmail.com> (https://github.com/AIEPhoenix)","homepage":"https://github.com/ai-markdown/ai-markdown/tree/main/packages/engine#readme","repository":{"type":"git","url":"git+https://github.com/ai-markdown/ai-markdown.git","directory":"packages/engine"},"bugs":{"url":"https://github.com/ai-markdown/ai-markdown/issues"},"keywords":["markdown","markdown-parser","ai","llm","streaming","incremental","incremental-parsing","prefix-freeze","latex","katex","math","remark","rehype","unified","hast","mdast","footnotes","sanitize","typescript"],"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":{"import":"./dist/index.d.ts","require":"./dist/index.d.cts"},"development":{"import":"./dist/index.dev.js","require":"./dist/index.dev.cjs"},"import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"peerDependencies":{"katex":"^0.16.0 || ^0.17.0"},"peerDependenciesMeta":{"katex":{"optional":true}},"dependencies":{"@ai-markdown/rehype-raw":"7.0.3","@types/hast":"^3.0.5","@types/mdast":"^4.0.4","devlop":"^1.1.0","html-url-attributes":"^3.0.1","mdast-util-to-hast":"^13.2.1","micromark-util-html-tag-name":"^2.0.1","micromark-util-normalize-identifier":"^2.0.1","micromark-util-sanitize-uri":"^2.0.1","rehype-katex":"^7.0.1","rehype-sanitize":"^6.0.0","rehype-unwrap-images":"^1.0.0","remark-breaks":"^4.0.0","remark-cjk-friendly":"^2.3.1","remark-cjk-friendly-gfm-strikethrough":"^2.3.1","remark-definition-list":"^2.0.0","remark-emoji":"^5.0.2","remark-gfm":"^4.0.1","remark-math":"^6.0.0","remark-pangu":"^2.2.0","remark-parse":"^11.0.0","remark-rehype":"^11.1.2","remark-remove-comments":"^1.1.1","remark-smartypants":"^3.0.3","remark-squeeze-paragraphs":"^6.0.0","remend":"^1.3.1","unified":"^11.0.5","unist-util-visit":"^5.1.0","vfile":"^6.0.3","@ai-markdown/remark-mark-highlight":"^1.0.2"},"devDependencies":{"@stryker-mutator/core":"^9.6.1","@stryker-mutator/vitest-runner":"^9.6.1","@types/lodash-es":"^4.17.12","@types/unist":"^3.0.3","fast-check":"^4.9.0","hast-util-sanitize":"^5.0.2","hastscript":"^9.0.1","lodash-es":"^4.18.0"},"scripts":{"build":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsup && node scripts/assert-dist-clean.mjs && node scripts/collect-bundled-licenses.mjs","test":"vitest --run","typecheck":"tsc --noEmit -p tsconfig.json","fuzz:splice":"vitest --run src/components/incrementalParse/spliceFuzz.test.ts","soak":"../../scripts/soak/soak.sh","soak:watch":"../../scripts/soak/soak-watch.sh","soak:aggregate":"node ../../scripts/soak/soak-aggregate.mjs","soak:coverage":"node ../../scripts/soak/assert-coverage-map.mjs"},"_nodeVersion":"26.0.0","_id":"@ai-markdown/engine@3.0.0","dist":{"integrity":"sha512-FxcnrEn7KJVNE5Qs8af6FONOIafHtsWYo+hRWvxl8kf2wf0jl2vdGMCsT4csf5u0C/GesiXAHaI3/Tjz6WA6lA==","shasum":"a680efc1acb52da36a0c659c9ad42e10bce7b0cb","tarball":"https://registry.npmjs.org/@ai-markdown/engine/-/engine-3.0.0.tgz","fileCount":14,"unpackedSize":11663763,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ai-markdown%2fengine@3.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIG5dvFBCmwcDrJr8jxc4kwsPTwkyiMGh6VsZYgqDpIyLAiBbuMUxob9Bnv+G41dqN08lOF1reb8fOvZJ7VHOdAaKHA=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:501a3298-d58f-44ef-873e-4c428d1bfa8c"}},"directories":{},"maintainers":[{"name":"aiephoenix","email":"aiephoenixbl@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/engine_3.0.0_1789053864517_0.6206529066615059"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-09T04:12:47.151Z","modified":"2026-09-10T15:24:25.134Z","3.0.0-beta.1":"2026-09-09T04:12:47.560Z","3.0.0-beta.2":"2026-09-09T14:07:48.374Z","3.0.0-rc.1":"2026-09-10T15:02:14.047Z","3.0.0":"2026-09-10T15:24:24.773Z"},"bugs":{"url":"https://github.com/ai-markdown/ai-markdown/issues"},"author":"Brian Lee <aiephoenixbl@gmail.com> (https://github.com/AIEPhoenix)","license":"MIT","homepage":"https://github.com/ai-markdown/ai-markdown/tree/main/packages/engine#readme","keywords":["markdown","markdown-parser","ai","llm","streaming","incremental","incremental-parsing","prefix-freeze","latex","katex","math","remark","rehype","unified","hast","mdast","footnotes","sanitize","typescript"],"repository":{"type":"git","url":"git+https://github.com/ai-markdown/ai-markdown.git","directory":"packages/engine"},"description":"Framework-independent Markdown parsing, incremental transforms, preprocessing and document registries for ai-markdown.","maintainers":[{"name":"aiephoenix","email":"aiephoenixbl@gmail.com"}],"readme":"# @ai-markdown/engine\n\n[![@ai-markdown/engine stable](https://img.shields.io/npm/v/@ai-markdown/engine?label=npm&color=blue)](https://www.npmjs.com/package/@ai-markdown/engine?activeTab=versions)\n[![@ai-markdown/engine monthly downloads](https://img.shields.io/npm/dm/@ai-markdown/engine?label=downloads%2Fmonth&color=blue)](https://www.npmjs.com/package/@ai-markdown/engine)\n[![TypeScript declarations included](https://img.shields.io/badge/TypeScript-included-3178c6?logo=typescript&logoColor=white)](https://github.com/ai-markdown/ai-markdown/tree/main/packages/engine)\n[![MIT license](https://img.shields.io/badge/license-MIT-blue)](https://github.com/ai-markdown/ai-markdown/blob/main/LICENSE)\n\n> **3.0.0:** React and Vue adapters share the public `@ai-markdown/core` and `@ai-markdown/engine` packages. See the [migration guide](../../docs/framework-transition.md).\n\n`@ai-markdown/engine` contains the string and syntax-tree processing used by ai-markdown: LaTeX preprocessing, the unified plugin chain, incremental parsing, and shared reference bookkeeping. It has no React dependency. A framework adapter supplies component lifecycle, DOM rendering, context subscriptions, and any presentation such as syntax highlighting.\n\n**This is the algorithm layer for adapter authors.** Shared core, React and Vue consume it at the exact same train version. The public root exports parsing, preprocessing, registry and policy contracts; fixtures and private registry containers are excluded. Public contracts follow semantic versioning from 3.0.0; breaking changes require a new major version. Applications should install `@ai-markdown/react` or `@ai-markdown/vue`; see [Getting started](../../docs/getting-started.md).\n\nThe examples below demonstrate individual entry points. They do not assemble a complete framework adapter: URL transformation, coordinated placeholder rendering, effect timing, and CSS remain the adapter's responsibility.\n\n## What's inside\n\nEverything is exported from the package root (`import { … } from '@ai-markdown/engine'`); the barrel is grouped by layer:\n\n| Layer                    | Modules                                                                                                                                        | Highlights                                                                                                                                                                                                                                                                                     |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Preprocessors            | `preprocessors/latex`, `preprocessors/remend`, `preprocessAIMDContent`                                                                         | `preprocessLaTeX(text)` (currency `$`, `\\[…\\]` / `\\(…\\)` normalization, code-fence and inline-code protection), `createIncrementalLatexPreprocessor()` for append-only streams, `remend` for unterminated-markup mending                                                                       |\n| Incremental parsing      | `incrementalParse/*`                                                                                                                           | `advanceIncrementalParse(state, content, options)` — the prefix-freeze engine: a line scanner decides a verified-safe freeze boundary, only the tail re-parses, and the two trees are spliced; every frame is deep-equal to a full parse (enforced by the arbiter suites) or falls back to one |\n| Pipeline assembly        | `markdown/*`, `pluginChain`, `plugins/catalog`, `customMdastHandlers`, `remarkInjectPhantomDefs`, `rehypeRebaseHashLinks`, `rehypeFooterAdorn` | `buildCoreRemarkPlugins` / `buildCoreRehypePlugins` / `buildCoreRemarkRehypeOptions` — the shared chains used by the React and Vue renderers; the sealed engine-plugin catalog (`highlight`, `definitionList`, `removeComments`, `smartypants`, `pangu`, `defaultEnginePlugins`)               |\n| Cross-chunk coordination | `documentRegistry`, `collectDefLabels`, `extractContributions`, `extractDefBodiesFromHast`, `crossChunkUrlSanitize`                            | `createRegistry()` — the per-document store that numbers footnotes and resolves link definitions across chunks; `sanitizeCrossChunkUrl()` mirrors the standalone two-gate URL policy                                                                                                           |\n| Sanitization             | `sanitizeSchema`, `extendSanitizeSchema`, `markdown/urlTransform`                                                                              | The library default `rehype-sanitize` schema (read-only singleton — clone with `extendSanitizeSchema`), `defaultUrlTransform`                                                                                                                                                                  |\n| Streaming                | `smoothStream/controller`                                                                                                                      | `createSmoothStreamController()` — the framework-agnostic typewriter pacing state machine behind `<AIMarkdownSmoothStream>`, with `SMOOTH_STREAM_PACING_PRESETS`                                                                                                                               |\n| Leaves                   | `hastPredicates`, `normalizeId`, `shortenDocumentId`, `devStageTimings`                                                                        | Small pure helpers; the shared test corpus stays source-only and is not exported                                                                                                                                                                                                               |\n\n## Install\n\n```bash\nnpm install @ai-markdown/engine\n```\n\nDual ESM/CJS build with types for both. ESM keeps pipeline dependencies external. The CJS build bundles ESM-only default-export plugins so Node receives callable plugins and does not try to resolve the import-only `remend` entry through `require`. Bundled third-party licenses ship in `dist/THIRD_PARTY_LICENSES.txt`. No React dependency. The only peer is `katex` (`^0.16 || ^0.17`, **optional** — needed only if you render math). The pipeline also receives KaTeX transitively through `rehype-katex`. If your application imports KaTeX CSS, declare KaTeX directly so the import resolves independently of dependency hoisting. A tree-only consumer does not need to load a browser stylesheet.\n\n## Example: the LaTeX preprocessor on its own\n\n```ts\nimport { preprocessLaTeX } from '@ai-markdown/engine';\n\npreprocessLaTeX('Price is $100, and \\\\(x^2\\\\) is inline math.');\n// → 'Price is \\\\$100, and $$x^2$$ is inline math.'\n// (currency `$` escaped; `\\\\(…\\\\)` normalized to the `$$…$$` form remark-math's inline rule accepts)\n```\n\nThe same function runs inside `@ai-markdown/react` before every parse; the incremental variant (`createIncrementalLatexPreprocessor`) reuses work across append-only frames.\n\n## Example: driving the incremental parser\n\n```ts\nimport {\n  advanceIncrementalParse,\n  buildCoreRemarkPlugins,\n  buildCoreRehypePlugins,\n  buildCoreRemarkRehypeOptions,\n  defaultEnginePlugins,\n  sanitizeSchema,\n  type IncrementalParseState,\n  type AdvanceOptions,\n} from '@ai-markdown/engine';\n\nconst remarkPlugins = buildCoreRemarkPlugins(defaultEnginePlugins);\nconst rehypePlugins = buildCoreRehypePlugins(sanitizeSchema, 'example-user-content-');\nconst remarkRehypeOptions = buildCoreRemarkRehypeOptions(true);\nconst options: AdvanceOptions = {\n  remarkPlugins,\n  rehypePlugins,\n  remarkRehypeOptions,\n  // Keep this key stable until a pipeline input changes.\n  depsKey: [remarkPlugins, rehypePlugins, remarkRehypeOptions],\n  defListEnabled: true, // defaultEnginePlugins includes definitionList.\n};\n\nlet state: IncrementalParseState | null = null;\nfor (const frame of ['# Hello', '# Hello\\n\\nworld', '# Hello\\n\\nworld and more']) {\n  const result = advanceIncrementalParse(state, frame, options);\n  state = result.nextState;\n  // result.hast — the full-document hast for this frame\n  // result.usedIncremental / result.boundary — whether the frame spliced, and where\n}\n```\n\n`AdvanceOptions` is documented in `incrementalParse/advanceIncrementalParse.ts`; the React renderer's `MarkdownContent` is the reference consumer.\n\n## Verification\n\nThe incremental engine ships with a five-layer equivalence stack (fixture pins, fuzz arbiter, direction battery, exhaustive census, arbiter-sensitivity meta-suite) plus a six-leg release-gate soak (`scripts/soak/soak.sh`, with a complete release profile and fresh seed base); the full record lives in `src/experiments/prefixFreeze/README.md`. Every reachable divergence found so far is pinned as a deterministic test.\n\n## Runtime support\n\nPure computation over strings and syntax trees: no DOM access, no\nNode-only APIs, and no unguarded environment reads. Runs in browsers,\nNode, workers, and embedded JS runtimes (e.g. Hermes/JavaScriptCore).\n\n## Versioning\n\nLockstep with `@ai-markdown/react`, which pins this package **exactly** — engine and shared core expose explicit adapter contracts that follow semantic versioning from 3.0.0 (see the status note above). Release notes: [release highlights](https://github.com/ai-markdown/ai-markdown/blob/main/docs/release-highlights.md).\n\n## Package family\n\n| Package                                                                                                  | Role                                                                                                        | Version policy                                            |\n| -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |\n| [`@ai-markdown/core`](https://www.npmjs.com/package/@ai-markdown/core)                                   | Framework-independent sessions, block planning, contributions and smooth coordination                       | Release train; exact engine dependency                    |\n| [`@ai-markdown/react`](https://www.npmjs.com/package/@ai-markdown/react)                                 | The React renderer — `<AIMarkdown>`, `<AIMarkdownSmoothStream>`, `<AIMarkdownDocuments>`, hooks, providers  | Release train                                             |\n| [`@ai-markdown/vue`](https://www.npmjs.com/package/@ai-markdown/vue)                                     | Vue 3.5 renderer — components, scoped slots, SSR/hydration and smooth composables                           | Release train; exact core and engine dependencies         |\n| [`@ai-markdown/react-mantine`](https://www.npmjs.com/package/@ai-markdown/react-mantine)                 | Mantine UI bindings — themed typography, code-highlight tabs, Mermaid, color-scheme wiring                  | Release train; compatible React 3.x peer                  |\n| [`@ai-markdown/engine`](https://www.npmjs.com/package/@ai-markdown/engine)                               | Framework-agnostic engine — incremental parsing, LaTeX preprocessing, plugin pipeline, cross-chunk registry | Release train; pinned exactly by shared core and adapters |\n| [`@ai-markdown/remark-mark-highlight`](https://www.npmjs.com/package/@ai-markdown/remark-mark-highlight) | remark plugin for `==mark==` highlight syntax                                                               | Independent semver                                        |\n\n## Owning incremental state\n\nKeep one parse state per logical input stream. Supply the full current source to `advanceIncrementalParse`, then retain only its returned `nextState` for the next frame. A replacement or a safety-gate failure can select a full parse; `usedIncremental: false` is an expected result, not itself an error. The returned hast still represents the whole current document.\n\nA successful splice depends on both source continuity and pipeline compatibility. If your selected plugins, schema, namespace, or conversion options change, update the dependency key as well. Mutating a plugin array in place while retaining its identity can make a hand-built adapter reuse state under the wrong assumptions. The example creates its pipeline once and enables definition-list handling consistently in both parsing options and plugin selection.\n\n`advanceIncrementalParse` does not implicitly apply every preprocessing convenience exposed by core. Normalize raw input first when you need the core LaTeX behavior, and retain a separate incremental LaTeX preprocessor per stream if using its stateful form. User transforms run on the normalized string in core; reproducing only the parse call is not necessarily equivalent to reproducing the React adapter's entire input pipeline.\n\n## Adapter responsibilities\n\nThe hast tree is an intermediate representation, not finished HTML or React output. The rehype sanitizer runs in the chain, while URL transformation is a later rendering concern. A direct consumer must apply the relevant URL policy to surviving URL attributes and must preserve convergence if it revisits a retained tree.\n\nCross-chunk coordination requires more than creating a registry. Core registers chunks and contributes processed data after commit, subscribes to document and label changes, renders placeholders under the consuming chunk's policy, and emits one aggregate footer. Engine-built private placeholder tags also use a provenance boundary in the shipped pipeline. A hand-assembled chain without the matching credential lifecycle is not a drop-in coordinated renderer.\n\nUse the React adapter as a source-level reference when building another host, and give that host its own lifecycle and equivalence tests. The [architecture guide](../../docs/architecture.md) traces the stage order, while [soak coverage](../../docs/soak-coverage.md) distinguishes a successful oracle comparison from evidence that an optimized path was exercised.\n\n## Repository commands\n\nAfter installing workspace dependencies, build with `pnpm --filter @ai-markdown/engine build` and type-check with `pnpm --filter @ai-markdown/engine typecheck`. The package's `fuzz:splice` command runs the splice property suite; `soak:coverage` validates the coverage map. Development soak runs use the smoke profile, and reused diagnostic seeds are marked as replay runs. Only complete release evidence can establish a release PASS.\n\nThe experimental README preserves the original L0–L4 study and later verification history. Its historical counts and tiers are not substitutes for the current production scanner, coverage map, or release runner configuration.\n\n## License\n\nMIT\n","readmeFilename":""}