tuimon 0.1.0 → 0.2.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.
Files changed (111) hide show
  1. package/AI.md +191 -0
  2. package/README.md +223 -87
  3. package/dist/browser.d.ts.map +1 -1
  4. package/dist/browser.js +3 -0
  5. package/dist/browser.js.map +1 -1
  6. package/dist/cli.js +171 -3
  7. package/dist/cli.js.map +1 -1
  8. package/dist/config.d.ts +17 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +106 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/fkeybar.d.ts.map +1 -1
  13. package/dist/fkeybar.js +13 -0
  14. package/dist/fkeybar.js.map +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +148 -18
  17. package/dist/index.js.map +1 -1
  18. package/dist/layout/generator-css.d.ts +3 -0
  19. package/dist/layout/generator-css.d.ts.map +1 -0
  20. package/dist/layout/generator-css.js +202 -0
  21. package/dist/layout/generator-css.js.map +1 -0
  22. package/dist/layout/generator-js.d.ts +3 -0
  23. package/dist/layout/generator-js.d.ts.map +1 -0
  24. package/dist/layout/generator-js.js +353 -0
  25. package/dist/layout/generator-js.js.map +1 -0
  26. package/dist/layout/generator.d.ts +4 -0
  27. package/dist/layout/generator.d.ts.map +1 -0
  28. package/dist/layout/generator.js +124 -0
  29. package/dist/layout/generator.js.map +1 -0
  30. package/dist/layout/theme.d.ts +4 -0
  31. package/dist/layout/theme.d.ts.map +1 -0
  32. package/dist/layout/theme.js +28 -0
  33. package/dist/layout/theme.js.map +1 -0
  34. package/dist/layout/types.d.ts +68 -0
  35. package/dist/layout/types.d.ts.map +1 -0
  36. package/dist/layout/types.js +3 -0
  37. package/dist/layout/types.js.map +1 -0
  38. package/dist/quick/auto-layout.d.ts +5 -0
  39. package/dist/quick/auto-layout.d.ts.map +1 -0
  40. package/dist/quick/auto-layout.js +262 -0
  41. package/dist/quick/auto-layout.js.map +1 -0
  42. package/dist/quick/db/detect.d.ts +16 -0
  43. package/dist/quick/db/detect.d.ts.map +1 -0
  44. package/dist/quick/db/detect.js +131 -0
  45. package/dist/quick/db/detect.js.map +1 -0
  46. package/dist/quick/db/mongo.d.ts +10 -0
  47. package/dist/quick/db/mongo.d.ts.map +1 -0
  48. package/dist/quick/db/mongo.js +81 -0
  49. package/dist/quick/db/mongo.js.map +1 -0
  50. package/dist/quick/db/mysql.d.ts +8 -0
  51. package/dist/quick/db/mysql.d.ts.map +1 -0
  52. package/dist/quick/db/mysql.js +43 -0
  53. package/dist/quick/db/mysql.js.map +1 -0
  54. package/dist/quick/db/postgres.d.ts +8 -0
  55. package/dist/quick/db/postgres.d.ts.map +1 -0
  56. package/dist/quick/db/postgres.js +47 -0
  57. package/dist/quick/db/postgres.js.map +1 -0
  58. package/dist/quick/db/sqlite.d.ts +8 -0
  59. package/dist/quick/db/sqlite.d.ts.map +1 -0
  60. package/dist/quick/db/sqlite.js +43 -0
  61. package/dist/quick/db/sqlite.js.map +1 -0
  62. package/dist/quick/db-mode.d.ts +13 -0
  63. package/dist/quick/db-mode.d.ts.map +1 -0
  64. package/dist/quick/db-mode.js +159 -0
  65. package/dist/quick/db-mode.js.map +1 -0
  66. package/dist/quick/detect.d.ts +4 -0
  67. package/dist/quick/detect.d.ts.map +1 -0
  68. package/dist/quick/detect.js +76 -0
  69. package/dist/quick/detect.js.map +1 -0
  70. package/dist/quick/file-mode.d.ts +5 -0
  71. package/dist/quick/file-mode.d.ts.map +1 -0
  72. package/dist/quick/file-mode.js +158 -0
  73. package/dist/quick/file-mode.js.map +1 -0
  74. package/dist/quick/parsers/csv.d.ts +3 -0
  75. package/dist/quick/parsers/csv.d.ts.map +1 -0
  76. package/dist/quick/parsers/csv.js +145 -0
  77. package/dist/quick/parsers/csv.js.map +1 -0
  78. package/dist/quick/parsers/detect-meta.d.ts +7 -0
  79. package/dist/quick/parsers/detect-meta.d.ts.map +1 -0
  80. package/dist/quick/parsers/detect-meta.js +35 -0
  81. package/dist/quick/parsers/detect-meta.js.map +1 -0
  82. package/dist/quick/parsers/json.d.ts +3 -0
  83. package/dist/quick/parsers/json.d.ts.map +1 -0
  84. package/dist/quick/parsers/json.js +74 -0
  85. package/dist/quick/parsers/json.js.map +1 -0
  86. package/dist/quick/parsers/log.d.ts +3 -0
  87. package/dist/quick/parsers/log.d.ts.map +1 -0
  88. package/dist/quick/parsers/log.js +185 -0
  89. package/dist/quick/parsers/log.js.map +1 -0
  90. package/dist/quick/parsers/modsec.d.ts +3 -0
  91. package/dist/quick/parsers/modsec.d.ts.map +1 -0
  92. package/dist/quick/parsers/modsec.js +338 -0
  93. package/dist/quick/parsers/modsec.js.map +1 -0
  94. package/dist/quick/types.d.ts +90 -0
  95. package/dist/quick/types.d.ts.map +1 -0
  96. package/dist/quick/types.js +3 -0
  97. package/dist/quick/types.js.map +1 -0
  98. package/dist/quick/watch-mode.d.ts +3 -0
  99. package/dist/quick/watch-mode.d.ts.map +1 -0
  100. package/dist/quick/watch-mode.js +156 -0
  101. package/dist/quick/watch-mode.js.map +1 -0
  102. package/dist/server.js +2 -2
  103. package/dist/server.js.map +1 -1
  104. package/dist/types.d.ts +8 -1
  105. package/dist/types.d.ts.map +1 -1
  106. package/examples/demo.ts +134 -0
  107. package/examples/generate-access-log.ts +42 -0
  108. package/examples/screenshot-test.ts +105 -0
  109. package/examples/screenshot.png +0 -0
  110. package/frame-log.txt +830 -0
  111. package/package.json +10 -5
package/AI.md ADDED
@@ -0,0 +1,191 @@
1
+ # TuiMon — AI Integration Guide
2
+
3
+ > Use this file when a user asks to display, monitor, or visualize data in a terminal.
4
+ > TuiMon renders beautiful dashboards with zero setup. Just install, send data, done.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ npm install -g tuimon
10
+ ```
11
+
12
+ ## Quickest Paths (pick one)
13
+
14
+ ### Path 1: I have a data file
15
+ ```bash
16
+ tuimon data.json # JSON array of objects → instant table + charts
17
+ tuimon users.csv # CSV → instant table + charts
18
+ tuimon access.log # Nginx log → request stats + browsable table
19
+ tuimon modsec.log # ModSecurity → security dashboard
20
+ ```
21
+ That's it. No code needed. TuiMon auto-detects format and creates the dashboard.
22
+
23
+ ### Path 2: I want live data from a function
24
+ Create one file:
25
+ ```js
26
+ // monitor.js
27
+ module.exports = () => ({
28
+ cpu: require('os').cpus().reduce((a,c) => a + (100 - c.times.idle / Object.values(c.times).reduce((x,y)=>x+y,0) * 100), 0) / require('os').cpus().length | 0,
29
+ memory: ((1 - require('os').freemem() / require('os').totalmem()) * 100) | 0,
30
+ uptime: process.uptime() | 0,
31
+ })
32
+ ```
33
+ ```bash
34
+ tuimon watch monitor.js
35
+ ```
36
+ TuiMon auto-detects data types and creates appropriate widgets. Refreshes every second.
37
+
38
+ ### Path 3: I want to monitor an HTTP endpoint
39
+ ```bash
40
+ tuimon watch --url http://localhost:3000/api/stats
41
+ ```
42
+ The endpoint must return JSON. TuiMon polls it every second and auto-creates the dashboard.
43
+
44
+ ### Path 4: I want a custom layout (still no HTML)
45
+ ```js
46
+ // dashboard.js
47
+ const tuimon = require('tuimon')
48
+
49
+ tuimon.default.start({
50
+ pages: {
51
+ main: {
52
+ default: true,
53
+ layout: {
54
+ title: 'My Dashboard',
55
+ stats: [
56
+ { id: 'users', label: 'Users', type: 'stat' },
57
+ { id: 'cpu', label: 'CPU', type: 'gauge' },
58
+ ],
59
+ panels: [
60
+ { id: 'requests', label: 'Requests', type: 'line', span: 2 },
61
+ { id: 'errors', label: 'Errors', type: 'event-log' },
62
+ ],
63
+ },
64
+ },
65
+ },
66
+ refresh: 1000,
67
+ data: () => ({
68
+ users: getUserCount(),
69
+ cpu: getCpuPercent(),
70
+ requests: { HTTP: getReqRate(), WS: getWsRate() },
71
+ errors: getRecentErrors(),
72
+ }),
73
+ })
74
+ ```
75
+
76
+ ## Data Format Rules
77
+
78
+ TuiMon accepts the **simplest possible data**. Just send what you have:
79
+
80
+ | You send | TuiMon shows |
81
+ |----------|-------------|
82
+ | `42` | Stat card with number |
83
+ | `73` (for id containing cpu/mem/disk) | Gauge (0-100%) |
84
+ | `"running"` | Stat card with text |
85
+ | `{ value: 42, trend: '+5', unit: 'req/s' }` | Stat card with trend |
86
+ | `{ Requests: 340, Errors: 12 }` | Line chart (auto-accumulates history over time) |
87
+ | `{ GET: 200, POST: 50 }` | Bar chart |
88
+ | `['Deploy completed', 'Scaled up']` | Event log (auto-timestamped) |
89
+ | `[{ text: 'Error', type: 'error' }]` | Event log (colored by type) |
90
+ | `['Node-1', 'Node-2']` | Status grid (all green) |
91
+ | `[{ label: 'DB', status: 'error' }]` | Status grid (colored dots) |
92
+
93
+ **Key insight for line charts:** You don't manage history. Each call to `render()` or each refresh sends CURRENT values. TuiMon accumulates the history automatically and builds the chart over time.
94
+
95
+ ## Widget Types
96
+
97
+ | Type | Use for |
98
+ |------|---------|
99
+ | `stat` | Single number or text value |
100
+ | `gauge` | Percentage (0-100 with color bar) |
101
+ | `line` | Time series (auto-accumulates history) |
102
+ | `bar` | Categorical comparison |
103
+ | `doughnut` | Distribution/proportion |
104
+ | `event-log` | Scrolling list of events |
105
+ | `status-grid` | Health indicators (colored dots) |
106
+ | `table` | Tabular data with pagination |
107
+
108
+ ## Per-Widget Throttle
109
+
110
+ Widgets can update at different speeds:
111
+ ```js
112
+ panels: [
113
+ { id: 'chart', label: 'Chart', type: 'line' }, // every frame
114
+ { id: 'events', label: 'Events', type: 'event-log', throttle: 2000 }, // max every 2s
115
+ { id: 'health', label: 'Health', type: 'status-grid', throttle: 5000 }, // max every 5s
116
+ ]
117
+ ```
118
+
119
+ ## VSCode Terminal
120
+
121
+ TuiMon works in VSCode's integrated terminal. Ensure this setting is enabled:
122
+ ```json
123
+ { "terminal.integrated.enableImages": true }
124
+ ```
125
+ Running `tuimon init` sets this automatically.
126
+
127
+ ## Common AI Use Cases
128
+
129
+ ### "Show me my server stats"
130
+ ```js
131
+ module.exports = () => ({
132
+ cpu: os.loadavg()[0],
133
+ memory: ((1 - os.freemem()/os.totalmem()) * 100) | 0,
134
+ uptime: process.uptime() | 0,
135
+ processes: execSync('ps aux | wc -l').toString().trim(),
136
+ })
137
+ ```
138
+ ```bash
139
+ tuimon watch server-stats.js
140
+ ```
141
+
142
+ ### "Monitor my API"
143
+ ```bash
144
+ tuimon watch --url http://localhost:3000/health
145
+ ```
146
+
147
+ ### "Visualize this JSON data"
148
+ ```bash
149
+ tuimon data.json
150
+ ```
151
+
152
+ ### "Show me my nginx traffic"
153
+ ```bash
154
+ tuimon /var/log/nginx/access.log
155
+ ```
156
+
157
+ ### "Monitor my database"
158
+ ```js
159
+ module.exports = async () => {
160
+ const pool = require('./db')
161
+ const { rows } = await pool.query('SELECT count(*) as c FROM users WHERE active = true')
162
+ return {
163
+ activeUsers: rows[0].c,
164
+ connections: pool.totalCount,
165
+ idle: pool.idleCount,
166
+ waiting: pool.waitingCount,
167
+ }
168
+ }
169
+ ```
170
+ ```bash
171
+ tuimon watch db-monitor.js
172
+ ```
173
+
174
+ ### "Show security events"
175
+ ```bash
176
+ tuimon /var/log/modsec_audit.log
177
+ ```
178
+
179
+ ## CLI Reference
180
+
181
+ ```
182
+ tuimon <file> # Visualize JSON/CSV/log file
183
+ tuimon <file> -c "col1,col2" # Show specific columns only
184
+ tuimon watch <file.js> # Live data from JS module
185
+ tuimon watch --url <url> # Poll JSON endpoint
186
+ tuimon watch --url <url> --interval 5000 # Custom poll interval
187
+ tuimon start # Full config mode
188
+ tuimon init # Scaffold project + enable VSCode
189
+ tuimon check # Verify terminal graphics support
190
+ tuimon ai # Print this guide
191
+ ```
package/README.md CHANGED
@@ -1,152 +1,288 @@
1
1
  # TuiMon
2
2
 
3
- > Render beautiful HTML dashboards directly in your terminal.
3
+ > Render beautiful dashboards directly in your terminal. Zero config required.
4
4
 
5
- ## Terminal Requirements
5
+ ## The Simplest Way to Visualize Data in Your Terminal
6
6
 
7
- | Terminal | Protocol | Status |
8
- |-----------|----------|------------|
9
- | Kitty | Kitty | Supported |
10
- | Ghostty | Kitty | Supported |
11
- | WezTerm | Kitty | Supported |
12
- | iTerm2 | iTerm2 | Supported |
13
- | VSCode | Sixel | Supported* |
14
- | mlterm | Sixel | Supported |
7
+ ```bash
8
+ # Visualize any data file instantly
9
+ tuimon data.json
10
+ tuimon users.csv
11
+ tuimon /var/log/nginx/access.log
12
+
13
+ # Live monitoring from a data function
14
+ tuimon watch metrics.js
15
+
16
+ # Poll a JSON API
17
+ tuimon watch --url http://localhost:3000/metrics
18
+
19
+ # Full custom dashboard (HTML/CSS/JS)
20
+ tuimon start
21
+ ```
22
+
23
+ No HTML. No config files. No charting libraries. Just point TuiMon at your data.
15
24
 
16
- \* Sixel support may vary by terminal version.
25
+ ## Terminal Support
26
+
27
+ | Terminal | Protocol | Status |
28
+ |----------|----------|--------|
29
+ | Kitty | Kitty | Supported |
30
+ | Ghostty | Kitty | Supported |
31
+ | WezTerm | Kitty | Supported |
32
+ | iTerm2 | iTerm2 | Supported |
33
+ | **VSCode** | Sixel | **Supported** (requires one setting) |
34
+ | mlterm | Sixel | Supported |
35
+
36
+ ### VSCode Setup
37
+
38
+ VSCode supports terminal images but it's **off by default**. Running `tuimon init` enables it automatically by creating `.vscode/settings.json` with:
39
+
40
+ ```json
41
+ { "terminal.integrated.enableImages": true }
42
+ ```
17
43
 
18
44
  ## Quick Start
19
45
 
20
46
  ```bash
21
- npx tuimon init
22
- npx tuimon check
23
- npx tuimon start
47
+ npm install -g tuimon
48
+ tuimon check # verify your terminal supports graphics
24
49
  ```
25
50
 
26
- Or install globally:
51
+ ## 1. Instant File Visualization
52
+
53
+ Point TuiMon at any data file — it auto-detects the format, picks the right charts, and renders a dashboard:
27
54
 
28
55
  ```bash
29
- npm install -g tuimon
30
- tuimon init && tuimon start
56
+ # JSON array → table + charts
57
+ tuimon users.json
58
+
59
+ # CSV → table + charts
60
+ tuimon sales.csv
61
+
62
+ # Nginx access log → request stats + table
63
+ tuimon /var/log/nginx/access.log
64
+
65
+ # ModSecurity audit log → security dashboard
66
+ tuimon /var/log/modsec_audit.log
67
+
68
+ # Filter columns
69
+ tuimon access.log --columns "Timestamp,IP,Path,Status"
31
70
  ```
32
71
 
33
- ## How It Works
72
+ **Auto-detected formats:**
73
+ - **JSON/JSONL** — arrays of objects → table + stat cards + charts
74
+ - **CSV/TSV** — auto-detects delimiter, header row, column types
75
+ - **Nginx combined log** — request stats, status codes, top endpoints/IPs, browsable request table
76
+ - **ModSecurity audit log** — security events, severity distribution, attack categories, top attacker IPs
77
+ - **JSON logs** — level distribution, latest entries
78
+ - **Plain text** — live tail
79
+
80
+ **Features:**
81
+ - Press **D** to switch to full-screen data table view, **ESC** to go back
82
+ - Arrow keys / PgUp / PgDn to navigate table pages
83
+ - **F5** to reload file, **F10** to quit
84
+ - File is **watched** — dashboard updates when the file changes on disk
85
+
86
+ ## 2. Live Data Monitoring
87
+
88
+ Create a JS file that exports a data function — TuiMon handles the rest:
34
89
 
35
- TuiMon renders your HTML pages in a headless Chromium browser via Playwright, screenshots them as PNG, and streams the images to your terminal using the Kitty graphics protocol (or Sixel as fallback). You write dashboards as normal HTML/CSS/JS — any charting library works.
90
+ ```js
91
+ // metrics.js
92
+ const os = require('os')
36
93
 
37
- ## Multi-Page Navigation
94
+ module.exports = () => ({
95
+ cpu: Math.round(100 - (os.cpus().reduce((a,c) => a + c.times.idle, 0) / os.cpus().reduce((a,c) => a + Object.values(c.times).reduce((x,y) => x+y, 0), 0)) * 100),
96
+ memory: Math.round((1 - os.freemem() / os.totalmem()) * 100),
97
+ uptime: Math.round(process.uptime()) + 's',
98
+ })
99
+ ```
100
+
101
+ ```bash
102
+ tuimon watch metrics.js
103
+ ```
104
+
105
+ TuiMon inspects the returned data and auto-creates the right widgets:
106
+
107
+ | Data type | Widget |
108
+ |-----------|--------|
109
+ | Number (0-100 + name like cpu/mem) | Gauge |
110
+ | Number (other) | Stat card |
111
+ | String | Stat card |
112
+ | `{ key: number, ... }` (2+ keys) | Line chart (auto-accumulates history) |
113
+ | `{ key: number }` | Bar chart |
114
+ | `['string', ...]` | Event log (auto-timestamped) |
115
+ | `[{ label, status }, ...]` | Status grid (colored dots) |
116
+
117
+ **Export options:**
118
+
119
+ ```js
120
+ module.exports = () => ({ ... }) // data function (required)
121
+ module.exports.refresh = 500 // refresh interval in ms (default: 1000)
122
+ module.exports.title = 'My App' // dashboard title
123
+ module.exports.layout = { ... } // override auto-detected layout
124
+ ```
125
+
126
+ ### Poll a JSON API
127
+
128
+ ```bash
129
+ tuimon watch --url http://localhost:3000/metrics
130
+ tuimon watch --url http://localhost:3000/metrics --interval 2000
131
+ ```
38
132
 
39
- Define multiple pages with keyboard shortcuts:
133
+ ## 3. Zero-HTML Declarative Dashboard
134
+
135
+ For more control without writing HTML, define widgets in a layout config:
40
136
 
41
137
  ```typescript
138
+ import tuimon from 'tuimon'
139
+
42
140
  const dash = await tuimon.start({
43
141
  pages: {
44
142
  overview: {
45
- html: './pages/overview.html',
46
143
  default: true,
47
- label: 'Overview',
48
- },
49
- cpu: {
50
- html: './pages/cpu-detail.html',
51
- shortcut: 'g',
52
- label: 'CPU Detail',
53
- },
54
- memory: {
55
- html: './pages/memory-detail.html',
56
- shortcut: 'm',
57
- label: 'Memory',
144
+ layout: {
145
+ title: 'My App',
146
+ stats: [
147
+ { id: 'users', label: 'Users Online', type: 'stat' },
148
+ { id: 'cpu', label: 'CPU', type: 'gauge' },
149
+ ],
150
+ panels: [
151
+ { id: 'traffic', label: 'Traffic', type: 'line', span: 2 },
152
+ { id: 'services', label: 'Services', type: 'doughnut' },
153
+ { id: 'events', label: 'Events', type: 'event-log', throttle: 2000 },
154
+ { id: 'health', label: 'Health', type: 'status-grid', throttle: 5000 },
155
+ ],
156
+ },
58
157
  },
59
158
  },
159
+ refresh: 500,
160
+ data: () => ({
161
+ users: getOnlineCount(),
162
+ cpu: getCpuPercent(),
163
+ traffic: { Requests: 340, Errors: 12 },
164
+ services: { Web: 47, API: 27 },
165
+ events: ['Deploy completed'],
166
+ health: ['Node-1', 'Node-2'],
167
+ }),
60
168
  })
61
169
  ```
62
170
 
63
- - Press a shortcut key from the overview to jump to a detail page
64
- - Press **ESC** on a detail page to return to overview
65
- - Press **ESC** on overview to show quit confirmation
66
- - Press **Ctrl+C** anywhere to exit immediately
171
+ **8 widget types:** `stat`, `gauge`, `line`, `doughnut`, `bar`, `event-log`, `status-grid`, `table`
67
172
 
68
- Add shortcut badges to HTML panels with data attributes:
173
+ **Per-widget throttle:** Each widget can have its own update rate — charts update every frame while event logs and status grids update less frequently.
69
174
 
70
- ```html
71
- <div class="panel" data-tm-key="g" data-tm-label="CPU Detail">
72
- <!-- panel content -->
73
- </div>
175
+ **Lazy data format:** Every widget accepts the simplest possible data. Just send numbers — TuiMon figures out the rest:
176
+
177
+ ```typescript
178
+ dash.render({
179
+ users: 42, // number → stat
180
+ cpu: 73, // number → gauge (0-100)
181
+ traffic: { Requests: 340, Errors: 12 }, // object → line chart (history auto-accumulated)
182
+ services: { Web: 47, API: 27 }, // object → doughnut
183
+ events: ['Deploy completed'], // string[] → event-log (auto-timestamped)
184
+ health: ['Node-1', 'Node-2'], // string[] → status-grid (all "ok")
185
+ })
74
186
  ```
75
187
 
76
- ## Per-Page F-Key Bindings
188
+ ## 4. Full Custom HTML Dashboard
77
189
 
78
- Each page defines its own F-key actions:
190
+ For complete control, write your dashboard as normal HTML/CSS/JS:
191
+
192
+ ```bash
193
+ tuimon init # scaffolds starter project
194
+ tuimon start # runs it
195
+ ```
196
+
197
+ TuiMon renders your HTML pages in a headless Chromium browser via Playwright, screenshots them as PNG, and streams the images to your terminal. Any charting library works — Chart.js, D3, ECharts, anything.
198
+
199
+ ### Multi-Page Navigation
79
200
 
80
201
  ```typescript
81
- pages: {
82
- overview: {
83
- html: './pages/overview.html',
84
- default: true,
85
- keys: {
86
- F5: { label: 'Refresh', action: async () => dash.render(await getData()) },
87
- F10: { label: 'Quit', action: () => process.exit(0) },
202
+ const dash = await tuimon.start({
203
+ pages: {
204
+ overview: {
205
+ html: './pages/overview.html',
206
+ default: true,
207
+ label: 'Overview',
208
+ },
209
+ cpu: {
210
+ html: './pages/cpu-detail.html',
211
+ shortcut: 'g',
212
+ label: 'CPU Detail',
88
213
  },
89
214
  },
90
- }
215
+ })
91
216
  ```
92
217
 
93
- The F-key bar at the bottom always reflects the active page's bindings.
218
+ - Press a shortcut key to jump to a detail page
219
+ - **ESC** on detail page returns to overview
220
+ - **ESC** on overview shows quit confirmation
221
+ - **Ctrl+C** exits immediately from anywhere
94
222
 
95
- ## API Reference
96
-
97
- ### `tuimon.start(options: TuiMonOptions): Promise<TuiMonDashboard>`
223
+ ### Per-Page F-Key Bindings
98
224
 
99
225
  ```typescript
100
- interface TuiMonOptions {
101
- pages: Record<string, PageConfig>
102
- data?: () => Record<string, unknown> | Promise<Record<string, unknown>>
103
- refresh?: number // auto-render interval in ms
104
- renderDelay?: number // delay after pushData before screenshot (default: 50)
226
+ keys: {
227
+ F5: { label: 'Refresh', action: async () => dash.render(await getData()) },
228
+ F10: { label: 'Quit', action: () => process.exit(0) },
105
229
  }
230
+ ```
106
231
 
107
- interface PageConfig {
108
- html: string // path to HTML file
109
- default?: boolean // exactly one page must be default
110
- shortcut?: string // single lowercase letter
111
- label?: string // human-readable name
112
- keys?: Partial<Record<FKey, KeyBinding>>
113
- }
232
+ ### Client Library
114
233
 
115
- interface KeyBinding {
116
- label: string
117
- action: () => void | Promise<void>
118
- }
234
+ In your HTML pages, the injected `TuiMon` object receives data:
235
+
236
+ ```javascript
237
+ TuiMon.onUpdate(function(data) {
238
+ TuiMon.set('#cpu', data.cpu)
239
+ TuiMon.set('#memory', data.memory + '%')
240
+ })
119
241
  ```
120
242
 
121
- ### `dash.render(data): Promise<void>`
243
+ Add shortcut badges to panels with data attributes:
122
244
 
123
- Push data to the current page and re-render.
245
+ ```html
246
+ <div class="panel" data-tm-key="g" data-tm-label="CPU Detail">
247
+ ```
124
248
 
125
- ### `dash.stop(): Promise<void>`
249
+ ## CLI Reference
126
250
 
127
- Gracefully shut down restores terminal state.
251
+ | Command | Description |
252
+ |---------|-------------|
253
+ | `tuimon <file>` | Visualize a JSON, CSV, or log file |
254
+ | `tuimon watch <file.js>` | Live dashboard from a data module |
255
+ | `tuimon watch --url <url>` | Poll a JSON endpoint |
256
+ | `tuimon start` | Run from tuimon.config.ts |
257
+ | `tuimon init` | Scaffold a starter project + enable VSCode |
258
+ | `tuimon check` | Check terminal graphics support |
128
259
 
129
- ## Client Library
260
+ **Options:**
261
+ - `-c, --columns <cols>` — comma-separated list of columns to display
262
+ - `--interval <ms>` — poll interval for URL watch mode (default: 1000)
130
263
 
131
- In your HTML pages, use the injected `TuiMon` object:
264
+ **Environment:**
265
+ - `TUIMON_DEBUG=1` — print per-frame timing to stderr
132
266
 
133
- ```javascript
134
- // Listen for data updates
135
- TuiMon.onUpdate(function(data) {
136
- TuiMon.set('#cpu', data.cpu)
137
- TuiMon.set('#memory', data.memory + '%')
138
- })
267
+ ## How It Works
139
268
 
140
- // TuiMon.set(selector, value) — sets text content or applies styles
141
- // TuiMon.notify(message, duration) — dispatches a notification event
142
269
  ```
270
+ Your data → TuiMon → Headless Chromium → Screenshot → Kitty/Sixel → Terminal
271
+ ```
272
+
273
+ 1. Your data is pushed to an HTML page running in headless Chromium
274
+ 2. Playwright takes a PNG screenshot
275
+ 3. The image is encoded as Kitty graphics protocol (or Sixel fallback)
276
+ 4. Written directly to your terminal's stdout
277
+
278
+ Typical frame time: **~50ms** (at 250ms refresh = 4 FPS with headroom to spare).
143
279
 
144
280
  ## Contributing
145
281
 
146
282
  - **TDD required** — write tests first, implementation second
147
283
  - Coverage thresholds: 80% lines, 80% functions, 75% branches
148
284
  - `npm test` must pass before any PR
149
- - Strict TypeScript — `strict: true`, no `any`
285
+ - Strict TypeScript — `strict: true`, `noUncheckedIndexedAccess`, no `any`
150
286
 
151
287
  ## License
152
288
 
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,wBAAsB,aAAa,CAAC,EAClC,GAAG,EACH,KAAK,EACL,MAAM,GACP,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAAC,aAAa,CAAC,CA8DzB"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,wBAAsB,aAAa,CAAC,EAClC,GAAG,EACH,KAAK,EACL,MAAM,GACP,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAAC,aAAa,CAAC,CAkEzB"}
package/dist/browser.js CHANGED
@@ -49,6 +49,9 @@ export async function createBrowser({ url, width, height, }) {
49
49
  async resize(w, h) {
50
50
  await page.setViewportSize({ width: w, height: h });
51
51
  },
52
+ async evaluate(expression) {
53
+ await page.evaluate(expression);
54
+ },
52
55
  async close() {
53
56
  await browser.close();
54
57
  },
@@ -1 +1 @@
1
- {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGrC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAClC,GAAG,EACH,KAAK,EACL,MAAM,GAKP;IACC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAA;IAC1C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;IAEpC,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IAC7C,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAA;IAEvD,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QAC1B,UAAU,EAAE,CAAA;QACZ,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAA;YAChF,OAAM;QACR,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,UAAU,kBAAkB,CAAC,CAAA;QACpF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,GAAG,CAAC,OAAO,IAAI,CAAC,CAAA;IAC9D,CAAC,CAAC,CAAA;IAEF,OAAO;QACL,KAAK,CAAC,UAAU;YACd,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAClD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACzB,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,IAA6B;YAC1C,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAA0B,EAAE,EAAE;gBACjD,MAAM,GAAG,GAAG,UAAqC,CAAA;gBACjD,IAAI,OAAO,GAAG,CAAC,mBAAmB,CAAC,KAAK,UAAU,EAAE,CAAC;oBACnD,CAAC;oBAAC,GAAG,CAAC,mBAAmB,CAA0C,CAAC,CAAC,CAAC,CAAA;gBACxE,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,CAAA;YACR,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,eAAe,CACxB,GAAG,EAAE,CAAE,UAAsC,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAC1E,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB,CAAA;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,kEAAkE;YACpE,CAAC;QACH,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,MAAc;YAC3B,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAA;QAC5D,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,CAAS,EAAE,CAAS;YAC/B,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAA;QACrD,CAAC;QAED,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;QACvB,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}