@appkit/llamacpp-cli 1.11.0 → 1.12.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 (105) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +356 -3
  3. package/dist/cli.js +99 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/admin/config.d.ts +10 -0
  6. package/dist/commands/admin/config.d.ts.map +1 -0
  7. package/dist/commands/admin/config.js +100 -0
  8. package/dist/commands/admin/config.js.map +1 -0
  9. package/dist/commands/admin/logs.d.ts +10 -0
  10. package/dist/commands/admin/logs.d.ts.map +1 -0
  11. package/dist/commands/admin/logs.js +114 -0
  12. package/dist/commands/admin/logs.js.map +1 -0
  13. package/dist/commands/admin/restart.d.ts +2 -0
  14. package/dist/commands/admin/restart.d.ts.map +1 -0
  15. package/dist/commands/admin/restart.js +29 -0
  16. package/dist/commands/admin/restart.js.map +1 -0
  17. package/dist/commands/admin/start.d.ts +2 -0
  18. package/dist/commands/admin/start.d.ts.map +1 -0
  19. package/dist/commands/admin/start.js +30 -0
  20. package/dist/commands/admin/start.js.map +1 -0
  21. package/dist/commands/admin/status.d.ts +2 -0
  22. package/dist/commands/admin/status.d.ts.map +1 -0
  23. package/dist/commands/admin/status.js +82 -0
  24. package/dist/commands/admin/status.js.map +1 -0
  25. package/dist/commands/admin/stop.d.ts +2 -0
  26. package/dist/commands/admin/stop.d.ts.map +1 -0
  27. package/dist/commands/admin/stop.js +21 -0
  28. package/dist/commands/admin/stop.js.map +1 -0
  29. package/dist/commands/logs.d.ts +1 -0
  30. package/dist/commands/logs.d.ts.map +1 -1
  31. package/dist/commands/logs.js +22 -0
  32. package/dist/commands/logs.js.map +1 -1
  33. package/dist/lib/admin-manager.d.ts +111 -0
  34. package/dist/lib/admin-manager.d.ts.map +1 -0
  35. package/dist/lib/admin-manager.js +413 -0
  36. package/dist/lib/admin-manager.js.map +1 -0
  37. package/dist/lib/admin-server.d.ts +148 -0
  38. package/dist/lib/admin-server.d.ts.map +1 -0
  39. package/dist/lib/admin-server.js +1161 -0
  40. package/dist/lib/admin-server.js.map +1 -0
  41. package/dist/lib/download-job-manager.d.ts +64 -0
  42. package/dist/lib/download-job-manager.d.ts.map +1 -0
  43. package/dist/lib/download-job-manager.js +164 -0
  44. package/dist/lib/download-job-manager.js.map +1 -0
  45. package/dist/tui/MultiServerMonitorApp.js +1 -1
  46. package/dist/types/admin-config.d.ts +19 -0
  47. package/dist/types/admin-config.d.ts.map +1 -0
  48. package/dist/types/admin-config.js +3 -0
  49. package/dist/types/admin-config.js.map +1 -0
  50. package/dist/utils/log-parser.d.ts +9 -0
  51. package/dist/utils/log-parser.d.ts.map +1 -1
  52. package/dist/utils/log-parser.js +11 -0
  53. package/dist/utils/log-parser.js.map +1 -1
  54. package/docs/images/web-ui-servers.png +0 -0
  55. package/package.json +1 -1
  56. package/src/cli.ts +100 -0
  57. package/src/commands/admin/config.ts +121 -0
  58. package/src/commands/admin/logs.ts +91 -0
  59. package/src/commands/admin/restart.ts +26 -0
  60. package/src/commands/admin/start.ts +27 -0
  61. package/src/commands/admin/status.ts +84 -0
  62. package/src/commands/admin/stop.ts +16 -0
  63. package/src/commands/logs.ts +24 -0
  64. package/src/lib/admin-manager.ts +435 -0
  65. package/src/lib/admin-server.ts +1243 -0
  66. package/src/lib/download-job-manager.ts +213 -0
  67. package/src/tui/MultiServerMonitorApp.ts +1 -1
  68. package/src/types/admin-config.ts +25 -0
  69. package/src/utils/log-parser.ts +13 -0
  70. package/web/README.md +429 -0
  71. package/web/eslint.config.js +23 -0
  72. package/web/index.html +13 -0
  73. package/web/llamacpp-web-dist.tar.gz +0 -0
  74. package/web/package-lock.json +4017 -0
  75. package/web/package.json +38 -0
  76. package/web/postcss.config.js +6 -0
  77. package/web/public/vite.svg +1 -0
  78. package/web/src/App.css +42 -0
  79. package/web/src/App.tsx +86 -0
  80. package/web/src/assets/react.svg +1 -0
  81. package/web/src/components/ApiKeyPrompt.tsx +71 -0
  82. package/web/src/components/CreateServerModal.tsx +372 -0
  83. package/web/src/components/DownloadProgress.tsx +123 -0
  84. package/web/src/components/Nav.tsx +89 -0
  85. package/web/src/components/RouterConfigModal.tsx +240 -0
  86. package/web/src/components/SearchModal.tsx +306 -0
  87. package/web/src/components/ServerConfigModal.tsx +291 -0
  88. package/web/src/hooks/useApi.ts +259 -0
  89. package/web/src/index.css +42 -0
  90. package/web/src/lib/api.ts +226 -0
  91. package/web/src/main.tsx +10 -0
  92. package/web/src/pages/Dashboard.tsx +103 -0
  93. package/web/src/pages/Models.tsx +258 -0
  94. package/web/src/pages/Router.tsx +270 -0
  95. package/web/src/pages/RouterLogs.tsx +201 -0
  96. package/web/src/pages/ServerLogs.tsx +553 -0
  97. package/web/src/pages/Servers.tsx +358 -0
  98. package/web/src/types/api.ts +140 -0
  99. package/web/tailwind.config.js +31 -0
  100. package/web/tsconfig.app.json +28 -0
  101. package/web/tsconfig.json +7 -0
  102. package/web/tsconfig.node.json +26 -0
  103. package/web/vite.config.ts +25 -0
  104. package/MONITORING-ACCURACY-FIX.md +0 -199
  105. package/PER-PROCESS-METRICS.md +0 -190
@@ -0,0 +1,201 @@
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import { ArrowLeft, Loader2, ChevronDown } from 'lucide-react';
4
+ import { useRouterLogs } from '../hooks/useApi';
5
+
6
+ type LogType = 'stdout' | 'stderr' | 'both';
7
+ type LogSort = 'newest' | 'oldest';
8
+
9
+ export function RouterLogs() {
10
+ const navigate = useNavigate();
11
+
12
+ const [logType, setLogType] = useState<LogType>('stdout');
13
+ const [sortOrder, setSortOrder] = useState<LogSort>('newest');
14
+ const [showSortDropdown, setShowSortDropdown] = useState(false);
15
+ const [autoScroll, setAutoScroll] = useState(true);
16
+
17
+ const logContainerRef = useRef<HTMLDivElement>(null);
18
+ const dropdownRef = useRef<HTMLDivElement>(null);
19
+
20
+ const { data: logsData, isLoading: logsLoading } = useRouterLogs(50000);
21
+
22
+ // Auto-scroll to bottom when new logs arrive
23
+ useEffect(() => {
24
+ if (autoScroll && logContainerRef.current) {
25
+ logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
26
+ }
27
+ }, [logsData, autoScroll, sortOrder]);
28
+
29
+ // Close dropdown on outside click
30
+ useEffect(() => {
31
+ const handleClickOutside = (e: MouseEvent) => {
32
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {
33
+ setShowSortDropdown(false);
34
+ }
35
+ };
36
+ document.addEventListener('mousedown', handleClickOutside);
37
+ return () => document.removeEventListener('mousedown', handleClickOutside);
38
+ }, []);
39
+
40
+ const getFilteredLogs = (): string[] => {
41
+ if (!logsData) return [];
42
+
43
+ let logs: string;
44
+ if (logType === 'stdout') {
45
+ logs = logsData.stdout || '';
46
+ } else if (logType === 'stderr') {
47
+ logs = logsData.stderr || '';
48
+ } else {
49
+ // Combine both
50
+ const stdout = logsData.stdout || '';
51
+ const stderr = logsData.stderr || '';
52
+ logs = [stderr, stdout].filter(l => l.trim()).join('\n');
53
+ }
54
+
55
+ const lines = logs.split('\n').filter(line => line.trim());
56
+
57
+ // Apply sort
58
+ if (sortOrder === 'oldest') {
59
+ return lines;
60
+ }
61
+
62
+ return [...lines].reverse();
63
+ };
64
+
65
+ const filteredLogs = getFilteredLogs();
66
+
67
+ return (
68
+ <div className="h-[calc(100vh-56px)] flex flex-col">
69
+ {/* Header */}
70
+ <div className="flex items-center px-4 py-3 border-b border-gray-200 bg-white">
71
+ <div className="flex items-center gap-3">
72
+ <button
73
+ onClick={() => navigate('/router')}
74
+ className="p-1.5 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
75
+ >
76
+ <ArrowLeft className="w-5 h-5" />
77
+ </button>
78
+ <div>
79
+ <h1 className="text-lg font-semibold text-gray-900">Router Logs</h1>
80
+ <p className="text-sm text-gray-500">Unified model routing service</p>
81
+ </div>
82
+ </div>
83
+ </div>
84
+
85
+ {/* Filter Bar */}
86
+ <div className="flex items-center justify-between px-4 py-3 border-b border-gray-100 bg-gray-50">
87
+ {/* Log Type Toggle */}
88
+ <div className="flex items-center gap-2">
89
+ <div className="flex items-center bg-white border border-gray-200 rounded-lg overflow-hidden">
90
+ <button
91
+ onClick={() => setLogType('stdout')}
92
+ className={`px-3 py-1.5 text-sm font-medium transition-colors cursor-pointer ${
93
+ logType === 'stdout'
94
+ ? 'bg-gray-100 text-gray-900'
95
+ : 'text-gray-600 hover:bg-gray-50'
96
+ }`}
97
+ >
98
+ Activity
99
+ </button>
100
+ <button
101
+ onClick={() => setLogType('stderr')}
102
+ className={`px-3 py-1.5 text-sm font-medium transition-colors cursor-pointer ${
103
+ logType === 'stderr'
104
+ ? 'bg-gray-100 text-gray-900'
105
+ : 'text-gray-600 hover:bg-gray-50'
106
+ }`}
107
+ >
108
+ System
109
+ </button>
110
+ <button
111
+ onClick={() => setLogType('both')}
112
+ className={`px-3 py-1.5 text-sm font-medium transition-colors cursor-pointer ${
113
+ logType === 'both'
114
+ ? 'bg-gray-100 text-gray-900'
115
+ : 'text-gray-600 hover:bg-gray-50'
116
+ }`}
117
+ >
118
+ Both
119
+ </button>
120
+ </div>
121
+ </div>
122
+
123
+ {/* Sort Dropdown */}
124
+ <div className="relative" ref={dropdownRef}>
125
+ <button
126
+ onClick={() => setShowSortDropdown(!showSortDropdown)}
127
+ className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-gray-600 bg-white border border-gray-200 rounded-lg hover:border-gray-300 transition-colors cursor-pointer"
128
+ >
129
+ {sortOrder === 'newest' ? 'Newest' : 'Oldest'}
130
+ <ChevronDown className="w-4 h-4" />
131
+ </button>
132
+
133
+ {showSortDropdown && (
134
+ <div className="absolute right-0 top-full mt-1 w-32 bg-white border border-gray-200 rounded-lg shadow-lg z-10">
135
+ <button
136
+ onClick={() => { setSortOrder('newest'); setShowSortDropdown(false); }}
137
+ className={`w-full text-left px-3 py-2 text-sm transition-colors cursor-pointer ${
138
+ sortOrder === 'newest' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:bg-gray-50'
139
+ }`}
140
+ >
141
+ Newest
142
+ </button>
143
+ <button
144
+ onClick={() => { setSortOrder('oldest'); setShowSortDropdown(false); }}
145
+ className={`w-full text-left px-3 py-2 text-sm transition-colors cursor-pointer ${
146
+ sortOrder === 'oldest' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:bg-gray-50'
147
+ }`}
148
+ >
149
+ Oldest
150
+ </button>
151
+ </div>
152
+ )}
153
+ </div>
154
+ </div>
155
+
156
+ {/* Log Content */}
157
+ <div
158
+ ref={logContainerRef}
159
+ className="flex-1 overflow-y-auto bg-gray-900 p-4 font-mono text-sm"
160
+ onScroll={(e) => {
161
+ const target = e.target as HTMLDivElement;
162
+ const isAtBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 50;
163
+ setAutoScroll(isAtBottom);
164
+ }}
165
+ >
166
+ {logsLoading ? (
167
+ <div className="flex items-center justify-center h-full">
168
+ <Loader2 className="w-6 h-6 animate-spin text-gray-400" />
169
+ </div>
170
+ ) : filteredLogs.length === 0 ? (
171
+ <div className="flex flex-col items-center justify-center h-full text-gray-500">
172
+ <p>No logs found</p>
173
+ <p className="text-sm mt-1">Router may not be running or has no activity yet</p>
174
+ </div>
175
+ ) : (
176
+ <div className="space-y-0.5">
177
+ {filteredLogs.map((line, index) => (
178
+ <div
179
+ key={index}
180
+ className="text-gray-300 break-all whitespace-pre-wrap leading-relaxed"
181
+ >
182
+ {line}
183
+ </div>
184
+ ))}
185
+ </div>
186
+ )}
187
+ </div>
188
+
189
+ {/* Footer with stats */}
190
+ <div className="flex items-center justify-between px-4 py-2 border-t border-gray-200 bg-gray-50 text-sm text-gray-500">
191
+ <span>
192
+ {filteredLogs.length} {filteredLogs.length === 1 ? 'line' : 'lines'}
193
+ </span>
194
+ <span className="flex items-center gap-2">
195
+ <span className={`w-2 h-2 rounded-full ${autoScroll ? 'bg-green-500' : 'bg-gray-300'}`} />
196
+ {autoScroll ? 'Auto-scroll on' : 'Auto-scroll off'}
197
+ </span>
198
+ </div>
199
+ </div>
200
+ );
201
+ }