
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
A drop-in replacement for markdown rendering in TTY, designed for AI-powered streaming with blessed
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.
npm install streamtty
# or
yarn add streamtty
# or
pnpm add streamtty
Note:
blessedis included as a dependency and will be installed automatically.
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);
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));
}
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!');
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);
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],
});
StreamttyMain class for rendering streamed markdown in TTY.
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
}
stream(chunk: string): voidStream a chunk of markdown content. Handles incomplete markdown gracefully.
streamtty.stream('# Hello ');
streamtty.stream('**World**');
setContent(markdown: string): voidSet complete markdown content all at once.
streamtty.setContent('# Complete Document\n\nWith **multiple** paragraphs.');
render(): voidManually trigger a render. Usually not needed as rendering is automatic.
clear(): voidClear all content from the display.
streamtty.clear();
startAutoRender(intervalMs?: number): voidStart auto-rendering at specified interval (default: 50ms).
stopAutoRender(): voidStop auto-rendering.
getScreen(): Widgets.ScreenGet the blessed screen instance.
getContainer(): Widgets.BoxElementGet the blessed container box.
getContent(): stringGet current buffer content.
destroy(): voidCleanup and destroy the instance.
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 },
},
});
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 - ExitCheck out the examples/ directory for complete examples:
yarn tsx examples/basic.ts
Shows static markdown rendering with various elements.
yarn tsx examples/streaming.ts
Simulates AI-like streaming of markdown content.
yarn tsx examples/chat.ts
Interactive chat interface with streaming AI responses.
# Install dependencies
yarn install
# Build
yarn build
# Watch mode
yarn dev
# Run examples
yarn example:basic
yarn example:streaming
yarn example:chat
Streamtty supports a wide range of markdown features:
**text** or __text__*text* or _text_Inline code: `code`~~text~~# H1
## H2
### H3
#### H4
##### H5
###### H6
- Unordered list
- Items
1. Ordered list
2. Items
```typescript
function hello(): void {
console.log('Hello!');
}
```
> This is a blockquote
> Multiple lines supported
[Link text](https://example.com)
| Column 1 | Column 2 |
|----------|----------|
| Data 1 | Data 2 |
---
- [x] Completed task
- [ ] Pending task
| 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 |
Contributions are welcome! Please feel free to submit a Pull Request.
MIT © [Your Name]
Made with ❤️ for the terminal
FAQs
A drop-in replacement for markdown rendering in TTY, designed for AI-powered streaming with blessed
We found that streamtty demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.