claude-stream 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_stream-0.1.0/.gitignore +1 -0
- claude_stream-0.1.0/LICENSE +13 -0
- claude_stream-0.1.0/PKG-INFO +141 -0
- claude_stream-0.1.0/README.md +113 -0
- claude_stream-0.1.0/pyproject.toml +44 -0
- claude_stream-0.1.0/src/claude_stream/__init__.py +158 -0
- claude_stream-0.1.0/src/claude_stream/__main__.py +14 -0
- claude_stream-0.1.0/src/claude_stream/blocks.py +115 -0
- claude_stream-0.1.0/src/claude_stream/cli.py +269 -0
- claude_stream-0.1.0/src/claude_stream/formatters.py +243 -0
- claude_stream-0.1.0/src/claude_stream/models.py +869 -0
- claude_stream-0.1.0/src/claude_stream/stream.py +121 -0
- claude_stream-0.1.0/src/claude_stream/watcher.py +217 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__pycache__/
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
2
|
+
Version 2, December 2004
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
|
5
|
+
|
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
|
7
|
+
copies of this license document, and changing it is allowed as long
|
|
8
|
+
as the name is changed.
|
|
9
|
+
|
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
12
|
+
|
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-stream
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Parse and prettify Claude Code JSONL stream output
|
|
5
|
+
Project-URL: Homepage, https://github.com/shitchell/claude-stream
|
|
6
|
+
Project-URL: Repository, https://github.com/shitchell/claude-stream
|
|
7
|
+
Project-URL: Issues, https://github.com/shitchell/claude-stream/issues
|
|
8
|
+
Author: Shaun Mitchell
|
|
9
|
+
License-Expression: WTFPL
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: anthropic,claude,cli,jsonl,stream
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: Public Domain
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: pydantic>=2.0
|
|
24
|
+
Requires-Dist: typing-extensions>=4.0
|
|
25
|
+
Provides-Extra: watch
|
|
26
|
+
Requires-Dist: watchdog>=3.0; extra == 'watch'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# claude-stream
|
|
30
|
+
|
|
31
|
+
Parse and prettify Claude Code JSONL stream output.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install claude-stream
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For file watching support:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install "claude-stream[watch]"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Read from a file
|
|
49
|
+
claude-stream session.jsonl
|
|
50
|
+
|
|
51
|
+
# Show only last N lines
|
|
52
|
+
claude-stream session.jsonl -n 20
|
|
53
|
+
|
|
54
|
+
# Read from stdin
|
|
55
|
+
cat session.jsonl | claude-stream
|
|
56
|
+
|
|
57
|
+
# Parse the most recent session
|
|
58
|
+
claude-stream --latest
|
|
59
|
+
claude-stream --latest -n 50 # Last 50 lines
|
|
60
|
+
|
|
61
|
+
# Find and parse a session by UUID
|
|
62
|
+
claude-stream --session abc123
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Watch Mode
|
|
66
|
+
|
|
67
|
+
Watch for new messages in real-time (like `tail -f`):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Watch all Claude sessions
|
|
71
|
+
claude-stream --watch ~/.claude/projects/
|
|
72
|
+
|
|
73
|
+
# Watch from any project directory (auto-resolves to Claude path)
|
|
74
|
+
claude-stream --watch .
|
|
75
|
+
claude-stream --watch ~/myproject
|
|
76
|
+
|
|
77
|
+
# Watch with initial context (last N lines)
|
|
78
|
+
claude-stream --watch . -n 10
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
When given a directory outside `~/.claude`, the path is automatically
|
|
82
|
+
converted to Claude's project format (e.g., `/home/user/project` becomes
|
|
83
|
+
`~/.claude/projects/-home-user-project`).
|
|
84
|
+
|
|
85
|
+
### Output Formats
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# ANSI terminal colors (default)
|
|
89
|
+
claude-stream --format ansi session.jsonl
|
|
90
|
+
|
|
91
|
+
# Markdown
|
|
92
|
+
claude-stream --format markdown session.jsonl > export.md
|
|
93
|
+
|
|
94
|
+
# Plain text
|
|
95
|
+
claude-stream --format plain session.jsonl
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Filtering
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Show only specific message types
|
|
102
|
+
claude-stream --show-type assistant --show-type user session.jsonl
|
|
103
|
+
|
|
104
|
+
# Show only messages with specific tools
|
|
105
|
+
claude-stream --show-tool Bash --show-tool Read session.jsonl
|
|
106
|
+
|
|
107
|
+
# Grep for patterns
|
|
108
|
+
claude-stream --grep "error" session.jsonl
|
|
109
|
+
|
|
110
|
+
# Exclude patterns
|
|
111
|
+
claude-stream --exclude "thinking" session.jsonl
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Display Options
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Hide thinking blocks
|
|
118
|
+
claude-stream --hide-thinking session.jsonl
|
|
119
|
+
|
|
120
|
+
# Hide tool results
|
|
121
|
+
claude-stream --hide-tool-results session.jsonl
|
|
122
|
+
|
|
123
|
+
# Show metadata (UUIDs, timestamps)
|
|
124
|
+
claude-stream --show-metadata session.jsonl
|
|
125
|
+
|
|
126
|
+
# Compact mode (hide thinking, tool results, metadata)
|
|
127
|
+
claude-stream --compact session.jsonl
|
|
128
|
+
|
|
129
|
+
# Show line numbers
|
|
130
|
+
claude-stream --line-numbers session.jsonl
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Architecture
|
|
134
|
+
|
|
135
|
+
- **Pydantic models** parse JSON into typed message structures
|
|
136
|
+
- **Messages** produce `RenderBlock` lists (flexible rendering primitives)
|
|
137
|
+
- **Formatters** convert `RenderBlocks` to output formats (ANSI, Markdown, Plain)
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
[WTFPL](http://www.wtfpl.net/)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# claude-stream
|
|
2
|
+
|
|
3
|
+
Parse and prettify Claude Code JSONL stream output.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install claude-stream
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For file watching support:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install "claude-stream[watch]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Read from a file
|
|
21
|
+
claude-stream session.jsonl
|
|
22
|
+
|
|
23
|
+
# Show only last N lines
|
|
24
|
+
claude-stream session.jsonl -n 20
|
|
25
|
+
|
|
26
|
+
# Read from stdin
|
|
27
|
+
cat session.jsonl | claude-stream
|
|
28
|
+
|
|
29
|
+
# Parse the most recent session
|
|
30
|
+
claude-stream --latest
|
|
31
|
+
claude-stream --latest -n 50 # Last 50 lines
|
|
32
|
+
|
|
33
|
+
# Find and parse a session by UUID
|
|
34
|
+
claude-stream --session abc123
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Watch Mode
|
|
38
|
+
|
|
39
|
+
Watch for new messages in real-time (like `tail -f`):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Watch all Claude sessions
|
|
43
|
+
claude-stream --watch ~/.claude/projects/
|
|
44
|
+
|
|
45
|
+
# Watch from any project directory (auto-resolves to Claude path)
|
|
46
|
+
claude-stream --watch .
|
|
47
|
+
claude-stream --watch ~/myproject
|
|
48
|
+
|
|
49
|
+
# Watch with initial context (last N lines)
|
|
50
|
+
claude-stream --watch . -n 10
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
When given a directory outside `~/.claude`, the path is automatically
|
|
54
|
+
converted to Claude's project format (e.g., `/home/user/project` becomes
|
|
55
|
+
`~/.claude/projects/-home-user-project`).
|
|
56
|
+
|
|
57
|
+
### Output Formats
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# ANSI terminal colors (default)
|
|
61
|
+
claude-stream --format ansi session.jsonl
|
|
62
|
+
|
|
63
|
+
# Markdown
|
|
64
|
+
claude-stream --format markdown session.jsonl > export.md
|
|
65
|
+
|
|
66
|
+
# Plain text
|
|
67
|
+
claude-stream --format plain session.jsonl
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Filtering
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Show only specific message types
|
|
74
|
+
claude-stream --show-type assistant --show-type user session.jsonl
|
|
75
|
+
|
|
76
|
+
# Show only messages with specific tools
|
|
77
|
+
claude-stream --show-tool Bash --show-tool Read session.jsonl
|
|
78
|
+
|
|
79
|
+
# Grep for patterns
|
|
80
|
+
claude-stream --grep "error" session.jsonl
|
|
81
|
+
|
|
82
|
+
# Exclude patterns
|
|
83
|
+
claude-stream --exclude "thinking" session.jsonl
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Display Options
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Hide thinking blocks
|
|
90
|
+
claude-stream --hide-thinking session.jsonl
|
|
91
|
+
|
|
92
|
+
# Hide tool results
|
|
93
|
+
claude-stream --hide-tool-results session.jsonl
|
|
94
|
+
|
|
95
|
+
# Show metadata (UUIDs, timestamps)
|
|
96
|
+
claude-stream --show-metadata session.jsonl
|
|
97
|
+
|
|
98
|
+
# Compact mode (hide thinking, tool results, metadata)
|
|
99
|
+
claude-stream --compact session.jsonl
|
|
100
|
+
|
|
101
|
+
# Show line numbers
|
|
102
|
+
claude-stream --line-numbers session.jsonl
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Architecture
|
|
106
|
+
|
|
107
|
+
- **Pydantic models** parse JSON into typed message structures
|
|
108
|
+
- **Messages** produce `RenderBlock` lists (flexible rendering primitives)
|
|
109
|
+
- **Formatters** convert `RenderBlocks` to output formats (ANSI, Markdown, Plain)
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
[WTFPL](http://www.wtfpl.net/)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "claude-stream"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Parse and prettify Claude Code JSONL stream output"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "WTFPL"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Shaun Mitchell" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["claude", "anthropic", "jsonl", "cli", "stream"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: Public Domain",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"pydantic>=2.0",
|
|
30
|
+
"typing_extensions>=4.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
watch = [
|
|
35
|
+
"watchdog>=3.0",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
claude-stream = "claude_stream.cli:main"
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/shitchell/claude-stream"
|
|
43
|
+
Repository = "https://github.com/shitchell/claude-stream"
|
|
44
|
+
Issues = "https://github.com/shitchell/claude-stream/issues"
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Parse and prettify Claude Code JSONL stream output.
|
|
3
|
+
|
|
4
|
+
Architecture:
|
|
5
|
+
- Pydantic models parse JSON into typed message structures
|
|
6
|
+
- Messages produce RenderBlock lists (flexible rendering primitives)
|
|
7
|
+
- Formatters convert RenderBlocks to output formats (ANSI, Markdown, Plain)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
# Block types and Style enum
|
|
13
|
+
from .blocks import (
|
|
14
|
+
AnyBlock,
|
|
15
|
+
CodeBlock,
|
|
16
|
+
DividerBlock,
|
|
17
|
+
HeaderBlock,
|
|
18
|
+
KeyValueBlock,
|
|
19
|
+
ListBlock,
|
|
20
|
+
NestedBlock,
|
|
21
|
+
RenderBlock,
|
|
22
|
+
SpacerBlock,
|
|
23
|
+
Style,
|
|
24
|
+
TextBlock,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Formatters
|
|
28
|
+
from .formatters import (
|
|
29
|
+
ANSIFormatter,
|
|
30
|
+
Formatter,
|
|
31
|
+
MarkdownFormatter,
|
|
32
|
+
PlainFormatter,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Models, TypedDicts, and parse_message
|
|
36
|
+
from .models import (
|
|
37
|
+
# TypedDicts
|
|
38
|
+
CompactMetadata,
|
|
39
|
+
ContentItem,
|
|
40
|
+
ImageContentItem,
|
|
41
|
+
ImageSourceInfo,
|
|
42
|
+
TextContentItem,
|
|
43
|
+
ThinkingContentItem,
|
|
44
|
+
ToolResultContentItem,
|
|
45
|
+
ToolResultContentValue,
|
|
46
|
+
ToolResultImageItem,
|
|
47
|
+
ToolResultTextItem,
|
|
48
|
+
ToolUseContentItem,
|
|
49
|
+
UsageInfo,
|
|
50
|
+
# Content block models
|
|
51
|
+
ContentBlock,
|
|
52
|
+
ImageContent,
|
|
53
|
+
TextContent,
|
|
54
|
+
ThinkingContent,
|
|
55
|
+
ToolResultContent,
|
|
56
|
+
ToolUseContent,
|
|
57
|
+
# Message models
|
|
58
|
+
AgentStyleMessage,
|
|
59
|
+
AssistantMessage,
|
|
60
|
+
BaseMessage,
|
|
61
|
+
FileHistorySnapshot,
|
|
62
|
+
QueueOperationMessage,
|
|
63
|
+
ResultMessage,
|
|
64
|
+
SummaryMessage,
|
|
65
|
+
SystemMessage,
|
|
66
|
+
SystemStyleMessage,
|
|
67
|
+
UserMessage,
|
|
68
|
+
# Discriminated union and parser
|
|
69
|
+
Message,
|
|
70
|
+
parse_message,
|
|
71
|
+
# Config
|
|
72
|
+
RenderConfig,
|
|
73
|
+
# Constants
|
|
74
|
+
TOOL_INPUT_TRUNCATE_LENGTH,
|
|
75
|
+
TOOL_RESULT_PREVIEW_LINES,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Stream processing
|
|
79
|
+
from .stream import (
|
|
80
|
+
process_stream,
|
|
81
|
+
should_show_message,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# File watching
|
|
85
|
+
from .watcher import (
|
|
86
|
+
FileWatcher,
|
|
87
|
+
WATCHDOG_AVAILABLE,
|
|
88
|
+
watch_path,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Conditionally export JSONLEventHandler if watchdog is available
|
|
92
|
+
if WATCHDOG_AVAILABLE:
|
|
93
|
+
from .watcher import JSONLEventHandler
|
|
94
|
+
|
|
95
|
+
__all__ = [
|
|
96
|
+
# Blocks
|
|
97
|
+
"AnyBlock",
|
|
98
|
+
"CodeBlock",
|
|
99
|
+
"DividerBlock",
|
|
100
|
+
"HeaderBlock",
|
|
101
|
+
"KeyValueBlock",
|
|
102
|
+
"ListBlock",
|
|
103
|
+
"NestedBlock",
|
|
104
|
+
"RenderBlock",
|
|
105
|
+
"SpacerBlock",
|
|
106
|
+
"Style",
|
|
107
|
+
"TextBlock",
|
|
108
|
+
# Formatters
|
|
109
|
+
"ANSIFormatter",
|
|
110
|
+
"Formatter",
|
|
111
|
+
"MarkdownFormatter",
|
|
112
|
+
"PlainFormatter",
|
|
113
|
+
# TypedDicts
|
|
114
|
+
"CompactMetadata",
|
|
115
|
+
"ContentItem",
|
|
116
|
+
"ImageContentItem",
|
|
117
|
+
"ImageSourceInfo",
|
|
118
|
+
"TextContentItem",
|
|
119
|
+
"ThinkingContentItem",
|
|
120
|
+
"ToolResultContentItem",
|
|
121
|
+
"ToolResultContentValue",
|
|
122
|
+
"ToolResultImageItem",
|
|
123
|
+
"ToolResultTextItem",
|
|
124
|
+
"ToolUseContentItem",
|
|
125
|
+
"UsageInfo",
|
|
126
|
+
# Content blocks
|
|
127
|
+
"ContentBlock",
|
|
128
|
+
"ImageContent",
|
|
129
|
+
"TextContent",
|
|
130
|
+
"ThinkingContent",
|
|
131
|
+
"ToolResultContent",
|
|
132
|
+
"ToolUseContent",
|
|
133
|
+
# Messages
|
|
134
|
+
"AgentStyleMessage",
|
|
135
|
+
"AssistantMessage",
|
|
136
|
+
"BaseMessage",
|
|
137
|
+
"FileHistorySnapshot",
|
|
138
|
+
"Message",
|
|
139
|
+
"QueueOperationMessage",
|
|
140
|
+
"ResultMessage",
|
|
141
|
+
"SummaryMessage",
|
|
142
|
+
"SystemMessage",
|
|
143
|
+
"SystemStyleMessage",
|
|
144
|
+
"UserMessage",
|
|
145
|
+
# Config and parsing
|
|
146
|
+
"RenderConfig",
|
|
147
|
+
"parse_message",
|
|
148
|
+
# Constants
|
|
149
|
+
"TOOL_INPUT_TRUNCATE_LENGTH",
|
|
150
|
+
"TOOL_RESULT_PREVIEW_LINES",
|
|
151
|
+
# Stream processing
|
|
152
|
+
"process_stream",
|
|
153
|
+
"should_show_message",
|
|
154
|
+
# Watcher
|
|
155
|
+
"FileWatcher",
|
|
156
|
+
"WATCHDOG_AVAILABLE",
|
|
157
|
+
"watch_path",
|
|
158
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Allow running as `python -m claude_stream`."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from .cli import main
|
|
6
|
+
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
exit_code: int = 0
|
|
9
|
+
try:
|
|
10
|
+
exit_code = main()
|
|
11
|
+
except KeyboardInterrupt:
|
|
12
|
+
print("\nexiting", file=sys.stderr)
|
|
13
|
+
|
|
14
|
+
sys.exit(exit_code)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Render block types for flexible output rendering.
|
|
2
|
+
|
|
3
|
+
This module defines the Style enum and all RenderBlock dataclasses used
|
|
4
|
+
as rendering primitives throughout the library.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from enum import Enum
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Style(Enum):
|
|
14
|
+
"""Style hints for rendering."""
|
|
15
|
+
|
|
16
|
+
# Text styles
|
|
17
|
+
BOLD = "bold"
|
|
18
|
+
DIM = "dim"
|
|
19
|
+
ITALIC = "italic"
|
|
20
|
+
|
|
21
|
+
# Semantic styles
|
|
22
|
+
ERROR = "error"
|
|
23
|
+
SUCCESS = "success"
|
|
24
|
+
WARNING = "warning"
|
|
25
|
+
INFO = "info"
|
|
26
|
+
|
|
27
|
+
# Role styles
|
|
28
|
+
USER = "user"
|
|
29
|
+
ASSISTANT = "assistant"
|
|
30
|
+
SYSTEM = "system"
|
|
31
|
+
TOOL = "tool"
|
|
32
|
+
THINKING = "thinking"
|
|
33
|
+
METADATA = "metadata"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class RenderBlock:
|
|
38
|
+
"""Base class for rendering primitives."""
|
|
39
|
+
|
|
40
|
+
styles: set[Style] = field(default_factory=set)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class HeaderBlock(RenderBlock):
|
|
45
|
+
"""A header/title block."""
|
|
46
|
+
|
|
47
|
+
text: str = ""
|
|
48
|
+
level: int = 1 # 1 = top level, 2 = subheader, etc.
|
|
49
|
+
icon: str = "" # Optional prefix icon
|
|
50
|
+
prefix: str = "" # Optional prefix text (e.g., "Summary:", "Tool:")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class TextBlock(RenderBlock):
|
|
55
|
+
"""Plain text content."""
|
|
56
|
+
|
|
57
|
+
text: str = ""
|
|
58
|
+
indent: int = 0 # Indentation level
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class CodeBlock(RenderBlock):
|
|
63
|
+
"""Code or preformatted content."""
|
|
64
|
+
|
|
65
|
+
content: str = ""
|
|
66
|
+
language: str = ""
|
|
67
|
+
indent: int = 0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class KeyValueBlock(RenderBlock):
|
|
72
|
+
"""Key-value pair."""
|
|
73
|
+
|
|
74
|
+
key: str = ""
|
|
75
|
+
value: str = ""
|
|
76
|
+
indent: int = 0
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class DividerBlock(RenderBlock):
|
|
81
|
+
"""Visual separator."""
|
|
82
|
+
|
|
83
|
+
char: str = "─"
|
|
84
|
+
width: int = 40
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class ListBlock(RenderBlock):
|
|
89
|
+
"""A list of items."""
|
|
90
|
+
|
|
91
|
+
items: list[str] = field(default_factory=list)
|
|
92
|
+
indent: int = 0
|
|
93
|
+
bullet: str = "*"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class NestedBlock(RenderBlock):
|
|
98
|
+
"""Container for nested blocks."""
|
|
99
|
+
|
|
100
|
+
children: list[RenderBlock] = field(default_factory=list)
|
|
101
|
+
indent: int = 0
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass
|
|
105
|
+
class SpacerBlock(RenderBlock):
|
|
106
|
+
"""Vertical space."""
|
|
107
|
+
|
|
108
|
+
lines: int = 1
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# Type alias for any render block
|
|
112
|
+
AnyBlock = (
|
|
113
|
+
HeaderBlock | TextBlock | CodeBlock | KeyValueBlock |
|
|
114
|
+
DividerBlock | ListBlock | NestedBlock | SpacerBlock
|
|
115
|
+
)
|