paratext
Coming from…

Coming from ansi-escapes

An ansi-escapes alternative with a drop-in path: import ansiEscapes from paratext, graded 4 / 4 by ansi-escapes' own test suite — then hyperlinks, images and the working directory that project to plain text for pipes and agents instead of raw escape bytes.

paratext is an ansi-escapes alternative you adopt by changing one import. The package root is ansi-escapes 7's surface — the CSI half that moves the cursor and erases the screen, and the OSC half that talks to the terminal program — and ansi-escapes' own test suite is the grade.

Migrate from ansi-escapes in one import

- import ansiEscapes, { cursorTo, eraseLines, link, image, beep } from 'ansi-escapes';
+ import ansiEscapes, { cursorTo, eraseLines, link, image, beep } from 'paratext';

Everything else stays. The CSI half — cursorTo, cursorMove, the cursor, erase and scroll members, clearScreen, clearTerminal, the alternate screen and synchronized output — is byte-exact with ansi-escapes 7.3.0, including the Terminal.app spelling of save and restore. It does not degrade, because the incumbent's does not: a cursor move silently dropped would corrupt the screen of a program that relied on it.

The OSC half — link, image, setCwd and beep — gives the incumbent's exact bytes on a terminal believed to understand them, and a static projection everywhere else. That is the one deliberate difference, and it is covered under what you gain.

Two names are declared and empty: iTerm and ConEmu. ansi-escapes hangs iTerm.setCwd, iTerm.annotation and ConEmu.setCwd off them, and paratext does not yet; importing them loads, and calling a member is a TypeScript compile error rather than a surprise at run time. The top-level setCwd carries both terminals' working-directory sequences, so only iTerm.annotation has no replacement — keep ansi-escapes for that call.

Is paratext compatible with ansi-escapes?

Graded, not claimed. ansi-escapes' own suite, vendored at 7.3.0 and unmodified apart from the import specifier, runs against paratext beside a control that runs it against real ansi-escapes:

passingrate
paratext4 / 4100.0%
ansi-escapes itself (control)4 / 4100.0%

From Compatibility, which npm run compat:page generates from the oracle's last run; that page is the authority. The suite is small — four cases — and three of them assert CSI: default export and clearTerminal check the cursor and clear sequences, and synchronized output checks ESC [ ? 2026 h and l. The fourth, named export(s), checks that a named export and the default's member are the same object. Until paratext implemented the CSI half, this row was 1 / 4. The same page grades the paratext/terminal-link and paratext/term-img paths against those packages' suites.

What you gain over ansi-escapes

No terminal answers "do you support OSC 1337", so emitting the bytes and hoping is what puts \u001B]1337;File=inline=1;… across the screen of anyone who piped your output to a file. paratext never hopes:

  • Every capability has a static projection. emit() returns it whenever support is absent or unknown: an image becomes its caption, a notification a printed line, a hyperlink text (url). On a pipe, that projection is what an agent reads.
  • The fallback is required. A capability without one is refused at registration; there is no opt-out.
  • A capability is data. Plain objects, no functions, so a capability travels through JSON, is diffable, and is validated against paratext/schema.json without running its author's code.
import { emit, processRuntime } from 'paratext';

emit(processRuntime(), 'link', { text: 'Docs', url: 'https://x.dev' });
// a terminal that supports it: the OSC 8 hyperlink
// a pipe:                      Docs (https://x.dev)

When to switch from ansi-escapes

  • Your CLI emits hyperlinks, images or notifications, and its output is ever piped, logged or read by an agent.
  • You want new terminal capabilities registered as data rather than waiting for a release.

If your program depends on an OSC sequence reaching a pipe byte for byte, keep ansi-escapes for that call. The registry, the schema and the plugin host are on paratext.

On this page