@appkit/llamacpp-cli 1.12.0 → 1.13.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 (136) hide show
  1. package/README.md +294 -168
  2. package/dist/cli.js +35 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/launch/claude.d.ts +6 -0
  5. package/dist/commands/launch/claude.d.ts.map +1 -0
  6. package/dist/commands/launch/claude.js +277 -0
  7. package/dist/commands/launch/claude.js.map +1 -0
  8. package/dist/lib/integration-checker.d.ts +26 -0
  9. package/dist/lib/integration-checker.d.ts.map +1 -0
  10. package/dist/lib/integration-checker.js +77 -0
  11. package/dist/lib/integration-checker.js.map +1 -0
  12. package/dist/lib/router-manager.d.ts +4 -0
  13. package/dist/lib/router-manager.d.ts.map +1 -1
  14. package/dist/lib/router-manager.js +10 -0
  15. package/dist/lib/router-manager.js.map +1 -1
  16. package/dist/lib/router-server.d.ts +13 -0
  17. package/dist/lib/router-server.d.ts.map +1 -1
  18. package/dist/lib/router-server.js +267 -7
  19. package/dist/lib/router-server.js.map +1 -1
  20. package/dist/types/integration-config.d.ts +28 -0
  21. package/dist/types/integration-config.d.ts.map +1 -0
  22. package/dist/types/integration-config.js +3 -0
  23. package/dist/types/integration-config.js.map +1 -0
  24. package/package.json +10 -2
  25. package/web/dist/assets/index-Bin89Lwr.css +1 -0
  26. package/web/dist/assets/index-CVmonw3T.js +17 -0
  27. package/web/{index.html → dist/index.html} +2 -1
  28. package/.versionrc.json +0 -16
  29. package/CHANGELOG.md +0 -213
  30. package/docs/images/.gitkeep +0 -1
  31. package/docs/images/web-ui-servers.png +0 -0
  32. package/src/cli.ts +0 -523
  33. package/src/commands/admin/config.ts +0 -121
  34. package/src/commands/admin/logs.ts +0 -91
  35. package/src/commands/admin/restart.ts +0 -26
  36. package/src/commands/admin/start.ts +0 -27
  37. package/src/commands/admin/status.ts +0 -84
  38. package/src/commands/admin/stop.ts +0 -16
  39. package/src/commands/config-global.ts +0 -38
  40. package/src/commands/config.ts +0 -323
  41. package/src/commands/create.ts +0 -183
  42. package/src/commands/delete.ts +0 -74
  43. package/src/commands/list.ts +0 -37
  44. package/src/commands/logs-all.ts +0 -251
  45. package/src/commands/logs.ts +0 -345
  46. package/src/commands/monitor.ts +0 -110
  47. package/src/commands/ps.ts +0 -84
  48. package/src/commands/pull.ts +0 -44
  49. package/src/commands/rm.ts +0 -107
  50. package/src/commands/router/config.ts +0 -116
  51. package/src/commands/router/logs.ts +0 -256
  52. package/src/commands/router/restart.ts +0 -36
  53. package/src/commands/router/start.ts +0 -60
  54. package/src/commands/router/status.ts +0 -119
  55. package/src/commands/router/stop.ts +0 -33
  56. package/src/commands/run.ts +0 -233
  57. package/src/commands/search.ts +0 -107
  58. package/src/commands/server-show.ts +0 -161
  59. package/src/commands/show.ts +0 -207
  60. package/src/commands/start.ts +0 -101
  61. package/src/commands/stop.ts +0 -39
  62. package/src/commands/tui.ts +0 -25
  63. package/src/lib/admin-manager.ts +0 -435
  64. package/src/lib/admin-server.ts +0 -1243
  65. package/src/lib/config-generator.ts +0 -130
  66. package/src/lib/download-job-manager.ts +0 -213
  67. package/src/lib/history-manager.ts +0 -172
  68. package/src/lib/launchctl-manager.ts +0 -225
  69. package/src/lib/metrics-aggregator.ts +0 -257
  70. package/src/lib/model-downloader.ts +0 -328
  71. package/src/lib/model-scanner.ts +0 -157
  72. package/src/lib/model-search.ts +0 -114
  73. package/src/lib/models-dir-setup.ts +0 -46
  74. package/src/lib/port-manager.ts +0 -80
  75. package/src/lib/router-logger.ts +0 -201
  76. package/src/lib/router-manager.ts +0 -414
  77. package/src/lib/router-server.ts +0 -538
  78. package/src/lib/state-manager.ts +0 -206
  79. package/src/lib/status-checker.ts +0 -113
  80. package/src/lib/system-collector.ts +0 -315
  81. package/src/tui/ConfigApp.ts +0 -1085
  82. package/src/tui/HistoricalMonitorApp.ts +0 -587
  83. package/src/tui/ModelsApp.ts +0 -368
  84. package/src/tui/MonitorApp.ts +0 -386
  85. package/src/tui/MultiServerMonitorApp.ts +0 -1833
  86. package/src/tui/RootNavigator.ts +0 -74
  87. package/src/tui/SearchApp.ts +0 -511
  88. package/src/tui/SplashScreen.ts +0 -149
  89. package/src/types/admin-config.ts +0 -25
  90. package/src/types/global-config.ts +0 -26
  91. package/src/types/history-types.ts +0 -39
  92. package/src/types/model-info.ts +0 -8
  93. package/src/types/monitor-types.ts +0 -162
  94. package/src/types/router-config.ts +0 -25
  95. package/src/types/server-config.ts +0 -46
  96. package/src/utils/downsample-utils.ts +0 -128
  97. package/src/utils/file-utils.ts +0 -146
  98. package/src/utils/format-utils.ts +0 -98
  99. package/src/utils/log-parser.ts +0 -284
  100. package/src/utils/log-utils.ts +0 -178
  101. package/src/utils/process-utils.ts +0 -316
  102. package/src/utils/prompt-utils.ts +0 -47
  103. package/test-load.sh +0 -100
  104. package/tsconfig.json +0 -20
  105. package/web/eslint.config.js +0 -23
  106. package/web/llamacpp-web-dist.tar.gz +0 -0
  107. package/web/package-lock.json +0 -4017
  108. package/web/package.json +0 -38
  109. package/web/postcss.config.js +0 -6
  110. package/web/src/App.css +0 -42
  111. package/web/src/App.tsx +0 -86
  112. package/web/src/assets/react.svg +0 -1
  113. package/web/src/components/ApiKeyPrompt.tsx +0 -71
  114. package/web/src/components/CreateServerModal.tsx +0 -372
  115. package/web/src/components/DownloadProgress.tsx +0 -123
  116. package/web/src/components/Nav.tsx +0 -89
  117. package/web/src/components/RouterConfigModal.tsx +0 -240
  118. package/web/src/components/SearchModal.tsx +0 -306
  119. package/web/src/components/ServerConfigModal.tsx +0 -291
  120. package/web/src/hooks/useApi.ts +0 -259
  121. package/web/src/index.css +0 -42
  122. package/web/src/lib/api.ts +0 -226
  123. package/web/src/main.tsx +0 -10
  124. package/web/src/pages/Dashboard.tsx +0 -103
  125. package/web/src/pages/Models.tsx +0 -258
  126. package/web/src/pages/Router.tsx +0 -270
  127. package/web/src/pages/RouterLogs.tsx +0 -201
  128. package/web/src/pages/ServerLogs.tsx +0 -553
  129. package/web/src/pages/Servers.tsx +0 -358
  130. package/web/src/types/api.ts +0 -140
  131. package/web/tailwind.config.js +0 -31
  132. package/web/tsconfig.app.json +0 -28
  133. package/web/tsconfig.json +0 -7
  134. package/web/tsconfig.node.json +0 -26
  135. package/web/vite.config.ts +0 -25
  136. /package/web/{public → dist}/vite.svg +0 -0
@@ -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
- }