@appkit/llamacpp-cli 1.11.0 → 1.12.1

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 (126) hide show
  1. package/README.md +572 -170
  2. package/dist/cli.js +99 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/admin/config.d.ts +10 -0
  5. package/dist/commands/admin/config.d.ts.map +1 -0
  6. package/dist/commands/admin/config.js +100 -0
  7. package/dist/commands/admin/config.js.map +1 -0
  8. package/dist/commands/admin/logs.d.ts +10 -0
  9. package/dist/commands/admin/logs.d.ts.map +1 -0
  10. package/dist/commands/admin/logs.js +114 -0
  11. package/dist/commands/admin/logs.js.map +1 -0
  12. package/dist/commands/admin/restart.d.ts +2 -0
  13. package/dist/commands/admin/restart.d.ts.map +1 -0
  14. package/dist/commands/admin/restart.js +29 -0
  15. package/dist/commands/admin/restart.js.map +1 -0
  16. package/dist/commands/admin/start.d.ts +2 -0
  17. package/dist/commands/admin/start.d.ts.map +1 -0
  18. package/dist/commands/admin/start.js +30 -0
  19. package/dist/commands/admin/start.js.map +1 -0
  20. package/dist/commands/admin/status.d.ts +2 -0
  21. package/dist/commands/admin/status.d.ts.map +1 -0
  22. package/dist/commands/admin/status.js +82 -0
  23. package/dist/commands/admin/status.js.map +1 -0
  24. package/dist/commands/admin/stop.d.ts +2 -0
  25. package/dist/commands/admin/stop.d.ts.map +1 -0
  26. package/dist/commands/admin/stop.js +21 -0
  27. package/dist/commands/admin/stop.js.map +1 -0
  28. package/dist/commands/logs.d.ts +1 -0
  29. package/dist/commands/logs.d.ts.map +1 -1
  30. package/dist/commands/logs.js +22 -0
  31. package/dist/commands/logs.js.map +1 -1
  32. package/dist/lib/admin-manager.d.ts +111 -0
  33. package/dist/lib/admin-manager.d.ts.map +1 -0
  34. package/dist/lib/admin-manager.js +413 -0
  35. package/dist/lib/admin-manager.js.map +1 -0
  36. package/dist/lib/admin-server.d.ts +148 -0
  37. package/dist/lib/admin-server.d.ts.map +1 -0
  38. package/dist/lib/admin-server.js +1161 -0
  39. package/dist/lib/admin-server.js.map +1 -0
  40. package/dist/lib/download-job-manager.d.ts +64 -0
  41. package/dist/lib/download-job-manager.d.ts.map +1 -0
  42. package/dist/lib/download-job-manager.js +164 -0
  43. package/dist/lib/download-job-manager.js.map +1 -0
  44. package/dist/tui/MultiServerMonitorApp.js +1 -1
  45. package/dist/types/admin-config.d.ts +19 -0
  46. package/dist/types/admin-config.d.ts.map +1 -0
  47. package/dist/types/admin-config.js +3 -0
  48. package/dist/types/admin-config.js.map +1 -0
  49. package/dist/utils/log-parser.d.ts +9 -0
  50. package/dist/utils/log-parser.d.ts.map +1 -1
  51. package/dist/utils/log-parser.js +11 -0
  52. package/dist/utils/log-parser.js.map +1 -1
  53. package/package.json +10 -2
  54. package/web/README.md +429 -0
  55. package/web/dist/assets/index-Bin89Lwr.css +1 -0
  56. package/web/dist/assets/index-CVmonw3T.js +17 -0
  57. package/web/dist/index.html +14 -0
  58. package/web/dist/vite.svg +1 -0
  59. package/.versionrc.json +0 -16
  60. package/CHANGELOG.md +0 -203
  61. package/MONITORING-ACCURACY-FIX.md +0 -199
  62. package/PER-PROCESS-METRICS.md +0 -190
  63. package/docs/images/.gitkeep +0 -1
  64. package/src/cli.ts +0 -423
  65. package/src/commands/config-global.ts +0 -38
  66. package/src/commands/config.ts +0 -323
  67. package/src/commands/create.ts +0 -183
  68. package/src/commands/delete.ts +0 -74
  69. package/src/commands/list.ts +0 -37
  70. package/src/commands/logs-all.ts +0 -251
  71. package/src/commands/logs.ts +0 -321
  72. package/src/commands/monitor.ts +0 -110
  73. package/src/commands/ps.ts +0 -84
  74. package/src/commands/pull.ts +0 -44
  75. package/src/commands/rm.ts +0 -107
  76. package/src/commands/router/config.ts +0 -116
  77. package/src/commands/router/logs.ts +0 -256
  78. package/src/commands/router/restart.ts +0 -36
  79. package/src/commands/router/start.ts +0 -60
  80. package/src/commands/router/status.ts +0 -119
  81. package/src/commands/router/stop.ts +0 -33
  82. package/src/commands/run.ts +0 -233
  83. package/src/commands/search.ts +0 -107
  84. package/src/commands/server-show.ts +0 -161
  85. package/src/commands/show.ts +0 -207
  86. package/src/commands/start.ts +0 -101
  87. package/src/commands/stop.ts +0 -39
  88. package/src/commands/tui.ts +0 -25
  89. package/src/lib/config-generator.ts +0 -130
  90. package/src/lib/history-manager.ts +0 -172
  91. package/src/lib/launchctl-manager.ts +0 -225
  92. package/src/lib/metrics-aggregator.ts +0 -257
  93. package/src/lib/model-downloader.ts +0 -328
  94. package/src/lib/model-scanner.ts +0 -157
  95. package/src/lib/model-search.ts +0 -114
  96. package/src/lib/models-dir-setup.ts +0 -46
  97. package/src/lib/port-manager.ts +0 -80
  98. package/src/lib/router-logger.ts +0 -201
  99. package/src/lib/router-manager.ts +0 -414
  100. package/src/lib/router-server.ts +0 -538
  101. package/src/lib/state-manager.ts +0 -206
  102. package/src/lib/status-checker.ts +0 -113
  103. package/src/lib/system-collector.ts +0 -315
  104. package/src/tui/ConfigApp.ts +0 -1085
  105. package/src/tui/HistoricalMonitorApp.ts +0 -587
  106. package/src/tui/ModelsApp.ts +0 -368
  107. package/src/tui/MonitorApp.ts +0 -386
  108. package/src/tui/MultiServerMonitorApp.ts +0 -1833
  109. package/src/tui/RootNavigator.ts +0 -74
  110. package/src/tui/SearchApp.ts +0 -511
  111. package/src/tui/SplashScreen.ts +0 -149
  112. package/src/types/global-config.ts +0 -26
  113. package/src/types/history-types.ts +0 -39
  114. package/src/types/model-info.ts +0 -8
  115. package/src/types/monitor-types.ts +0 -162
  116. package/src/types/router-config.ts +0 -25
  117. package/src/types/server-config.ts +0 -46
  118. package/src/utils/downsample-utils.ts +0 -128
  119. package/src/utils/file-utils.ts +0 -146
  120. package/src/utils/format-utils.ts +0 -98
  121. package/src/utils/log-parser.ts +0 -271
  122. package/src/utils/log-utils.ts +0 -178
  123. package/src/utils/process-utils.ts +0 -316
  124. package/src/utils/prompt-utils.ts +0 -47
  125. package/test-load.sh +0 -100
  126. package/tsconfig.json +0 -20
@@ -1,386 +0,0 @@
1
- import blessed from 'blessed';
2
- import { ServerConfig } from '../types/server-config.js';
3
- import { MetricsAggregator } from '../lib/metrics-aggregator.js';
4
- import { MonitorData } from '../types/monitor-types.js';
5
- import { HistoryManager } from '../lib/history-manager.js';
6
- import { createHistoricalUI } from './HistoricalMonitorApp.js';
7
-
8
- export async function createMonitorUI(
9
- screen: blessed.Widgets.Screen,
10
- server: ServerConfig
11
- ): Promise<void> {
12
- let updateInterval = 2000;
13
- let intervalId: NodeJS.Timeout | null = null;
14
- let consecutiveFailures = 0;
15
- let lastGoodData: MonitorData | null = null;
16
- const STALE_THRESHOLD = 5;
17
- const metricsAggregator = new MetricsAggregator(server);
18
- const historyManager = new HistoryManager(server.id);
19
-
20
- // Single scrollable content box
21
- const contentBox = blessed.box({
22
- top: 0,
23
- left: 0,
24
- width: '100%',
25
- height: '100%',
26
- tags: true,
27
- scrollable: true,
28
- alwaysScroll: true,
29
- keys: true,
30
- vi: true,
31
- mouse: true,
32
- scrollbar: {
33
- ch: '█',
34
- style: {
35
- fg: 'blue',
36
- },
37
- },
38
- });
39
- screen.append(contentBox);
40
-
41
- // Helper to create progress bar
42
- function createProgressBar(percentage: number, width: number = 30): string {
43
- const filled = Math.round((percentage / 100) * width);
44
- const empty = width - filled;
45
- return '[' + '█'.repeat(Math.max(0, filled)) + '░'.repeat(Math.max(0, empty)) + ']';
46
- }
47
-
48
- // Fetch and update display
49
- async function fetchData() {
50
- try {
51
- const data = await metricsAggregator.collectMonitorData(server, updateInterval);
52
-
53
- // Reset failure count on success
54
- consecutiveFailures = 0;
55
- lastGoodData = data;
56
-
57
- // Append to history (silent failure)
58
- // Only save history for servers that are healthy and not stale
59
- if (!data.server.stale && data.server.healthy) {
60
- historyManager.appendSnapshot(data.server, data.system).catch(() => {
61
- // Don't interrupt monitoring on history write failure
62
- });
63
- }
64
-
65
- const termWidth = (screen.width as number) || 80;
66
- const divider = '─'.repeat(termWidth - 2); // Account for padding
67
-
68
- let content = '';
69
-
70
- // Header
71
- content += `{bold}{blue-fg}═══ ${server.modelName} (${server.port}){/blue-fg}{/bold}\n\n`;
72
-
73
- // Server Info
74
- content += '{bold}Server Information{/bold}\n';
75
- content += divider + '\n';
76
-
77
- const statusIcon = data.server.healthy ? '{green-fg}●{/green-fg}' : '{red-fg}●{/red-fg}';
78
- const statusText = data.server.healthy ? 'RUNNING' : 'UNHEALTHY';
79
- content += `Status: ${statusIcon} ${statusText}\n`;
80
-
81
- if (data.server.uptime) {
82
- content += `Uptime: ${data.server.uptime}\n`;
83
- }
84
-
85
- content += `Model: ${server.modelName}\n`;
86
- // Handle null host (legacy configs) by defaulting to 127.0.0.1
87
- const displayHost = server.host || '127.0.0.1';
88
- content += `Endpoint: http://${displayHost}:${server.port}\n`;
89
- content += `Slots: ${data.server.activeSlots} active / ${data.server.totalSlots} total\n`;
90
- content += '\n';
91
-
92
- // Request Metrics
93
- if (data.server.totalSlots > 0) {
94
- content += '{bold}Request Metrics{/bold}\n';
95
- content += divider + '\n';
96
- content += `Active: ${data.server.activeSlots} / ${data.server.totalSlots}\n`;
97
- content += `Idle: ${data.server.idleSlots} / ${data.server.totalSlots}\n`;
98
-
99
- if (data.server.avgPromptSpeed !== undefined && data.server.avgPromptSpeed > 0) {
100
- content += `Prompt: ${Math.round(data.server.avgPromptSpeed)} tokens/sec\n`;
101
- }
102
-
103
- if (data.server.avgGenerateSpeed !== undefined && data.server.avgGenerateSpeed > 0) {
104
- content += `Generate: ${Math.round(data.server.avgGenerateSpeed)} tokens/sec\n`;
105
- }
106
-
107
- content += '\n';
108
- }
109
-
110
- // Active Slots Detail
111
- if (data.server.slots.length > 0) {
112
- const activeSlots = data.server.slots.filter(s => s.state === 'processing');
113
-
114
- if (activeSlots.length > 0) {
115
- content += '{bold}Active Slots{/bold}\n';
116
- content += divider + '\n';
117
-
118
- activeSlots.forEach((slot) => {
119
- content += `Slot #${slot.id}: {yellow-fg}PROCESSING{/yellow-fg}`;
120
-
121
- if (slot.timings?.predicted_per_second) {
122
- content += ` - ${Math.round(slot.timings.predicted_per_second)} tok/s`;
123
- }
124
-
125
- if (slot.n_decoded !== undefined) {
126
- content += ` - ${slot.n_decoded} tokens`;
127
- }
128
-
129
- content += '\n';
130
- });
131
-
132
- content += '\n';
133
- }
134
- }
135
-
136
- // Model Resources (per-process metrics)
137
- content += '{bold}Model Resources{/bold}\n';
138
- content += divider + '\n';
139
-
140
- // GPU: System-wide (can't get per-process on macOS)
141
- if (data.system && data.system.gpuUsage !== undefined) {
142
- const bar = createProgressBar(data.system.gpuUsage);
143
- content += `GPU: {cyan-fg}${bar}{/cyan-fg} ${Math.round(data.system.gpuUsage)}% {gray-fg}(system){/gray-fg}`;
144
-
145
- if (data.system.temperature !== undefined) {
146
- content += ` - ${Math.round(data.system.temperature)}°C`;
147
- }
148
-
149
- content += '\n';
150
- }
151
-
152
- // CPU: Per-process
153
- if (data.server.processCpuUsage !== undefined) {
154
- const bar = createProgressBar(data.server.processCpuUsage);
155
- content += `CPU: {cyan-fg}${bar}{/cyan-fg} ${Math.round(data.server.processCpuUsage)}%\n`;
156
- }
157
-
158
- // Memory: Per-process
159
- if (data.server.processMemory !== undefined) {
160
- const memoryGB = data.server.processMemory / (1024 ** 3);
161
- // For progress bar, estimate against typical model sizes (e.g., 8GB max)
162
- const estimatedMax = 8;
163
- const memoryPercentage = Math.min((memoryGB / estimatedMax) * 100, 100);
164
- const bar = createProgressBar(memoryPercentage);
165
- content += `Memory: {cyan-fg}${bar}{/cyan-fg} ${memoryGB.toFixed(2)} GB\n`;
166
- }
167
-
168
- if (data.system && data.system.warnings && data.system.warnings.length > 0) {
169
- content += `\n{yellow-fg}⚠ ${data.system.warnings.join(', ')}{/yellow-fg}\n`;
170
- }
171
-
172
- content += '\n';
173
-
174
- // Footer
175
- content += divider + '\n';
176
- content += `{gray-fg}Updated: ${data.lastUpdated.toLocaleTimeString()} | `;
177
- content += `Interval: ${updateInterval}ms | `;
178
- content += `[H]istory [R]efresh [+/-]Speed [Q]uit{/gray-fg}`;
179
-
180
- contentBox.setContent(content);
181
- screen.render();
182
-
183
- } catch (err) {
184
- consecutiveFailures++;
185
- const isStale = consecutiveFailures >= STALE_THRESHOLD;
186
-
187
- // If we have last good data and we're stale, show it with indicator
188
- if (lastGoodData && isStale) {
189
- const termWidth = (screen.width as number) || 80;
190
- const divider = '─'.repeat(termWidth - 2);
191
-
192
- let content = '';
193
-
194
- // Header with stale warning
195
- content += `{bold}{blue-fg}═══ ${server.modelName} (${server.port}){/blue-fg}{/bold}\n`;
196
- content += '{bold}{yellow-fg}⚠ CONNECTION LOST - SHOWING STALE DATA{/yellow-fg}{/bold}\n\n';
197
-
198
- // Server Info
199
- content += '{bold}Server Information{/bold}\n';
200
- content += divider + '\n';
201
-
202
- const statusIcon = '{yellow-fg}●{/yellow-fg}';
203
- const statusText = 'STALE';
204
- content += `Status: ${statusIcon} ${statusText}\n`;
205
-
206
- if (lastGoodData.server.uptime) {
207
- content += `Uptime: ${lastGoodData.server.uptime}\n`;
208
- }
209
-
210
- content += `Model: ${server.modelName}\n`;
211
- // Handle null host (legacy configs) by defaulting to 127.0.0.1
212
- const displayHost = server.host || '127.0.0.1';
213
- content += `Endpoint: http://${displayHost}:${server.port}\n`;
214
- content += `Slots: ${lastGoodData.server.activeSlots} active / ${lastGoodData.server.totalSlots} total\n\n`;
215
-
216
- // Request Metrics
217
- if (lastGoodData.server.totalSlots > 0) {
218
- content += '{bold}Request Metrics{/bold} {yellow-fg}(stale){/yellow-fg}\n';
219
- content += divider + '\n';
220
- content += `Active: ${lastGoodData.server.activeSlots} / ${lastGoodData.server.totalSlots}\n`;
221
- content += `Idle: ${lastGoodData.server.idleSlots} / ${lastGoodData.server.totalSlots}\n`;
222
-
223
- if (lastGoodData.server.avgPromptSpeed !== undefined && lastGoodData.server.avgPromptSpeed > 0) {
224
- content += `Prompt: ${Math.round(lastGoodData.server.avgPromptSpeed)} tokens/sec\n`;
225
- }
226
-
227
- if (lastGoodData.server.avgGenerateSpeed !== undefined && lastGoodData.server.avgGenerateSpeed > 0) {
228
- content += `Generate: ${Math.round(lastGoodData.server.avgGenerateSpeed)} tokens/sec\n`;
229
- }
230
-
231
- content += '\n';
232
- }
233
-
234
- // Active Slots Detail
235
- if (lastGoodData.server.slots.length > 0) {
236
- const activeSlots = lastGoodData.server.slots.filter(s => s.state === 'processing');
237
-
238
- if (activeSlots.length > 0) {
239
- content += '{bold}Active Slots{/bold} {yellow-fg}(stale){/yellow-fg}\n';
240
- content += divider + '\n';
241
-
242
- activeSlots.forEach((slot) => {
243
- content += `Slot #${slot.id}: {yellow-fg}PROCESSING{/yellow-fg}`;
244
-
245
- if (slot.timings?.predicted_per_second) {
246
- content += ` - ${Math.round(slot.timings.predicted_per_second)} tok/s`;
247
- }
248
-
249
- if (slot.n_decoded !== undefined) {
250
- content += ` - ${slot.n_decoded} tokens`;
251
- }
252
-
253
- content += '\n';
254
- });
255
-
256
- content += '\n';
257
- }
258
- }
259
-
260
- // Model Resources (per-process metrics)
261
- content += '{bold}Model Resources{/bold} {yellow-fg}(stale){/yellow-fg}\n';
262
- content += divider + '\n';
263
-
264
- // GPU: System-wide (can't get per-process on macOS)
265
- if (lastGoodData.system && lastGoodData.system.gpuUsage !== undefined) {
266
- const bar = createProgressBar(lastGoodData.system.gpuUsage);
267
- content += `GPU: {cyan-fg}${bar}{/cyan-fg} ${Math.round(lastGoodData.system.gpuUsage)}% {gray-fg}(system){/gray-fg}`;
268
-
269
- if (lastGoodData.system.temperature !== undefined) {
270
- content += ` - ${Math.round(lastGoodData.system.temperature)}°C`;
271
- }
272
-
273
- content += '\n';
274
- }
275
-
276
- // CPU: Per-process
277
- if (lastGoodData.server.processCpuUsage !== undefined) {
278
- const bar = createProgressBar(lastGoodData.server.processCpuUsage);
279
- content += `CPU: {cyan-fg}${bar}{/cyan-fg} ${Math.round(lastGoodData.server.processCpuUsage)}%\n`;
280
- }
281
-
282
- // Memory: Per-process
283
- if (lastGoodData.server.processMemory !== undefined) {
284
- const memoryGB = lastGoodData.server.processMemory / (1024 ** 3);
285
- const estimatedMax = 8;
286
- const memoryPercentage = Math.min((memoryGB / estimatedMax) * 100, 100);
287
- const bar = createProgressBar(memoryPercentage);
288
- content += `Memory: {cyan-fg}${bar}{/cyan-fg} ${memoryGB.toFixed(2)} GB\n`;
289
- }
290
-
291
- if (lastGoodData.system && lastGoodData.system.warnings && lastGoodData.system.warnings.length > 0) {
292
- content += `\n{yellow-fg}⚠ ${lastGoodData.system.warnings.join(', ')}{/yellow-fg}\n`;
293
- }
294
-
295
- content += '\n';
296
-
297
- // Footer
298
- content += divider + '\n';
299
- content += `{yellow-fg}Last good data: ${lastGoodData.lastUpdated.toLocaleTimeString()}{/yellow-fg}\n`;
300
- content += `{yellow-fg}Connection failures: ${consecutiveFailures}{/yellow-fg}\n`;
301
- content += `{gray-fg}Interval: ${updateInterval}ms | [H]istory [R]efresh [+/-]Speed [Q]uit{/gray-fg}`;
302
-
303
- contentBox.setContent(content);
304
- screen.render();
305
- } else if (!lastGoodData || consecutiveFailures < STALE_THRESHOLD) {
306
- // Show connection error (either no last data or not stale yet)
307
- const errorMsg = err instanceof Error ? err.message : 'Unknown error';
308
- const retryMsg = consecutiveFailures < STALE_THRESHOLD
309
- ? `Retrying... (${consecutiveFailures}/${STALE_THRESHOLD})`
310
- : 'Connection lost';
311
-
312
- contentBox.setContent(
313
- '{bold}{red-fg}Connection Error{/red-fg}{/bold}\n\n' +
314
- `{red-fg}${errorMsg}{/red-fg}\n\n` +
315
- `{yellow-fg}${retryMsg}{/yellow-fg}\n\n` +
316
- '{gray-fg}Press [R] to retry or [Q] to quit{/gray-fg}'
317
- );
318
- screen.render();
319
- }
320
- }
321
- }
322
-
323
- // Polling
324
- function startPolling() {
325
- if (intervalId) clearInterval(intervalId);
326
- fetchData();
327
- intervalId = setInterval(fetchData, updateInterval);
328
- }
329
-
330
- // Keyboard shortcuts
331
- screen.key(['r', 'R'], () => {
332
- fetchData();
333
- });
334
-
335
- screen.key(['+', '='], () => {
336
- updateInterval = Math.max(500, updateInterval - 500);
337
- startPolling();
338
- });
339
-
340
- screen.key(['-', '_'], () => {
341
- updateInterval = Math.min(10000, updateInterval + 500);
342
- startPolling();
343
- });
344
-
345
- // Track whether we're in historical view to prevent H key conflicts
346
- let inHistoricalView = false;
347
-
348
- screen.key(['h', 'H'], async () => {
349
- // Prevent entering historical view if already there
350
- if (inHistoricalView) return;
351
-
352
- // Keep polling in background for live historical updates
353
- // Remove current content box
354
- screen.remove(contentBox);
355
-
356
- // Mark that we're in historical view
357
- inHistoricalView = true;
358
-
359
- // Show historical view (polling continues in background)
360
- await createHistoricalUI(screen, server, () => {
361
- // Mark that we've left historical view
362
- inHistoricalView = false;
363
- // Re-attach content box when returning from history
364
- screen.append(contentBox);
365
- });
366
- });
367
-
368
- screen.key(['q', 'Q', 'C-c'], () => {
369
- if (intervalId) clearInterval(intervalId);
370
- screen.destroy();
371
- process.exit(0);
372
- });
373
-
374
- // Initial display
375
- contentBox.setContent('{cyan-fg}⏳ Connecting to server...{/cyan-fg}');
376
- screen.render();
377
-
378
- startPolling();
379
-
380
- // Cleanup
381
- screen.on('destroy', () => {
382
- if (intervalId) clearInterval(intervalId);
383
- // Note: macmon child processes will automatically die when parent exits
384
- // since they're spawned with detached: false
385
- });
386
- }