tuimon 0.1.0 → 0.3.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 (139) hide show
  1. package/AI.md +191 -0
  2. package/README.md +240 -94
  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 +224 -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/presets/coverage.d.ts +3 -0
  95. package/dist/quick/presets/coverage.d.ts.map +1 -0
  96. package/dist/quick/presets/coverage.js +362 -0
  97. package/dist/quick/presets/coverage.js.map +1 -0
  98. package/dist/quick/presets/deps.d.ts +3 -0
  99. package/dist/quick/presets/deps.d.ts.map +1 -0
  100. package/dist/quick/presets/deps.js +194 -0
  101. package/dist/quick/presets/deps.js.map +1 -0
  102. package/dist/quick/presets/docker.d.ts +3 -0
  103. package/dist/quick/presets/docker.d.ts.map +1 -0
  104. package/dist/quick/presets/docker.js +100 -0
  105. package/dist/quick/presets/docker.js.map +1 -0
  106. package/dist/quick/presets/git.d.ts +3 -0
  107. package/dist/quick/presets/git.d.ts.map +1 -0
  108. package/dist/quick/presets/git.js +116 -0
  109. package/dist/quick/presets/git.js.map +1 -0
  110. package/dist/quick/presets/ps.d.ts +3 -0
  111. package/dist/quick/presets/ps.d.ts.map +1 -0
  112. package/dist/quick/presets/ps.js +168 -0
  113. package/dist/quick/presets/ps.js.map +1 -0
  114. package/dist/quick/presets/runner.d.ts +3 -0
  115. package/dist/quick/presets/runner.d.ts.map +1 -0
  116. package/dist/quick/presets/runner.js +20 -0
  117. package/dist/quick/presets/runner.js.map +1 -0
  118. package/dist/quick/presets/types.d.ts +7 -0
  119. package/dist/quick/presets/types.d.ts.map +1 -0
  120. package/dist/quick/presets/types.js +2 -0
  121. package/dist/quick/presets/types.js.map +1 -0
  122. package/dist/quick/types.d.ts +90 -0
  123. package/dist/quick/types.d.ts.map +1 -0
  124. package/dist/quick/types.js +3 -0
  125. package/dist/quick/types.js.map +1 -0
  126. package/dist/quick/watch-mode.d.ts +3 -0
  127. package/dist/quick/watch-mode.d.ts.map +1 -0
  128. package/dist/quick/watch-mode.js +156 -0
  129. package/dist/quick/watch-mode.js.map +1 -0
  130. package/dist/server.js +2 -2
  131. package/dist/server.js.map +1 -1
  132. package/dist/types.d.ts +9 -2
  133. package/dist/types.d.ts.map +1 -1
  134. package/examples/demo.ts +134 -0
  135. package/examples/generate-access-log.ts +42 -0
  136. package/examples/screenshot-test.ts +105 -0
  137. package/examples/screenshot.png +0 -0
  138. package/frame-log.txt +830 -0
  139. 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,298 @@
1
1
  # TuiMon
2
2
 
3
- > Render beautiful HTML dashboards directly in your terminal.
3
+ > Your HTML, CSS, and JavaScript, rendered directly in the terminal.
4
4
 
5
- ## Terminal Requirements
5
+ ## What Is TuiMon?
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
+ TuiMon takes any HTML page and renders it live in your terminal. Write your dashboard with HTML, CSS flexbox, Chart.js, D3, or whatever you already know, and TuiMon turns it into a real-time terminal application.
15
8
 
16
- \* Sixel support may vary by terminal version.
9
+ No curses. No blessed. No terminal UI framework. Just the web tech you already use.
17
10
 
18
- ## Quick Start
19
-
20
- ```bash
21
- npx tuimon init
22
- npx tuimon check
23
- npx tuimon start
24
11
  ```
12
+ Your HTML/CSS/JS > Headless Chromium > Screenshot > Terminal Graphics > Your Terminal
13
+ ```
14
+
15
+ If it works in a browser, it works in TuiMon.
25
16
 
26
- Or install globally:
17
+ But you don't have to write HTML if you don't want to. TuiMon also comes with a beautiful built-in theme and a set of zero-config CLI tools that let you visualize files, databases, and live data without writing a single line of HTML.
18
+
19
+ ## Quick Start
27
20
 
28
21
  ```bash
29
22
  npm install -g tuimon
30
- tuimon init && tuimon start
23
+ tuimon init # scaffolds a starter dashboard
24
+ tuimon start # renders it in your terminal
31
25
  ```
32
26
 
33
- ## How It Works
27
+ ---
34
28
 
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.
29
+ ## 1. Build Your Own Dashboard with HTML
36
30
 
37
- ## Multi-Page Navigation
31
+ This is what TuiMon was built for. You write your dashboard as a normal HTML page. Use CSS flexbox, grid, animations, whatever. Use any charting library. TuiMon renders it in your terminal.
38
32
 
39
- Define multiple pages with keyboard shortcuts:
33
+ ```html
34
+ <!-- pages/dashboard.html -->
35
+ <div style="display: flex; gap: 20px; padding: 20px; background: #0a0e1a; color: white; height: 100vh;">
36
+ <div style="flex: 1; background: #0f1629; border-radius: 8px; padding: 16px;">
37
+ <h3>CPU Usage</h3>
38
+ <canvas id="cpuChart"></canvas>
39
+ </div>
40
+ <div style="flex: 1; background: #0f1629; border-radius: 8px; padding: 16px;">
41
+ <h3>Memory</h3>
42
+ <div id="memValue" style="font-size: 48px; color: #00e5ff;">--</div>
43
+ </div>
44
+ </div>
45
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
46
+ <script>
47
+ TuiMon.onUpdate(function(data) {
48
+ TuiMon.set('#memValue', data.memory + '%')
49
+ // update your charts, DOM, anything you want
50
+ })
51
+ </script>
52
+ ```
40
53
 
41
54
  ```typescript
55
+ // tuimon.config.ts
56
+ import tuimon from 'tuimon'
57
+
42
58
  const dash = await tuimon.start({
43
59
  pages: {
44
- overview: {
45
- html: './pages/overview.html',
60
+ main: {
61
+ html: './pages/dashboard.html',
46
62
  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',
63
+ keys: {
64
+ F5: { label: 'Refresh', action: async () => dash.render(await getData()) },
65
+ F10: { label: 'Quit', action: () => process.exit(0) },
66
+ },
58
67
  },
59
68
  },
69
+ refresh: 1000,
70
+ data: getData,
60
71
  })
61
72
  ```
62
73
 
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
74
+ ### Multiple Pages
67
75
 
68
- Add shortcut badges to HTML panels with data attributes:
76
+ You can define multiple HTML pages and let users switch between them with keyboard shortcuts. Press a letter to jump to a detail page, ESC to go back.
69
77
 
70
- ```html
71
- <div class="panel" data-tm-key="g" data-tm-label="CPU Detail">
72
- <!-- panel content -->
73
- </div>
78
+ ```typescript
79
+ pages: {
80
+ overview: { html: './pages/overview.html', default: true },
81
+ cpu: { html: './pages/cpu-detail.html', shortcut: 'g', label: 'CPU Detail' },
82
+ memory: { html: './pages/memory-detail.html', shortcut: 'm', label: 'Memory' },
83
+ }
74
84
  ```
75
85
 
76
- ## Per-Page F-Key Bindings
86
+ ### Client Library
87
+
88
+ TuiMon automatically injects a small client script into your HTML pages. You use it to receive data updates:
89
+
90
+ - `TuiMon.onUpdate(callback)` receives data whenever `dash.render(data)` is called
91
+ - `TuiMon.set(selector, value)` is a shortcut to update text content or styles
92
+ - `TuiMon.notify(message)` dispatches a notification event
77
93
 
78
- Each page defines its own F-key actions:
94
+ ### Shortcut Badges
95
+
96
+ Add `data-tm-key="g"` to any element and TuiMon automatically renders a `[G]` badge in the corner. Users immediately know they can press G to navigate there.
97
+
98
+ ### F-Key Bar
99
+
100
+ Each page can define its own F-key bindings. The bar at the bottom of the terminal always shows the active page's keys.
101
+
102
+ ---
103
+
104
+ ## 2. Use the Built-in Theme (No HTML Needed)
105
+
106
+ If you don't want to design anything, TuiMon comes with a built-in dark neon theme. Just define your widgets and push data. TuiMon generates the HTML for you behind the scenes.
79
107
 
80
108
  ```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) },
109
+ const dash = await tuimon.start({
110
+ pages: {
111
+ main: {
112
+ default: true,
113
+ layout: {
114
+ title: 'My App',
115
+ stats: [
116
+ { id: 'users', label: 'Users Online', type: 'stat' },
117
+ { id: 'cpu', label: 'CPU', type: 'gauge' },
118
+ ],
119
+ panels: [
120
+ { id: 'traffic', label: 'Traffic', type: 'line', span: 2 },
121
+ { id: 'services', label: 'Services', type: 'doughnut' },
122
+ { id: 'events', label: 'Events', type: 'event-log', throttle: 2000 },
123
+ { id: 'health', label: 'Health', type: 'status-grid', throttle: 5000 },
124
+ ],
125
+ },
88
126
  },
89
127
  },
90
- }
128
+ refresh: 500,
129
+ data: () => ({
130
+ users: 42,
131
+ cpu: 73,
132
+ traffic: { Requests: 340, Errors: 12 },
133
+ services: { Web: 47, API: 27 },
134
+ events: ['Deploy completed'],
135
+ health: ['Node-1', 'Node-2'],
136
+ }),
137
+ })
91
138
  ```
92
139
 
93
- The F-key bar at the bottom always reflects the active page's bindings.
140
+ ### Widget Types
94
141
 
95
- ## API Reference
142
+ There are 8 built-in widget types: `stat`, `gauge`, `line`, `doughnut`, `bar`, `event-log`, `status-grid`, and `table`.
96
143
 
97
- ### `tuimon.start(options: TuiMonOptions): Promise<TuiMonDashboard>`
144
+ ### Just Send Numbers
98
145
 
99
- ```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)
105
- }
146
+ You don't need to learn a data format. Just send the simplest thing and TuiMon figures it out:
106
147
 
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
- }
148
+ | What you send | What TuiMon shows |
149
+ |---------------|-------------------|
150
+ | `42` | Stat card with the number |
151
+ | `73` (for something named cpu or mem) | Gauge bar showing 73% |
152
+ | `{ Requests: 340, Errors: 12 }` | Line chart that builds up over time |
153
+ | `['Deploy completed']` | Event log with automatic timestamps |
154
+ | `['Node-1', 'Node-2']` | Status grid with green dots |
114
155
 
115
- interface KeyBinding {
116
- label: string
117
- action: () => void | Promise<void>
118
- }
119
- ```
156
+ For line charts, you don't manage history. Each render call sends the current values and TuiMon accumulates the history automatically.
157
+
158
+ ### Per-Widget Throttle
159
+
160
+ Each widget can update at its own speed. Your charts can update every frame while your event log only updates every 2 seconds and your status grid every 5 seconds. Just add `throttle: 2000` to any widget config.
161
+
162
+ ---
163
+
164
+ ## 3. Instant Visualization (Zero Setup)
120
165
 
121
- ### `dash.render(data): Promise<void>`
166
+ Sometimes you just need to quickly look at some data. TuiMon can do that too.
122
167
 
123
- Push data to the current page and re-render.
168
+ ### View a File
124
169
 
125
- ### `dash.stop(): Promise<void>`
170
+ ```bash
171
+ tuimon data.json # JSON array of objects, shown as table + charts
172
+ tuimon users.csv # CSV file, auto-detects delimiter
173
+ tuimon access.log # Nginx access log, shows request stats
174
+ tuimon modsec_audit.log # ModSecurity log, shows security dashboard
175
+ tuimon data.json -c "name,age" # Only show specific columns
176
+ ```
177
+
178
+ TuiMon auto-detects the file format, picks the right widgets, and builds a dashboard. It also watches the file for changes so the dashboard updates if the file is modified.
126
179
 
127
- Gracefully shut down restores terminal state.
180
+ Press D to switch to a full-screen data table. Use arrow keys to page through the data. ESC goes back.
128
181
 
129
- ## Client Library
182
+ ### Watch Live Data
130
183
 
131
- In your HTML pages, use the injected `TuiMon` object:
184
+ Create a JS file that exports a function returning your data:
132
185
 
133
- ```javascript
134
- // Listen for data updates
135
- TuiMon.onUpdate(function(data) {
136
- TuiMon.set('#cpu', data.cpu)
137
- TuiMon.set('#memory', data.memory + '%')
186
+ ```js
187
+ // metrics.js
188
+ const os = require('os')
189
+ module.exports = () => ({
190
+ cpu: getCpuPercent(),
191
+ memory: getMemPercent(),
192
+ uptime: process.uptime(),
138
193
  })
194
+ ```
195
+
196
+ ```bash
197
+ tuimon watch metrics.js
198
+ ```
199
+
200
+ TuiMon calls your function every second, auto-detects the data shape, and builds a dashboard.
201
+
202
+ You can also poll an HTTP endpoint that returns JSON:
203
+
204
+ ```bash
205
+ tuimon watch --url http://localhost:3000/metrics
206
+ tuimon watch --url http://localhost:3000/metrics --interval 5000
207
+ ```
208
+
209
+ ### View a Database Table
210
+
211
+ If you are working on a project that already has a database driver installed and a connection string in `.env`, you can view your data directly:
212
+
213
+ ```bash
214
+ tuimon db users # view a table or collection
215
+ tuimon db users --watch # re-query every 2 seconds
216
+ tuimon db "SELECT * FROM orders" # run a custom query
217
+ tuimon db users --query '{"active":true}' # MongoDB filter
218
+ tuimon db users --env MY_DB_URI # use a specific env variable
219
+ tuimon db users -c "name,email,role" # only show these columns
220
+ ```
221
+
222
+ TuiMon finds the database driver in your project's `node_modules/` folder and reads the connection string from your `.env` file. It supports MongoDB, PostgreSQL, MySQL, and SQLite.
223
+
224
+ No new dependencies are installed. TuiMon uses whatever driver your project already has.
225
+
226
+ ---
227
+
228
+ ## Terminal Support
139
229
 
140
- // TuiMon.set(selector, value) sets text content or applies styles
141
- // TuiMon.notify(message, duration) — dispatches a notification event
230
+ | Terminal | Protocol | Status |
231
+ |----------|----------|--------|
232
+ | Kitty | Kitty | Supported |
233
+ | Ghostty | Kitty | Supported |
234
+ | WezTerm | Kitty | Supported |
235
+ | iTerm2 | iTerm2 | Supported |
236
+ | VSCode | Sixel | Supported |
237
+ | mlterm | Sixel | Supported |
238
+
239
+ ### VSCode
240
+
241
+ Running `tuimon init` automatically enables terminal images in VSCode. It creates a `.vscode/settings.json` file with:
242
+
243
+ ```json
244
+ { "terminal.integrated.enableImages": true }
142
245
  ```
143
246
 
247
+ If you are adding TuiMon to an existing project, add that setting manually or run `tuimon init`.
248
+
249
+ ---
250
+
251
+ ## Global Config
252
+
253
+ You can set preferences once so you don't have to repeat them:
254
+
255
+ ```bash
256
+ tuimon config db.envVar MONGODB_URI # which env var holds your DB connection
257
+ tuimon config db.defaultLimit 500 # how many rows to show by default
258
+ tuimon config refresh 250 # default refresh rate in ms
259
+ tuimon config # show current config
260
+ tuimon config --reset # reset everything to defaults
261
+ ```
262
+
263
+ Config is stored in `~/.tuimon/config.json`.
264
+
265
+ ---
266
+
267
+ ## CLI Reference
268
+
269
+ | Command | What it does |
270
+ |---------|--------------|
271
+ | `tuimon <file>` | Visualize a JSON, CSV, or log file |
272
+ | `tuimon watch <file.js>` | Live dashboard from a JS data module |
273
+ | `tuimon watch --url <url>` | Poll a JSON endpoint |
274
+ | `tuimon db <table or query>` | View a database table or run a query |
275
+ | `tuimon start` | Run a custom HTML dashboard from tuimon.config.ts |
276
+ | `tuimon init` | Scaffold a starter project and enable VSCode |
277
+ | `tuimon check` | Check if your terminal supports graphics |
278
+ | `tuimon config` | View or set global preferences |
279
+ | `tuimon ai` | Print the AI integration guide |
280
+
281
+ Set `TUIMON_DEBUG=1` to print per-frame timing to stderr.
282
+
283
+ ---
284
+
285
+ ## How It Works
286
+
287
+ TuiMon runs a headless Chromium browser via Playwright. Your HTML page loads in the browser. TuiMon pushes data into the page, takes a PNG screenshot, encodes it using the Kitty graphics protocol (or Sixel for terminals that need it), and writes it to stdout. The F-key bar and keyboard input run natively in the terminal.
288
+
289
+ A typical frame takes about 50ms from data push to pixels on screen.
290
+
291
+ ---
292
+
144
293
  ## Contributing
145
294
 
146
- - **TDD required** write tests first, implementation second
147
- - Coverage thresholds: 80% lines, 80% functions, 75% branches
148
- - `npm test` must pass before any PR
149
- - Strict TypeScript — `strict: true`, no `any`
295
+ Tests first, implementation second. Coverage thresholds are 80% lines, 80% functions, and 75% branches. TypeScript is strict with no exceptions.
150
296
 
151
297
  ## License
152
298
 
@@ -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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"}