llmd 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/client.js +1 -0
- package/dist/llmd +735 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 llmd contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# llmd
|
|
2
|
+
|
|
3
|
+
**Serve Markdown as beautiful HTML. Instantly.**
|
|
4
|
+
|
|
5
|
+
A zero-config CLI tool for viewing Markdown files in your browser with syntax highlighting, live reload, and a clean interface. Built for developers reviewing LLM-generated documentation.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
██╗ ██╗ ███╗ ███╗██████╗
|
|
9
|
+
██║ ██║ ████╗ ████║██╔══██╗
|
|
10
|
+
██║ ██║ ██╔████╔██║██║ ██║
|
|
11
|
+
██║ ██║ ██║╚██╔╝██║██║ ██║
|
|
12
|
+
███████╗███████╗██║ ╚═╝ ██║██████╔╝
|
|
13
|
+
╚══════╝╚══════╝╚═╝ ╚═╝╚═════╝
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Zero config** - Point at a directory and go
|
|
19
|
+
- **Syntax highlighting** - Powered by Shiki
|
|
20
|
+
- **Live reload** - Watch mode reloads on file changes
|
|
21
|
+
- **Copy buttons** - One-click code copying
|
|
22
|
+
- **Dark/light themes** - With 3 font options
|
|
23
|
+
- **Fast** - Built with Bun, instant startup
|
|
24
|
+
- **Sidebar navigation** - Browse files with directory structure
|
|
25
|
+
- **Table of contents** - Auto-generated from headings
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
### npm (Recommended)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g llmd
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or run directly without installing:
|
|
36
|
+
```bash
|
|
37
|
+
npx llmd
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Requires Node.js 22 or later.
|
|
41
|
+
|
|
42
|
+
### From Source
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git clone https://github.com/pbzona/llmd.git
|
|
46
|
+
cd llmd
|
|
47
|
+
bun install
|
|
48
|
+
bun run build:npm
|
|
49
|
+
npm install -g .
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Serve current directory
|
|
56
|
+
llmd
|
|
57
|
+
|
|
58
|
+
# Serve specific directory
|
|
59
|
+
llmd ./docs
|
|
60
|
+
|
|
61
|
+
# Dark mode with live reload
|
|
62
|
+
llmd ./docs --theme dark --watch
|
|
63
|
+
|
|
64
|
+
# Custom port
|
|
65
|
+
llmd ./docs --port 8080
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Font Combinations
|
|
69
|
+
|
|
70
|
+
llmd includes 9 built-in font combinations:
|
|
71
|
+
|
|
72
|
+
- **serif** - System serif fonts (Georgia, Times)
|
|
73
|
+
- **sans** - System sans-serif fonts (default)
|
|
74
|
+
- **mono** - System monospace fonts
|
|
75
|
+
- **classic** - Baskerville headings + Geist body
|
|
76
|
+
- **future** - Space Mono headings + Space Grotesk body
|
|
77
|
+
- **modern** - Inter throughout + JetBrains Mono
|
|
78
|
+
- **artsy** - Playfair Display + Fira Code
|
|
79
|
+
- **literary** - Spectral headings + Newsreader body
|
|
80
|
+
- **editorial** - Bitter headings + Lora body
|
|
81
|
+
|
|
82
|
+
All custom fonts are loaded from Google Fonts CDN for fast, reliable delivery.
|
|
83
|
+
|
|
84
|
+
### Custom Fonts
|
|
85
|
+
|
|
86
|
+
Create custom font combinations in your `themes.json` config file.
|
|
87
|
+
|
|
88
|
+
**Location:** `~/.config/llmd/themes.json` (or `$XDG_CONFIG_HOME/llmd/themes.json`)
|
|
89
|
+
|
|
90
|
+
**Simple Example (Auto-loaded from Google Fonts):**
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"fontThemes": {
|
|
94
|
+
"myfont": {
|
|
95
|
+
"heading": "Montserrat, sans-serif",
|
|
96
|
+
"body": "Open Sans, sans-serif",
|
|
97
|
+
"code": "Source Code Pro, monospace"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Google Fonts are **loaded automatically** with weights 400 and 700. Just specify the font family names - no need to construct Google Fonts URLs manually!
|
|
104
|
+
|
|
105
|
+
**Advanced Example (Custom Weights/Styles):**
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"fontThemes": {
|
|
109
|
+
"custom": {
|
|
110
|
+
"heading": "Poppins, sans-serif",
|
|
111
|
+
"body": "Inter, sans-serif",
|
|
112
|
+
"code": "Fira Code, monospace",
|
|
113
|
+
"googleFontsUrl": "https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Inter:wght@300;400;500&family=Fira+Code:wght@400;500&display=swap"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Use `googleFontsUrl` only if you need specific weights (like 300, 500, 600) or styles (italic, etc.). Get custom URLs from [Google Fonts](https://fonts.google.com).
|
|
120
|
+
|
|
121
|
+
**Usage:**
|
|
122
|
+
```bash
|
|
123
|
+
llmd --fonts myfont
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Requirements:**
|
|
127
|
+
- `heading`, `body`, and `code` properties are required
|
|
128
|
+
- Font names should include CSS fallbacks (e.g., `"Roboto, sans-serif"`)
|
|
129
|
+
- System fonts (Arial, Georgia, etc.) don't load from Google Fonts
|
|
130
|
+
- Invalid font names will show helpful errors listing all available fonts
|
|
131
|
+
|
|
132
|
+
## Color Themes
|
|
133
|
+
|
|
134
|
+
llmd includes 6 built-in color themes:
|
|
135
|
+
|
|
136
|
+
- **dark** - Default dark theme (default)
|
|
137
|
+
- **light** - Warm light theme
|
|
138
|
+
- **nord** - Nord-inspired cool theme
|
|
139
|
+
- **dracula** - Dracula-inspired purple theme
|
|
140
|
+
- **solarized** - Solarized Light theme
|
|
141
|
+
- **monokai** - Monokai-inspired theme
|
|
142
|
+
|
|
143
|
+
### Custom Themes
|
|
144
|
+
|
|
145
|
+
Create custom color themes in your `themes.json` config file.
|
|
146
|
+
|
|
147
|
+
**Location:** `~/.config/llmd/themes.json` (or `$XDG_CONFIG_HOME/llmd/themes.json`)
|
|
148
|
+
|
|
149
|
+
**Format:**
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"colorThemes": {
|
|
153
|
+
"mytheme": {
|
|
154
|
+
"bg": "#1a1a1a",
|
|
155
|
+
"fg": "#e0e0e0",
|
|
156
|
+
"border": "#333",
|
|
157
|
+
"hover": "#2a2a2a",
|
|
158
|
+
"accent": "#4a9eff",
|
|
159
|
+
"codeBg": "#2d2d2d",
|
|
160
|
+
"sidebarBg": "#151515",
|
|
161
|
+
"folderIcon": "#a78bfa",
|
|
162
|
+
"fileIcon": "#fbbf24"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Unified Config:**
|
|
169
|
+
You can combine both color themes and font themes in a single file:
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"colorThemes": {
|
|
173
|
+
"mytheme": { ... }
|
|
174
|
+
},
|
|
175
|
+
"fontThemes": {
|
|
176
|
+
"myfont": { ... }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Usage:**
|
|
182
|
+
```bash
|
|
183
|
+
llmd --theme mytheme --fonts myfont
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
If a theme or font is not found, llmd will list all available options.
|
|
187
|
+
|
|
188
|
+
**Note:** The old flat format for color themes (without `colorThemes` key) is still supported for backward compatibility.
|
|
189
|
+
|
|
190
|
+
## Options
|
|
191
|
+
|
|
192
|
+
| Flag | Description | Default |
|
|
193
|
+
|------|-------------|---------|
|
|
194
|
+
| `--port <number>` | Port (0 = random) | `0` (random) |
|
|
195
|
+
| `--host <string>` | Host interface | `localhost` |
|
|
196
|
+
| `--theme <name>` | Color theme: `dark`, `light`, `nord`, `dracula`, `solarized`, `monokai`, or custom | `dark` |
|
|
197
|
+
| `--fonts <name>` | Font combination: `serif`, `sans`, `mono`, `classic`, `future`, `modern`, `artsy`, `literary`, `editorial` | `sans` |
|
|
198
|
+
| `--open / --no-open` | Auto-open browser | `--open` |
|
|
199
|
+
| `--watch / --no-watch` | Live reload on changes | `--no-watch` |
|
|
200
|
+
| `-h, --help` | Show help | |
|
|
201
|
+
| `--version` | Show version | |
|
|
202
|
+
|
|
203
|
+
## Development
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Install dependencies
|
|
207
|
+
bun install
|
|
208
|
+
|
|
209
|
+
# Run with hot reload
|
|
210
|
+
bun --hot index.ts ./docs
|
|
211
|
+
|
|
212
|
+
# Run tests
|
|
213
|
+
bun test
|
|
214
|
+
|
|
215
|
+
# Build binary
|
|
216
|
+
bun run build
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Tech Stack
|
|
220
|
+
|
|
221
|
+
- **Runtime**: Bun
|
|
222
|
+
- **Markdown**: marked (GFM support)
|
|
223
|
+
- **Highlighting**: Shiki (VS Code themes)
|
|
224
|
+
- **Server**: Bun.serve() with WebSocket
|
|
225
|
+
- **Bundler**: Bun's built-in bundler
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT
|
|
230
|
+
|
|
231
|
+
## Contributing
|
|
232
|
+
|
|
233
|
+
Issues and PRs welcome. This tool is intentionally minimal—new features should materially improve the "view markdown now" workflow.
|
package/dist/client.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var s=()=>{document.querySelectorAll("pre code").forEach((o)=>{let d=o.parentElement;if(!d)return;if(d.querySelector(".copy-button"))return;let t=document.createElement("button");t.className="copy-button",t.textContent="Copy",t.setAttribute("aria-label","Copy code to clipboard"),t.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(o.textContent||""),t.textContent="Copied!",t.classList.add("copied"),setTimeout(()=>{t.textContent="Copy",t.classList.remove("copied")},2000)}catch(e){console.error("Failed to copy:",e),t.textContent="Failed",setTimeout(()=>{t.textContent="Copy"},2000)}}),d.appendChild(t)})};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",s);else s();var p=(o)=>{let t=`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}/_ws`,e=null,n=null,l=()=>{e=new WebSocket(t),e.addEventListener("open",()=>{console.log("[llmd] Connected to file watcher"),e?.send(JSON.stringify({type:"watch",file:o}))}),e.addEventListener("message",(i)=>{try{let a=JSON.parse(i.data);if(a.type==="reload"&&a.file===o)console.log(`[llmd] File changed: ${o}, reloading...`),window.location.reload()}catch(a){console.error("[llmd] Failed to parse message:",a)}}),e.addEventListener("close",()=>{console.log("[llmd] Disconnected from file watcher"),n=window.setTimeout(()=>{console.log("[llmd] Reconnecting..."),l()},2000)}),e.addEventListener("error",(i)=>{console.error("[llmd] WebSocket error:",i),e?.close()})};l(),window.addEventListener("beforeunload",()=>{if(n)clearTimeout(n);e?.close()})};window.connectFileWatcher=p;console.log("[llmd] Client initialized");
|