winhelm-mcp 1.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.
Files changed (125) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/LICENSE +21 -0
  3. package/README.md +646 -0
  4. package/dist/config/config-manager.d.ts +50 -0
  5. package/dist/config/config-manager.d.ts.map +1 -0
  6. package/dist/config/config-manager.js +300 -0
  7. package/dist/config/config-manager.js.map +1 -0
  8. package/dist/config/default-config.d.ts +4 -0
  9. package/dist/config/default-config.d.ts.map +1 -0
  10. package/dist/config/default-config.js +48 -0
  11. package/dist/config/default-config.js.map +1 -0
  12. package/dist/config/profiles.d.ts +16 -0
  13. package/dist/config/profiles.d.ts.map +1 -0
  14. package/dist/config/profiles.js +208 -0
  15. package/dist/config/profiles.js.map +1 -0
  16. package/dist/engine/filesystem.d.ts +52 -0
  17. package/dist/engine/filesystem.d.ts.map +1 -0
  18. package/dist/engine/filesystem.js +499 -0
  19. package/dist/engine/filesystem.js.map +1 -0
  20. package/dist/engine/http-client.d.ts +10 -0
  21. package/dist/engine/http-client.d.ts.map +1 -0
  22. package/dist/engine/http-client.js +93 -0
  23. package/dist/engine/http-client.js.map +1 -0
  24. package/dist/engine/pdf-generator.d.ts +15 -0
  25. package/dist/engine/pdf-generator.d.ts.map +1 -0
  26. package/dist/engine/pdf-generator.js +325 -0
  27. package/dist/engine/pdf-generator.js.map +1 -0
  28. package/dist/engine/powershell-runner.d.ts +23 -0
  29. package/dist/engine/powershell-runner.d.ts.map +1 -0
  30. package/dist/engine/powershell-runner.js +148 -0
  31. package/dist/engine/powershell-runner.js.map +1 -0
  32. package/dist/engine/ripgrep.d.ts +20 -0
  33. package/dist/engine/ripgrep.d.ts.map +1 -0
  34. package/dist/engine/ripgrep.js +173 -0
  35. package/dist/engine/ripgrep.js.map +1 -0
  36. package/dist/engine/system.d.ts +67 -0
  37. package/dist/engine/system.d.ts.map +1 -0
  38. package/dist/engine/system.js +558 -0
  39. package/dist/engine/system.js.map +1 -0
  40. package/dist/engine/task-manager.d.ts +66 -0
  41. package/dist/engine/task-manager.d.ts.map +1 -0
  42. package/dist/engine/task-manager.js +203 -0
  43. package/dist/engine/task-manager.js.map +1 -0
  44. package/dist/gateway/dashboard-html.d.ts +7 -0
  45. package/dist/gateway/dashboard-html.d.ts.map +1 -0
  46. package/dist/gateway/dashboard-html.js +624 -0
  47. package/dist/gateway/dashboard-html.js.map +1 -0
  48. package/dist/gateway/preview-html.d.ts +5 -0
  49. package/dist/gateway/preview-html.d.ts.map +1 -0
  50. package/dist/gateway/preview-html.js +351 -0
  51. package/dist/gateway/preview-html.js.map +1 -0
  52. package/dist/gateway/rate-limiter.d.ts +8 -0
  53. package/dist/gateway/rate-limiter.d.ts.map +1 -0
  54. package/dist/gateway/rate-limiter.js +51 -0
  55. package/dist/gateway/rate-limiter.js.map +1 -0
  56. package/dist/gateway/server.d.ts +18 -0
  57. package/dist/gateway/server.d.ts.map +1 -0
  58. package/dist/gateway/server.js +337 -0
  59. package/dist/gateway/server.js.map +1 -0
  60. package/dist/gateway/sse-gateway.d.ts +43 -0
  61. package/dist/gateway/sse-gateway.d.ts.map +1 -0
  62. package/dist/gateway/sse-gateway.js +161 -0
  63. package/dist/gateway/sse-gateway.js.map +1 -0
  64. package/dist/gateway/streamable-gateway.d.ts +39 -0
  65. package/dist/gateway/streamable-gateway.d.ts.map +1 -0
  66. package/dist/gateway/streamable-gateway.js +176 -0
  67. package/dist/gateway/streamable-gateway.js.map +1 -0
  68. package/dist/index.d.ts +5 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +164 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/tools/desktop-tools.d.ts +3 -0
  73. package/dist/tools/desktop-tools.d.ts.map +1 -0
  74. package/dist/tools/desktop-tools.js +280 -0
  75. package/dist/tools/desktop-tools.js.map +1 -0
  76. package/dist/tools/file-tools.d.ts +3 -0
  77. package/dist/tools/file-tools.d.ts.map +1 -0
  78. package/dist/tools/file-tools.js +433 -0
  79. package/dist/tools/file-tools.js.map +1 -0
  80. package/dist/tools/index.d.ts +12 -0
  81. package/dist/tools/index.d.ts.map +1 -0
  82. package/dist/tools/index.js +16 -0
  83. package/dist/tools/index.js.map +1 -0
  84. package/dist/tools/network-tools.d.ts +3 -0
  85. package/dist/tools/network-tools.d.ts.map +1 -0
  86. package/dist/tools/network-tools.js +108 -0
  87. package/dist/tools/network-tools.js.map +1 -0
  88. package/dist/tools/registry.d.ts +50 -0
  89. package/dist/tools/registry.d.ts.map +1 -0
  90. package/dist/tools/registry.js +54 -0
  91. package/dist/tools/registry.js.map +1 -0
  92. package/dist/tools/terminal-tools.d.ts +3 -0
  93. package/dist/tools/terminal-tools.d.ts.map +1 -0
  94. package/dist/tools/terminal-tools.js +152 -0
  95. package/dist/tools/terminal-tools.js.map +1 -0
  96. package/dist/tools/tool-wrapper.d.ts +7 -0
  97. package/dist/tools/tool-wrapper.d.ts.map +1 -0
  98. package/dist/tools/tool-wrapper.js +47 -0
  99. package/dist/tools/tool-wrapper.js.map +1 -0
  100. package/dist/types/index.d.ts +261 -0
  101. package/dist/types/index.d.ts.map +1 -0
  102. package/dist/types/index.js +2 -0
  103. package/dist/types/index.js.map +1 -0
  104. package/dist/utils/file-logger.d.ts +24 -0
  105. package/dist/utils/file-logger.d.ts.map +1 -0
  106. package/dist/utils/file-logger.js +117 -0
  107. package/dist/utils/file-logger.js.map +1 -0
  108. package/dist/utils/logger.d.ts +51 -0
  109. package/dist/utils/logger.d.ts.map +1 -0
  110. package/dist/utils/logger.js +189 -0
  111. package/dist/utils/logger.js.map +1 -0
  112. package/dist/utils/sanitizer.d.ts +13 -0
  113. package/dist/utils/sanitizer.d.ts.map +1 -0
  114. package/dist/utils/sanitizer.js +60 -0
  115. package/dist/utils/sanitizer.js.map +1 -0
  116. package/docs/EXAMPLES.md +171 -0
  117. package/docs/PROFILES.md +423 -0
  118. package/docs/SECURITY.md +190 -0
  119. package/docs/TOOLS.md +366 -0
  120. package/manifest.json +74 -0
  121. package/package.json +89 -0
  122. package/scripts/build-exe.ps1 +37 -0
  123. package/scripts/manage-service.ps1 +112 -0
  124. package/server.json +23 -0
  125. package/winhelm.config.example.json +30 -0
@@ -0,0 +1,624 @@
1
+ import { PROFILES } from "../config/profiles.js";
2
+ /**
3
+ * Lightweight, zero-dependency, self-contained Web Monitor Dashboard for WinHelm.
4
+ * Served directly by Express without external CDN dependencies.
5
+ */
6
+ export function getDashboardHtml(activeProfile = "full") {
7
+ const profileDef = PROFILES[activeProfile] || PROFILES.full;
8
+ const activeTools = profileDef.tools;
9
+ const activeCount = activeTools.length;
10
+ const renderTool = (name, color) => {
11
+ const isAct = activeTools.includes(name);
12
+ if (isAct) {
13
+ return `<div class="tool-item"><span class="tool-dot" style="background: ${color};"></span> ${name}</div>`;
14
+ }
15
+ return `<div class="tool-item inactive" title="Not loaded in ${profileDef.name} profile"><span class="tool-dot" style="background: #4b5563;"></span> <span style="text-decoration: line-through; opacity: 0.6;">${name}</span></div>`;
16
+ };
17
+ const renderResource = () => {
18
+ if (profileDef.includesResource) {
19
+ return `<div class="tool-item"><span class="tool-dot" style="background: #eab308;"></span> preview://file</div>`;
20
+ }
21
+ return `<div class="tool-item inactive" title="Not loaded in ${profileDef.name} profile"><span class="tool-dot" style="background: #4b5563;"></span> <span style="text-decoration: line-through; opacity: 0.6;">preview://file</span></div>`;
22
+ };
23
+ return `<!DOCTYPE html>
24
+ <html lang="en">
25
+ <head>
26
+ <meta charset="UTF-8">
27
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
28
+ <title>WinHelm | Monitor Dashboard</title>
29
+ <style>
30
+ :root {
31
+ --bg: #0b0f19;
32
+ --card-bg: #111827;
33
+ --card-border: #1f2937;
34
+ --text-main: #f3f4f6;
35
+ --text-muted: #9ca3af;
36
+ --primary: #3b82f6;
37
+ --primary-hover: #2563eb;
38
+ --success: #10b981;
39
+ --warning: #f59e0b;
40
+ --danger: #ef4444;
41
+ --purple: #8b5cf6;
42
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
43
+ }
44
+ * { box-sizing: border-box; margin: 0; padding: 0; }
45
+ body {
46
+ background-color: var(--bg);
47
+ color: var(--text-main);
48
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
49
+ line-height: 1.5;
50
+ padding: 24px;
51
+ min-height: 100vh;
52
+ }
53
+ .container { max-width: 1300px; margin: 0 auto; }
54
+
55
+ /* Header */
56
+ header {
57
+ display: flex;
58
+ justify-content: space-between;
59
+ align-items: center;
60
+ padding-bottom: 20px;
61
+ border-bottom: 1px solid var(--card-border);
62
+ margin-bottom: 24px;
63
+ flex-wrap: wrap;
64
+ gap: 16px;
65
+ }
66
+ .logo-area { display: flex; align-items: center; gap: 12px; }
67
+ .status-badge {
68
+ display: inline-flex;
69
+ align-items: center;
70
+ gap: 6px;
71
+ background: rgba(16, 185, 129, 0.15);
72
+ color: var(--success);
73
+ padding: 4px 10px;
74
+ border-radius: 9999px;
75
+ font-size: 13px;
76
+ font-weight: 600;
77
+ border: 1px solid rgba(16, 185, 129, 0.3);
78
+ }
79
+ .pulse-dot {
80
+ width: 8px;
81
+ height: 8px;
82
+ background-color: var(--success);
83
+ border-radius: 50%;
84
+ box-shadow: 0 0 8px var(--success);
85
+ animation: pulse 2s infinite;
86
+ }
87
+ @keyframes pulse {
88
+ 0% { transform: scale(0.95); opacity: 0.8; }
89
+ 50% { transform: scale(1.2); opacity: 1; }
90
+ 100% { transform: scale(0.95); opacity: 0.8; }
91
+ }
92
+ .header-controls { display: flex; align-items: center; gap: 12px; }
93
+ button {
94
+ background: var(--card-bg);
95
+ color: var(--text-main);
96
+ border: 1px solid var(--card-border);
97
+ padding: 8px 14px;
98
+ border-radius: 6px;
99
+ cursor: pointer;
100
+ font-size: 13px;
101
+ font-weight: 500;
102
+ display: inline-flex;
103
+ align-items: center;
104
+ gap: 6px;
105
+ transition: all 0.2s;
106
+ }
107
+ button:hover { background: #1f2937; border-color: #374151; }
108
+ button.primary { background: var(--primary); border-color: var(--primary); color: #fff; }
109
+ button.primary:hover { background: var(--primary-hover); }
110
+ .toggle-label {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 6px;
114
+ font-size: 13px;
115
+ color: var(--text-muted);
116
+ cursor: pointer;
117
+ }
118
+
119
+ /* Grid Layout */
120
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-bottom: 24px; }
121
+ .card {
122
+ background: var(--card-bg);
123
+ border: 1px solid var(--card-border);
124
+ border-radius: 10px;
125
+ padding: 20px;
126
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
127
+ }
128
+ .card-title {
129
+ font-size: 13px;
130
+ text-transform: uppercase;
131
+ letter-spacing: 0.05em;
132
+ color: var(--text-muted);
133
+ margin-bottom: 12px;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: space-between;
137
+ }
138
+ .metric-value { font-size: 28px; font-weight: 700; color: #fff; }
139
+ .metric-sub { font-size: 13px; color: var(--text-muted); margin-top: 4px; }
140
+
141
+ /* Progress bars */
142
+ .progress-bar-bg {
143
+ background: #1f2937;
144
+ height: 8px;
145
+ border-radius: 4px;
146
+ overflow: hidden;
147
+ margin-top: 10px;
148
+ }
149
+ .progress-bar-fill {
150
+ height: 100%;
151
+ background: var(--primary);
152
+ border-radius: 4px;
153
+ transition: width 0.4s ease;
154
+ }
155
+ .fill-green { background: var(--success); }
156
+ .fill-yellow { background: var(--warning); }
157
+ .fill-red { background: var(--danger); }
158
+
159
+ /* Drives list */
160
+ .drive-row {
161
+ display: flex;
162
+ justify-content: space-between;
163
+ align-items: center;
164
+ font-size: 13px;
165
+ margin-top: 8px;
166
+ }
167
+
168
+ /* Live Feed / Table */
169
+ .feed-header {
170
+ display: flex;
171
+ justify-content: space-between;
172
+ align-items: center;
173
+ margin-bottom: 16px;
174
+ flex-wrap: wrap;
175
+ gap: 12px;
176
+ }
177
+ .filter-group { display: flex; gap: 8px; flex-wrap: wrap; }
178
+ .filter-chip {
179
+ background: #1f2937;
180
+ border: 1px solid var(--card-border);
181
+ color: var(--text-muted);
182
+ padding: 4px 10px;
183
+ border-radius: 6px;
184
+ font-size: 12px;
185
+ cursor: pointer;
186
+ }
187
+ .filter-chip.active { background: var(--primary); color: #fff; border-color: var(--primary); }
188
+
189
+ .table-container {
190
+ overflow-x: auto;
191
+ background: var(--card-bg);
192
+ border: 1px solid var(--card-border);
193
+ border-radius: 10px;
194
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
195
+ }
196
+ table { width: 100%; border-collapse: collapse; text-align: left; font-size: 13px; }
197
+ th {
198
+ background: #161f30;
199
+ color: var(--text-muted);
200
+ font-weight: 600;
201
+ padding: 12px 16px;
202
+ border-bottom: 1px solid var(--card-border);
203
+ text-transform: uppercase;
204
+ font-size: 11px;
205
+ letter-spacing: 0.05em;
206
+ }
207
+ td {
208
+ padding: 12px 16px;
209
+ border-bottom: 1px solid var(--card-border);
210
+ color: #e5e7eb;
211
+ font-family: var(--font-mono);
212
+ font-size: 12px;
213
+ }
214
+ tr:hover td { background: rgba(255, 255, 255, 0.02); }
215
+
216
+ /* Badges */
217
+ .badge {
218
+ display: inline-block;
219
+ padding: 2px 8px;
220
+ border-radius: 4px;
221
+ font-size: 11px;
222
+ font-weight: 600;
223
+ text-transform: uppercase;
224
+ }
225
+ .badge-tool { background: rgba(139, 92, 246, 0.2); color: #c4b5fd; border: 1px solid rgba(139, 92, 246, 0.4); }
226
+ .badge-req { background: rgba(59, 130, 246, 0.2); color: #93c5fd; border: 1px solid rgba(59, 130, 246, 0.4); }
227
+ .badge-sec { background: rgba(245, 158, 11, 0.2); color: #fde68a; border: 1px solid rgba(245, 158, 11, 0.4); }
228
+ .badge-err { background: rgba(239, 68, 68, 0.2); color: #fca5a5; border: 1px solid rgba(239, 68, 68, 0.4); }
229
+
230
+ .status-tag {
231
+ padding: 2px 6px;
232
+ border-radius: 4px;
233
+ font-size: 11px;
234
+ font-weight: 600;
235
+ }
236
+ .status-success { color: var(--success); }
237
+ .status-running { color: var(--warning); }
238
+ .status-fail { color: var(--danger); }
239
+
240
+ .tools-grid {
241
+ display: grid;
242
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
243
+ gap: 10px;
244
+ margin-top: 12px;
245
+ }
246
+ .tool-item {
247
+ background: #161f30;
248
+ border: 1px solid var(--card-border);
249
+ padding: 8px 12px;
250
+ border-radius: 6px;
251
+ font-family: var(--font-mono);
252
+ font-size: 12px;
253
+ color: #93c5fd;
254
+ display: flex;
255
+ align-items: center;
256
+ gap: 6px;
257
+ }
258
+ .tool-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--success); }
259
+ .tool-item.inactive {
260
+ opacity: 0.35;
261
+ background: #0d131f;
262
+ border: 1px dashed #374151;
263
+ color: #6b7280;
264
+ }
265
+ </style>
266
+ </head>
267
+ <body>
268
+ <div class="container">
269
+ <header>
270
+ <div class="logo-area">
271
+ <h2>⚡ WinHelm</h2>
272
+ <span class="status-badge"><span class="pulse-dot"></span> LIVE MONITOR</span>
273
+ <span class="status-badge" style="background: rgba(99, 102, 241, 0.2); color: #a5b4fc; border: 1px solid rgba(99, 102, 241, 0.4); text-transform: uppercase;">PROFILE: ${profileDef.name.toUpperCase()} (${activeCount} TOOLS)</span>
274
+ </div>
275
+ <div class="header-controls">
276
+ <label class="toggle-label">
277
+ <input type="checkbox" id="autoRefresh" checked> Auto-refresh (2.5s)
278
+ </label>
279
+ <button id="btnRefresh" onclick="fetchData()">🔄 Refresh</button>
280
+ <button onclick="window.open('/api/monitor/export?format=json')">📥 Export JSON</button>
281
+ <button onclick="window.open('/api/monitor/export?format=csv')">📥 Export CSV</button>
282
+ <button id="btnClear" onclick="clearLogs()">🗑️ Clear</button>
283
+ </div>
284
+ </header>
285
+
286
+ <!-- Top Metrics -->
287
+ <div class="grid">
288
+ <!-- Card 1: Server Status -->
289
+ <div class="card">
290
+ <div class="card-title">Server Runtime</div>
291
+ <div class="metric-value" id="uptimeText">--</div>
292
+ <div class="metric-sub" id="serverInfoText">WinHelm v1.0.0</div>
293
+ </div>
294
+
295
+ <!-- Card 2: Active MCP Sessions -->
296
+ <div class="card">
297
+ <div class="card-title">Connected Sessions</div>
298
+ <div class="metric-value" id="activeSessionsText">0</div>
299
+ <div class="metric-sub" id="sessionBreakdown">Streamable: 0 | SSE: 0 | Tasks: 0</div>
300
+ </div>
301
+
302
+ <!-- Card 3: CPU Usage -->
303
+ <div class="card">
304
+ <div class="card-title">CPU Load</div>
305
+ <div class="metric-value" id="cpuLoadText">-- %</div>
306
+ <div class="progress-bar-bg">
307
+ <div class="progress-bar-fill" id="cpuBar" style="width: 0%"></div>
308
+ </div>
309
+ </div>
310
+
311
+ <!-- Card 4: RAM Usage -->
312
+ <div class="card">
313
+ <div class="card-title">Memory (RAM)</div>
314
+ <div class="metric-value" id="ramText">-- / -- GB</div>
315
+ <div class="progress-bar-bg">
316
+ <div class="progress-bar-fill fill-green" id="ramBar" style="width: 0%"></div>
317
+ </div>
318
+ </div>
319
+ </div>
320
+
321
+ <!-- Hardware: Drives & GPU -->
322
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; margin-bottom: 24px;">
323
+ <!-- Drives Info -->
324
+ <div class="card">
325
+ <div class="card-title">Storage Drives</div>
326
+ <div id="drivesContainer" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; margin-top: 8px;">
327
+ <div style="color: var(--text-muted); font-size: 13px;">Reading drive metrics...</div>
328
+ </div>
329
+ </div>
330
+
331
+ <!-- GPU Telemetry Card -->
332
+ <div class="card" id="gpuCard">
333
+ <div class="card-title">GPU Telemetry</div>
334
+ <div id="gpuContainer" style="margin-top: 8px; font-size: 13px; color: var(--text-muted);">
335
+ Detecting GPU...
336
+ </div>
337
+ </div>
338
+ </div>
339
+
340
+ <!-- Live Activity Table -->
341
+ <div class="feed-header">
342
+ <h3 style="font-size: 16px; font-weight: 600;">Activity & Execution Stream</h3>
343
+ <div class="filter-group">
344
+ <span class="filter-chip active" onclick="setFilter('all', this)">All</span>
345
+ <span class="filter-chip" onclick="setFilter('tool', this)">Tools</span>
346
+ <span class="filter-chip" onclick="setFilter('req', this)">HTTP Requests</span>
347
+ <span class="filter-chip" onclick="setFilter('security', this)">Security</span>
348
+ <span class="filter-chip" onclick="setFilter('error', this)">Errors</span>
349
+ </div>
350
+ </div>
351
+
352
+ <div class="table-container">
353
+ <table>
354
+ <thead>
355
+ <tr>
356
+ <th style="width: 100px;">Time</th>
357
+ <th style="width: 110px;">Type</th>
358
+ <th style="width: 200px;">Event</th>
359
+ <th>Details</th>
360
+ <th style="width: 90px;">Latency</th>
361
+ <th style="width: 100px;">Status</th>
362
+ </tr>
363
+ </thead>
364
+ <tbody id="logsTableBody">
365
+ <tr><td colspan="6" style="text-align: center; color: var(--text-muted); padding: 24px;">No logs recorded yet</td></tr>
366
+ </tbody>
367
+ </table>
368
+ </div>
369
+
370
+ <!-- Registered Tools Reference -->
371
+ <div class="card" style="margin-top: 24px;">
372
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
373
+ <div class="card-title" style="margin-bottom: 0;">Registered Tools (${activeCount} Active in ${profileDef.name} Profile / 38 Total)</div>
374
+ <div style="font-size: 12px; color: var(--text-muted); display: flex; gap: 12px; flex-wrap: wrap;">
375
+ <span><span class="tool-dot" style="background: #10b981;"></span> Terminal</span>
376
+ <span><span class="tool-dot" style="background: #8b5cf6;"></span> Background Tasks</span>
377
+ <span><span class="tool-dot" style="background: #3b82f6;"></span> Filesystem</span>
378
+ <span><span class="tool-dot" style="background: #f59e0b;"></span> Search & PDF</span>
379
+ <span><span class="tool-dot" style="background: #ec4899;"></span> Desktop</span>
380
+ <span><span class="tool-dot" style="background: #06b6d4;"></span> System & Services</span>
381
+ <span><span class="tool-dot" style="background: #14b8a6;"></span> Network</span>
382
+ </div>
383
+ </div>
384
+ <div class="tools-grid">
385
+ <!-- Terminal & Tasks -->
386
+ ${renderTool("terminal_run", "#10b981")}
387
+ ${renderTool("terminal_task_start", "#8b5cf6")}
388
+ ${renderTool("terminal_task_list", "#8b5cf6")}
389
+ ${renderTool("terminal_task_logs", "#8b5cf6")}
390
+ ${renderTool("terminal_task_send", "#8b5cf6")}
391
+ ${renderTool("terminal_task_kill", "#8b5cf6")}
392
+ <!-- Filesystem & Archives -->
393
+ ${renderTool("file_read", "#3b82f6")}
394
+ ${renderTool("file_write", "#3b82f6")}
395
+ ${renderTool("file_edit", "#3b82f6")}
396
+ ${renderTool("file_list", "#3b82f6")}
397
+ ${renderTool("file_search", "#3b82f6")}
398
+ ${renderTool("file_delete_safe", "#3b82f6")}
399
+ ${renderTool("file_move", "#3b82f6")}
400
+ ${renderTool("file_copy", "#3b82f6")}
401
+ ${renderTool("archive_zip", "#3b82f6")}
402
+ ${renderTool("archive_unzip", "#3b82f6")}
403
+ ${renderTool("file_tail", "#3b82f6")}
404
+ ${renderTool("file_hash", "#3b82f6")}
405
+ <!-- Search & Documents -->
406
+ ${renderTool("file_search_ripgrep", "#f59e0b")}
407
+ ${renderTool("pdf_generate", "#f59e0b")}
408
+ ${renderTool("file_preview", "#f59e0b")}
409
+ <!-- Desktop, Clipboard & Toast -->
410
+ ${renderTool("clipboard_get", "#ec4899")}
411
+ ${renderTool("clipboard_set", "#ec4899")}
412
+ ${renderTool("screen_capture", "#ec4899")}
413
+ ${renderTool("system_open", "#ec4899")}
414
+ ${renderTool("notification_send", "#ec4899")}
415
+ <!-- System, Hardware & Services -->
416
+ ${renderTool("system_info", "#06b6d4")}
417
+ ${renderTool("gpu_info", "#06b6d4")}
418
+ ${renderTool("process_list", "#06b6d4")}
419
+ ${renderTool("process_kill", "#06b6d4")}
420
+ ${renderTool("port_check", "#06b6d4")}
421
+ ${renderTool("eventlog_query", "#06b6d4")}
422
+ ${renderTool("service_list", "#06b6d4")}
423
+ ${renderTool("service_status", "#06b6d4")}
424
+ ${renderTool("service_control", "#06b6d4")}
425
+ <!-- Network & Probe -->
426
+ ${renderTool("http_ping", "#14b8a6")}
427
+ ${renderTool("http_request", "#14b8a6")}
428
+ ${renderTool("network_info", "#14b8a6")}
429
+ <!-- MCP Resource -->
430
+ ${renderResource()}
431
+ </div>
432
+ </div>
433
+ </div>
434
+
435
+ <script>
436
+ let currentFilter = 'all';
437
+ let logsCache = [];
438
+
439
+ function formatUptime(seconds) {
440
+ const h = Math.floor(seconds / 3600);
441
+ const m = Math.floor((seconds % 3600) / 60);
442
+ const s = seconds % 60;
443
+ return \`\${h}h \${m}m \${s}s\`;
444
+ }
445
+
446
+ function formatTime(isoStr) {
447
+ if (!isoStr) return '--:--:--';
448
+ const d = new Date(isoStr);
449
+ return d.toLocaleTimeString();
450
+ }
451
+
452
+ function setFilter(type, el) {
453
+ currentFilter = type;
454
+ document.querySelectorAll('.filter-chip').forEach(c => c.classList.remove('active'));
455
+ el.classList.add('active');
456
+ renderLogs();
457
+ }
458
+
459
+ function renderLogs() {
460
+ const tbody = document.getElementById('logsTableBody');
461
+ const filtered = logsCache.filter(item => {
462
+ if (currentFilter === 'all') return true;
463
+ if (currentFilter === 'tool') return item.type === 'tool';
464
+ if (currentFilter === 'req') return item.type === 'req';
465
+ if (currentFilter === 'security') return item.type === 'security';
466
+ if (currentFilter === 'error') return item.type === 'error' || item.level === 'error';
467
+ return true;
468
+ });
469
+
470
+ if (filtered.length === 0) {
471
+ tbody.innerHTML = '<tr><td colspan="6" style="text-align: center; color: var(--text-muted); padding: 24px;">No matching events</td></tr>';
472
+ return;
473
+ }
474
+
475
+ tbody.innerHTML = filtered.map(log => {
476
+ let badgeClass = 'badge-tool';
477
+ let typeLabel = 'TOOL';
478
+ if (log.type === 'req') { badgeClass = 'badge-req'; typeLabel = 'HTTP'; }
479
+ if (log.type === 'security') { badgeClass = 'badge-sec'; typeLabel = 'SECURITY'; }
480
+ if (log.type === 'error' || log.level === 'error') { badgeClass = 'badge-err'; typeLabel = 'ERROR'; }
481
+
482
+ let statusClass = 'status-success';
483
+ if (log.status === 'RUNNING') statusClass = 'status-running';
484
+ if (log.status === 'FAILED' || log.status === 'BLOCKED' || (typeof log.status === 'number' && log.status >= 400)) statusClass = 'status-fail';
485
+
486
+ const duration = log.durationMs !== undefined ? \`\${log.durationMs}ms\` : '-';
487
+ const detail = log.detail ? log.detail.replace(/</g, '&lt;').replace(/>/g, '&gt;') : '-';
488
+
489
+ return \`
490
+ <tr>
491
+ <td style="color: var(--text-muted)">\${formatTime(log.timestamp)}</td>
492
+ <td><span class="badge \${badgeClass}">\${typeLabel}</span></td>
493
+ <td style="font-weight: 600; color: #fff;">\${log.title}</td>
494
+ <td style="color: #cbd5e1; word-break: break-all;">\${detail}</td>
495
+ <td style="color: var(--text-muted)">\${duration}</td>
496
+ <td><span class="status-tag \${statusClass}">\${log.status || 'OK'}</span></td>
497
+ </tr>
498
+ \`;
499
+ }).join('');
500
+ }
501
+
502
+ async function fetchData() {
503
+ try {
504
+ const urlParams = new URLSearchParams(window.location.search);
505
+ const token = urlParams.get('token') || urlParams.get('auth');
506
+ if (token) {
507
+ document.cookie = 'token=' + encodeURIComponent(token) + '; path=/; SameSite=Lax';
508
+ }
509
+ const tokenQuery = token ? '?token=' + encodeURIComponent(token) : '';
510
+
511
+ const [statsRes, logsRes] = await Promise.all([
512
+ fetch('/api/monitor/stats' + tokenQuery).then(r => r.json()),
513
+ fetch('/api/monitor/logs' + tokenQuery).then(r => r.json())
514
+ ]);
515
+
516
+ // Server & Uptime
517
+ document.getElementById('uptimeText').textContent = formatUptime(statsRes.uptimeSeconds || 0);
518
+ document.getElementById('serverInfoText').textContent = \`Port: \${statsRes.port} | Host: \${statsRes.host}\`;
519
+
520
+ // Sessions
521
+ const sse = statsRes.activeSessions?.sse || 0;
522
+ const http = statsRes.activeSessions?.streamableHttp || 0;
523
+ document.getElementById('sessionBreakdown').textContent = \`Streamable: \${http} | SSE: \${sse} | Tasks: \${statsRes.backgroundTasks || 0}\`;
524
+
525
+ // CPU
526
+ if (statsRes.system?.CpuLoadPercentage !== undefined) {
527
+ const cpu = statsRes.system.CpuLoadPercentage;
528
+ document.getElementById('cpuLoadText').textContent = \`\${cpu}%\`;
529
+ const cpuBar = document.getElementById('cpuBar');
530
+ cpuBar.style.width = \`\${Math.min(100, Math.max(0, cpu))}%\`;
531
+ cpuBar.className = \`progress-bar-fill \${cpu > 80 ? 'fill-red' : cpu > 50 ? 'fill-yellow' : 'fill-green'}\`;
532
+ }
533
+
534
+ // RAM
535
+ if (statsRes.system?.TotalRamGB && statsRes.system?.UsedRamGB) {
536
+ const used = statsRes.system.UsedRamGB;
537
+ const total = statsRes.system.TotalRamGB;
538
+ const pct = Math.round((used / total) * 100);
539
+ document.getElementById('ramText').textContent = \`\${used} / \${total} GB (\${pct}%)\`;
540
+ const ramBar = document.getElementById('ramBar');
541
+ ramBar.style.width = \`\${pct}%\`;
542
+ ramBar.className = \`progress-bar-fill \${pct > 85 ? 'fill-red' : pct > 65 ? 'fill-yellow' : 'fill-green'}\`;
543
+ }
544
+
545
+ // Drives
546
+ if (statsRes.system?.Drives && Array.isArray(statsRes.system.Drives)) {
547
+ const drivesHtml = statsRes.system.Drives.map(d => {
548
+ const usedPct = Math.round((d.UsedGB / d.TotalGB) * 100) || 0;
549
+ return \`
550
+ <div style="background: #161f30; padding: 12px; border-radius: 6px; border: 1px solid var(--card-border);">
551
+ <div class="drive-row" style="font-weight: 600; color: #fff;">
552
+ <span>Drive \${d.Name}:</span>
553
+ <span>\${d.FreeGB} GB Free / \${d.TotalGB} GB</span>
554
+ </div>
555
+ <div class="progress-bar-bg" style="margin-top: 6px;">
556
+ <div class="progress-bar-fill \${usedPct > 90 ? 'fill-red' : 'fill-green'}" style="width: \${usedPct}%"></div>
557
+ </div>
558
+ </div>
559
+ \`;
560
+ }).join('');
561
+ document.getElementById('drivesContainer').innerHTML = drivesHtml;
562
+ }
563
+
564
+ // GPU Telemetry
565
+ const gpuContainer = document.getElementById('gpuContainer');
566
+ if (statsRes.gpu && statsRes.gpu.gpus && statsRes.gpu.gpus.length > 0) {
567
+ const gpuHtml = statsRes.gpu.gpus.map(g => {
568
+ const vramPct = g.memoryTotalMB ? Math.round((g.memoryUsedMB / g.memoryTotalMB) * 100) : 0;
569
+ const tempText = g.temperatureC ? g.temperatureC + '°C' : '';
570
+ const tempColor = g.temperatureC > 75 ? 'var(--danger)' : 'var(--success)';
571
+ return \`
572
+ <div style="background: #161f30; padding: 12px; border-radius: 6px; border: 1px solid var(--card-border); margin-bottom: 8px;">
573
+ <div style="display: flex; justify-content: space-between; font-weight: 600; color: #fff;">
574
+ <span>\${g.name}</span>
575
+ <span style="color: \${tempColor};">\${tempText}</span>
576
+ </div>
577
+ \${g.memoryTotalMB ? \`
578
+ <div style="display: flex; justify-content: space-between; font-size: 12px; color: var(--text-muted); margin-top: 4px;">
579
+ <span>VRAM: \${g.memoryUsedMB} MB / \${g.memoryTotalMB} MB</span>
580
+ <span>Driver: \${g.driverVersion || 'N/A'}</span>
581
+ </div>
582
+ <div class="progress-bar-bg" style="margin-top: 6px;">
583
+ <div class="progress-bar-fill \${vramPct > 85 ? 'fill-red' : 'fill-green'}" style="width: \${vramPct}%"></div>
584
+ </div>
585
+ \` : '<div style="font-size: 12px; color: var(--text-muted); margin-top: 4px;">Integrated / WMI GPU Active</div>'}
586
+ </div>
587
+ \`;
588
+ }).join('');
589
+ gpuContainer.innerHTML = gpuHtml;
590
+ } else {
591
+ gpuContainer.innerHTML = '<div style="color: var(--text-muted); font-size: 13px;">Standard Graphics Adapter Active (No dedicated NVIDIA GPU detected)</div>';
592
+ }
593
+
594
+ // Logs
595
+ logsCache = logsRes.logs || [];
596
+ renderLogs();
597
+ } catch (err) {
598
+ console.warn('Dashboard fetch error:', err);
599
+ }
600
+ }
601
+
602
+ async function clearLogs() {
603
+ const urlParams = new URLSearchParams(window.location.search);
604
+ const token = urlParams.get('token') || urlParams.get('auth');
605
+ const tokenQuery = token ? '?token=' + encodeURIComponent(token) : '';
606
+ await fetch('/api/monitor/logs' + tokenQuery, { method: 'DELETE' });
607
+ logsCache = [];
608
+ renderLogs();
609
+ }
610
+
611
+ // Auto-refresh interval
612
+ setInterval(() => {
613
+ if (document.getElementById('autoRefresh').checked) {
614
+ fetchData();
615
+ }
616
+ }, 2500);
617
+
618
+ // Initial fetch
619
+ fetchData();
620
+ </script>
621
+ </body>
622
+ </html>`;
623
+ }
624
+ //# sourceMappingURL=dashboard-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-html.js","sourceRoot":"","sources":["../../src/gateway/dashboard-html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generate standalone responsive Dark-Mode HTML preview page for any file
3
+ */
4
+ export declare function getFilePreviewHtml(filePath: string): Promise<string>;
5
+ //# sourceMappingURL=preview-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-html.d.ts","sourceRoot":"","sources":["../../src/gateway/preview-html.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+T1E"}