@nicomatt69/streamtty
v0.2.0
Published
A drop-in replacement for markdown rendering in TTY, designed for AI-powered streaming with blessed
Downloads
108
Maintainers
Readme
Streamtty
A drop-in replacement for markdown rendering in TTY environments, designed for AI-powered streaming with blessed.
Streamtty is inspired by Streamdown but built specifically for terminal/TTY environments using blessed. It handles the unique challenges of streaming Markdown content from AI models in terminals, providing seamless formatting even with incomplete or unterminated Markdown blocks.
✨ Features
Core Features
- 🚀 Streaming-optimized - Handles incomplete Markdown gracefully during real-time generation
- 🎨 Unterminated block parsing - Styles incomplete bold, italic, code, links, and headings
- 📊 GitHub Flavored Markdown - Tables, task lists, and strikethrough support
- 📝 Rich formatting - Headers, lists, blockquotes, links, and more
- ⚡ Performance optimized - Debounced rendering for efficient updates
- 🎮 Interactive - Built-in keyboard navigation and scrolling
Enhanced Features (Streamdown Parity) ✨ NEW
- 📐 Math Rendering - LaTeX math expressions converted to Unicode (inline and block)
- 📊 Mermaid Diagrams - Flowcharts, sequence diagrams, and more rendered as ASCII art
- 🎨 Shiki Syntax Highlighting - Advanced code highlighting with multiple themes
- 📋 Advanced Tables - Full table support with alignment, borders, and navigation
- 🛡️ Security Layer - ANSI sanitization, input validation, and injection prevention
- ⌨️ Interactive Controls - Copy code, export diagrams, navigate with keyboard shortcuts
- 🔌 Plugin System - Remark/Rehype compatible plugin architecture
- 🎭 Theme Support - Light/dark themes with auto-detection
- 🧩 Component Overrides - Customize rendering for any token type
📦 Installation
npm install streamtty
# or
yarn add streamtty
# or
pnpm add streamttyNote:
blessedis included as a dependency and will be installed automatically.
🚀 Quick Start
Basic Usage
import { Streamtty } from 'streamtty';
const markdown = `
# Hello World
This is **bold** and this is *italic*.
\`\`\`typescript
console.log('Hello, Streamtty!');
\`\`\`
`;
const streamtty = new Streamtty();
streamtty.setContent(markdown);Streaming Usage (AI-like)
import { Streamtty } from 'streamtty';
const streamtty = new Streamtty({
parseIncompleteMarkdown: true,
autoScroll: true,
});
// Simulate AI streaming
const chunks = ['# Hello ', '**World**', '!\n\nThis is ', '`streaming`'];
for (const chunk of chunks) {
streamtty.stream(chunk);
await new Promise(resolve => setTimeout(resolve, 100));
}Interactive Chat Example
import blessed from 'blessed';
import { Streamtty } from 'streamtty';
const screen = blessed.screen({
smartCSR: true,
title: 'AI Chat',
});
const streamtty = new Streamtty({ screen });
// Stream AI response character by character
function streamResponse(response: string) {
let index = 0;
const interval = setInterval(() => {
if (index < response.length) {
streamtty.stream(response[index]);
index++;
} else {
clearInterval(interval);
}
}, 50);
}
streamResponse('# AI Response\n\nHere is some **formatted** text!');Enhanced Features Usage
import { Streamtty } from 'streamtty';
// Enable all enhanced features
const streamtty = new Streamtty({
syntaxHighlight: true,
theme: 'dark',
shikiLanguages: ['typescript', 'python', 'bash'],
enhancedFeatures: {
math: true, // LaTeX math rendering
mermaid: true, // Mermaid diagrams
shiki: true, // Advanced syntax highlighting
security: true, // ANSI sanitization & validation
interactiveControls: true, // Keyboard shortcuts
advancedTables: true, // Enhanced table rendering
},
controls: {
code: true, // Press 'c' to copy code blocks
table: true, // Arrow keys to navigate tables
mermaid: true, // Press 'e' to export diagrams
math: true, // Copy math expressions
},
security: {
enabled: true,
stripDangerousAnsi: true,
allowedLinkPrefixes: ['https://'],
},
});
// Math rendering
const mathContent = `
Inline math: $E = mc^2$
Block math:
$$
\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}
$$
`;
streamtty.setContent(mathContent);
// Mermaid diagrams
const diagramContent = `
\`\`\`mermaid
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Success]
B -->|No| D[Retry]
\`\`\`
`;
streamtty.stream(diagramContent);
// Advanced tables
const tableContent = `
| Feature | Status | Priority |
|---------|:------:|----------|
| Math | ✅ | High |
| Mermaid | ✅ | High |
| Tables | ✅ | Medium |
`;
streamtty.stream(tableContent);Plugin System
import { Streamtty, RemarkPlugin, RehypePlugin } from 'streamtty';
// Custom remark plugin (pre-parse)
const customRemarkPlugin: RemarkPlugin = {
name: 'custom-remark',
type: 'remark',
priority: 50,
async process(markdown, context) {
// Transform markdown before parsing
return markdown.replace(/TODO:/g, '📝 TODO:');
},
};
// Custom rehype plugin (post-parse)
const customRehypePlugin: RehypePlugin = {
name: 'custom-rehype',
type: 'rehype',
priority: 50,
async process(tokens, context) {
// Transform tokens after parsing
return tokens.map(token => {
if (token.type === 'text' && token.content.includes('IMPORTANT')) {
token.style = { fg: 'red', bold: true };
}
return token;
});
},
};
const streamtty = new Streamtty({
remarkPlugins: [customRemarkPlugin],
rehypePlugins: [customRehypePlugin],
});📖 API Reference
Streamtty
Main class for rendering streamed markdown in TTY.
Constructor Options
interface StreamttyOptions {
parseIncompleteMarkdown?: boolean; // Default: true
styles?: Partial<MarkdownStyles>;
syntaxHighlight?: boolean; // Default: true
showLineNumbers?: boolean; // Default: false
maxWidth?: number; // Default: 120
gfm?: boolean; // Default: true
screen?: Widgets.Screen; // Custom blessed screen
autoScroll?: boolean; // Default: true
}Methods
stream(chunk: string): void
Stream a chunk of markdown content. Handles incomplete markdown gracefully.
streamtty.stream('# Hello ');
streamtty.stream('**World**');setContent(markdown: string): void
Set complete markdown content all at once.
streamtty.setContent('# Complete Document\n\nWith **multiple** paragraphs.');render(): void
Manually trigger a render. Usually not needed as rendering is automatic.
clear(): void
Clear all content from the display.
streamtty.clear();startAutoRender(intervalMs?: number): void
Start auto-rendering at specified interval (default: 50ms).
stopAutoRender(): void
Stop auto-rendering.
getScreen(): Widgets.Screen
Get the blessed screen instance.
getContainer(): Widgets.BoxElement
Get the blessed container box.
getContent(): string
Get current buffer content.
destroy(): void
Cleanup and destroy the instance.
🎨 Styling
Streamtty uses blessed's styling system. You can customize styles for different markdown elements:
const streamtty = new Streamtty({
styles: {
h1: { fg: 'cyan', bold: true },
h2: { fg: 'blue', bold: true },
code: { fg: 'green', bold: true },
codeBlock: { fg: 'white', bg: 'black' },
blockquote: { fg: 'gray', italic: true },
link: { fg: 'blue', underline: true },
},
});⌨️ Keyboard Shortcuts
Built-in keyboard navigation:
↑/k- Scroll up↓/j- Scroll downPage Up- Scroll up one pagePage Down- Scroll down one pageHome/g- Go to topEnd/G- Go to bottomEscape/q/Ctrl+C- Exit
📚 Examples
Check out the examples/ directory for complete examples:
Basic Example
yarn tsx examples/basic.tsShows static markdown rendering with various elements.
Streaming Example
yarn tsx examples/streaming.tsSimulates AI-like streaming of markdown content.
Chat Example
yarn tsx examples/chat.tsInteractive chat interface with streaming AI responses.
🔧 Development
# Install dependencies
yarn install
# Build
yarn build
# Watch mode
yarn dev
# Run examples
yarn example:basic
yarn example:streaming
yarn example:chat📝 Markdown Support
Streamtty supports a wide range of markdown features:
Basic Formatting
- Bold:
**text**or__text__ - Italic:
*text*or_text_ Inline code:`code`- ~~Strikethrough~~:
~~text~~
Headers
# H1
## H2
### H3
#### H4
##### H5
###### H6Lists
- Unordered list
- Items
1. Ordered list
2. ItemsCode Blocks
```typescript
function hello(): void {
console.log('Hello!');
}
```Blockquotes
> This is a blockquote
> Multiple lines supportedLinks
[Link text](https://example.com)Tables
| Column 1 | Column 2 |
|----------|----------|
| Data 1 | Data 2 |Horizontal Rules
---Task Lists
- [x] Completed task
- [ ] Pending task🆚 Streamdown vs Streamtty
| Feature | Streamdown | Streamtty | |---------|-----------|-----------| | Environment | React / Web | TTY / Terminal | | Rendering | React Components | Blessed Widgets | | Output | HTML/JSX | ANSI/Terminal | | Use Case | Web Apps | CLI Tools / TUIs | | Dependencies | React, ReactDOM | Blessed, Marked |
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT © [Your Name]
🙏 Credits
- Inspired by Streamdown by Vercel
- Built with blessed
- Markdown parsing by marked
🔗 Links
- Streamdown - The web/React version
- blessed - Terminal UI library
- marked - Markdown parser
Made with ❤️ for the terminal
