@appkit/llamacpp-cli 1.12.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 (114) hide show
  1. package/README.md +217 -168
  2. package/package.json +10 -2
  3. package/web/dist/assets/index-Bin89Lwr.css +1 -0
  4. package/web/dist/assets/index-CVmonw3T.js +17 -0
  5. package/web/{index.html → dist/index.html} +2 -1
  6. package/.versionrc.json +0 -16
  7. package/CHANGELOG.md +0 -213
  8. package/docs/images/.gitkeep +0 -1
  9. package/docs/images/web-ui-servers.png +0 -0
  10. package/src/cli.ts +0 -523
  11. package/src/commands/admin/config.ts +0 -121
  12. package/src/commands/admin/logs.ts +0 -91
  13. package/src/commands/admin/restart.ts +0 -26
  14. package/src/commands/admin/start.ts +0 -27
  15. package/src/commands/admin/status.ts +0 -84
  16. package/src/commands/admin/stop.ts +0 -16
  17. package/src/commands/config-global.ts +0 -38
  18. package/src/commands/config.ts +0 -323
  19. package/src/commands/create.ts +0 -183
  20. package/src/commands/delete.ts +0 -74
  21. package/src/commands/list.ts +0 -37
  22. package/src/commands/logs-all.ts +0 -251
  23. package/src/commands/logs.ts +0 -345
  24. package/src/commands/monitor.ts +0 -110
  25. package/src/commands/ps.ts +0 -84
  26. package/src/commands/pull.ts +0 -44
  27. package/src/commands/rm.ts +0 -107
  28. package/src/commands/router/config.ts +0 -116
  29. package/src/commands/router/logs.ts +0 -256
  30. package/src/commands/router/restart.ts +0 -36
  31. package/src/commands/router/start.ts +0 -60
  32. package/src/commands/router/status.ts +0 -119
  33. package/src/commands/router/stop.ts +0 -33
  34. package/src/commands/run.ts +0 -233
  35. package/src/commands/search.ts +0 -107
  36. package/src/commands/server-show.ts +0 -161
  37. package/src/commands/show.ts +0 -207
  38. package/src/commands/start.ts +0 -101
  39. package/src/commands/stop.ts +0 -39
  40. package/src/commands/tui.ts +0 -25
  41. package/src/lib/admin-manager.ts +0 -435
  42. package/src/lib/admin-server.ts +0 -1243
  43. package/src/lib/config-generator.ts +0 -130
  44. package/src/lib/download-job-manager.ts +0 -213
  45. package/src/lib/history-manager.ts +0 -172
  46. package/src/lib/launchctl-manager.ts +0 -225
  47. package/src/lib/metrics-aggregator.ts +0 -257
  48. package/src/lib/model-downloader.ts +0 -328
  49. package/src/lib/model-scanner.ts +0 -157
  50. package/src/lib/model-search.ts +0 -114
  51. package/src/lib/models-dir-setup.ts +0 -46
  52. package/src/lib/port-manager.ts +0 -80
  53. package/src/lib/router-logger.ts +0 -201
  54. package/src/lib/router-manager.ts +0 -414
  55. package/src/lib/router-server.ts +0 -538
  56. package/src/lib/state-manager.ts +0 -206
  57. package/src/lib/status-checker.ts +0 -113
  58. package/src/lib/system-collector.ts +0 -315
  59. package/src/tui/ConfigApp.ts +0 -1085
  60. package/src/tui/HistoricalMonitorApp.ts +0 -587
  61. package/src/tui/ModelsApp.ts +0 -368
  62. package/src/tui/MonitorApp.ts +0 -386
  63. package/src/tui/MultiServerMonitorApp.ts +0 -1833
  64. package/src/tui/RootNavigator.ts +0 -74
  65. package/src/tui/SearchApp.ts +0 -511
  66. package/src/tui/SplashScreen.ts +0 -149
  67. package/src/types/admin-config.ts +0 -25
  68. package/src/types/global-config.ts +0 -26
  69. package/src/types/history-types.ts +0 -39
  70. package/src/types/model-info.ts +0 -8
  71. package/src/types/monitor-types.ts +0 -162
  72. package/src/types/router-config.ts +0 -25
  73. package/src/types/server-config.ts +0 -46
  74. package/src/utils/downsample-utils.ts +0 -128
  75. package/src/utils/file-utils.ts +0 -146
  76. package/src/utils/format-utils.ts +0 -98
  77. package/src/utils/log-parser.ts +0 -284
  78. package/src/utils/log-utils.ts +0 -178
  79. package/src/utils/process-utils.ts +0 -316
  80. package/src/utils/prompt-utils.ts +0 -47
  81. package/test-load.sh +0 -100
  82. package/tsconfig.json +0 -20
  83. package/web/eslint.config.js +0 -23
  84. package/web/llamacpp-web-dist.tar.gz +0 -0
  85. package/web/package-lock.json +0 -4017
  86. package/web/package.json +0 -38
  87. package/web/postcss.config.js +0 -6
  88. package/web/src/App.css +0 -42
  89. package/web/src/App.tsx +0 -86
  90. package/web/src/assets/react.svg +0 -1
  91. package/web/src/components/ApiKeyPrompt.tsx +0 -71
  92. package/web/src/components/CreateServerModal.tsx +0 -372
  93. package/web/src/components/DownloadProgress.tsx +0 -123
  94. package/web/src/components/Nav.tsx +0 -89
  95. package/web/src/components/RouterConfigModal.tsx +0 -240
  96. package/web/src/components/SearchModal.tsx +0 -306
  97. package/web/src/components/ServerConfigModal.tsx +0 -291
  98. package/web/src/hooks/useApi.ts +0 -259
  99. package/web/src/index.css +0 -42
  100. package/web/src/lib/api.ts +0 -226
  101. package/web/src/main.tsx +0 -10
  102. package/web/src/pages/Dashboard.tsx +0 -103
  103. package/web/src/pages/Models.tsx +0 -258
  104. package/web/src/pages/Router.tsx +0 -270
  105. package/web/src/pages/RouterLogs.tsx +0 -201
  106. package/web/src/pages/ServerLogs.tsx +0 -553
  107. package/web/src/pages/Servers.tsx +0 -358
  108. package/web/src/types/api.ts +0 -140
  109. package/web/tailwind.config.js +0 -31
  110. package/web/tsconfig.app.json +0 -28
  111. package/web/tsconfig.json +0 -7
  112. package/web/tsconfig.node.json +0 -26
  113. package/web/vite.config.ts +0 -25
  114. /package/web/{public → dist}/vite.svg +0 -0
@@ -1,123 +0,0 @@
1
- import { X, Download, Loader2, CheckCircle, AlertCircle } from 'lucide-react';
2
- import { useDownloadJobs, useCancelDownload } from '../hooks/useApi';
3
- import type { DownloadJob } from '../types/api';
4
-
5
- export function DownloadProgress() {
6
- const { data: jobsData } = useDownloadJobs(true);
7
- const cancelMutation = useCancelDownload();
8
-
9
- const jobs = jobsData?.jobs || [];
10
-
11
- // Filter to active jobs only (pending, downloading)
12
- const activeJobs = jobs.filter(
13
- job => job.status === 'pending' || job.status === 'downloading'
14
- );
15
-
16
- // Nothing to show if no active downloads
17
- if (activeJobs.length === 0) return null;
18
-
19
- const handleCancel = (jobId: string) => {
20
- cancelMutation.mutate(jobId);
21
- };
22
-
23
- return (
24
- <div className="fixed bottom-4 right-4 z-40 w-80">
25
- <div className="bg-white rounded-lg shadow-lg border border-gray-200 overflow-hidden">
26
- {/* Header */}
27
- <div className="px-4 py-2.5 bg-gray-50 border-b border-gray-200 flex items-center gap-2">
28
- <Download className="w-4 h-4 text-gray-600" />
29
- <span className="text-sm font-medium text-gray-700">
30
- {activeJobs.length} download{activeJobs.length !== 1 ? 's' : ''} in progress
31
- </span>
32
- </div>
33
-
34
- {/* Jobs */}
35
- <div className="max-h-60 overflow-y-auto divide-y divide-gray-100">
36
- {activeJobs.map((job) => (
37
- <JobItem
38
- key={job.id}
39
- job={job}
40
- onCancel={() => handleCancel(job.id)}
41
- />
42
- ))}
43
- </div>
44
- </div>
45
- </div>
46
- );
47
- }
48
-
49
- interface JobItemProps {
50
- job: DownloadJob;
51
- onCancel: () => void;
52
- }
53
-
54
- function JobItem({ job, onCancel }: JobItemProps) {
55
- const formatBytes = (bytes: number) => {
56
- if (bytes >= 1e9) return `${(bytes / 1e9).toFixed(1)} GB`;
57
- if (bytes >= 1e6) return `${(bytes / 1e6).toFixed(1)} MB`;
58
- return `${(bytes / 1e3).toFixed(1)} KB`;
59
- };
60
-
61
- const getStatusIcon = () => {
62
- switch (job.status) {
63
- case 'completed':
64
- return <CheckCircle className="w-4 h-4 text-green-500" />;
65
- case 'failed':
66
- case 'cancelled':
67
- return <AlertCircle className="w-4 h-4 text-red-500" />;
68
- default:
69
- return <Loader2 className="w-4 h-4 text-gray-400 animate-spin" />;
70
- }
71
- };
72
-
73
- return (
74
- <div className="px-4 py-3">
75
- <div className="flex items-center justify-between mb-1">
76
- <div className="flex items-center gap-2 flex-1 min-w-0">
77
- {getStatusIcon()}
78
- <span className="text-sm font-medium text-gray-900 truncate">
79
- {job.filename}
80
- </span>
81
- </div>
82
- {(job.status === 'pending' || job.status === 'downloading') && (
83
- <button
84
- onClick={onCancel}
85
- className="p-1 hover:bg-gray-100 rounded transition-colors cursor-pointer"
86
- title="Cancel download"
87
- >
88
- <X className="w-4 h-4 text-gray-400" />
89
- </button>
90
- )}
91
- </div>
92
-
93
- {job.progress && (
94
- <>
95
- <div className="w-full bg-gray-200 rounded-full h-1.5 mb-1">
96
- <div
97
- className="bg-gray-700 h-1.5 rounded-full transition-all duration-300"
98
- style={{ width: `${job.progress.percentage}%` }}
99
- />
100
- </div>
101
- <div className="flex items-center justify-between text-xs text-gray-500">
102
- <span>
103
- {formatBytes(job.progress.downloaded)} / {formatBytes(job.progress.total)}
104
- </span>
105
- <span>{job.progress.speed}</span>
106
- </div>
107
- </>
108
- )}
109
-
110
- {job.status === 'pending' && !job.progress && (
111
- <p className="text-xs text-gray-500">Starting...</p>
112
- )}
113
-
114
- {job.status === 'failed' && job.error && (
115
- <p className="text-xs text-red-500 truncate">{job.error}</p>
116
- )}
117
-
118
- {job.status === 'cancelled' && (
119
- <p className="text-xs text-gray-500">Cancelled</p>
120
- )}
121
- </div>
122
- );
123
- }
@@ -1,89 +0,0 @@
1
- import { Link, useLocation } from 'react-router-dom';
2
- import { Search, LogOut } from 'lucide-react';
3
- import { api } from '../lib/api';
4
-
5
- interface NavProps {
6
- onLogout?: () => void;
7
- searchQuery?: string;
8
- onSearchChange?: (query: string) => void;
9
- }
10
-
11
- export function Nav({ onLogout, searchQuery = '', onSearchChange }: NavProps) {
12
- const location = useLocation();
13
-
14
- const handleLogout = () => {
15
- api.clearApiKey();
16
- onLogout?.();
17
- };
18
-
19
- return (
20
- <nav className="border-b border-neutral-200 bg-white">
21
- <div className="max-w-7xl mx-auto px-6">
22
- <div className="flex items-center justify-between h-16">
23
- {/* Logo and Nav Links */}
24
- <div className="flex items-center space-x-10">
25
- <Link to="/" className="flex items-center">
26
- <span className="text-xl font-bold text-neutral-900 tracking-tight">LLAMA CPP</span>
27
- </Link>
28
-
29
- <div className="flex items-center space-x-1">
30
- <Link
31
- to="/servers"
32
- className={`px-3 py-2 text-sm font-medium transition-colors rounded-md ${
33
- location.pathname === '/servers' || location.pathname === '/'
34
- ? 'text-neutral-900 bg-neutral-100'
35
- : 'text-neutral-600 hover:text-neutral-900 hover:bg-neutral-50'
36
- }`}
37
- >
38
- Servers
39
- </Link>
40
- <Link
41
- to="/models"
42
- className={`px-3 py-2 text-sm font-medium transition-colors rounded-md ${
43
- location.pathname === '/models'
44
- ? 'text-neutral-900 bg-neutral-100'
45
- : 'text-neutral-600 hover:text-neutral-900 hover:bg-neutral-50'
46
- }`}
47
- >
48
- Models
49
- </Link>
50
- <Link
51
- to="/router"
52
- className={`px-3 py-2 text-sm font-medium transition-colors rounded-md ${
53
- location.pathname === '/router'
54
- ? 'text-neutral-900 bg-neutral-100'
55
- : 'text-neutral-600 hover:text-neutral-900 hover:bg-neutral-50'
56
- }`}
57
- >
58
- Router
59
- </Link>
60
- </div>
61
- </div>
62
-
63
- {/* Search + Logout */}
64
- <div className="flex items-center space-x-3">
65
- {onSearchChange && (
66
- <div className="relative">
67
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-neutral-400 pointer-events-none" />
68
- <input
69
- type="search"
70
- placeholder="Search models..."
71
- value={searchQuery}
72
- onChange={(e) => onSearchChange(e.target.value)}
73
- className="w-72 pl-9 pr-4 py-2 text-sm text-neutral-900 placeholder:text-neutral-400 border border-neutral-200 rounded-md bg-white hover:border-neutral-300 focus:outline-none focus:border-neutral-400 transition-colors"
74
- />
75
- </div>
76
- )}
77
- <button
78
- onClick={handleLogout}
79
- className="p-2 text-neutral-500 hover:text-neutral-700 hover:bg-neutral-100 rounded-md transition-colors cursor-pointer"
80
- title="Logout"
81
- >
82
- <LogOut className="w-4 h-4" />
83
- </button>
84
- </div>
85
- </div>
86
- </div>
87
- </nav>
88
- );
89
- }
@@ -1,240 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { X, Loader2, Save } from 'lucide-react';
3
- import { useUpdateRouter } from '../hooks/useApi';
4
- import type { RouterInfo } from '../types/api';
5
-
6
- interface RouterConfigModalProps {
7
- router: RouterInfo | null;
8
- isOpen: boolean;
9
- onClose: () => void;
10
- }
11
-
12
- interface FormData {
13
- port: number;
14
- host: string;
15
- verbose: boolean;
16
- requestTimeout: number;
17
- healthCheckInterval: number;
18
- }
19
-
20
- export function RouterConfigModal({ router, isOpen, onClose }: RouterConfigModalProps) {
21
- const updateRouter = useUpdateRouter();
22
-
23
- const [formData, setFormData] = useState<FormData>({
24
- port: 9100,
25
- host: '127.0.0.1',
26
- verbose: false,
27
- requestTimeout: 120000,
28
- healthCheckInterval: 5000,
29
- });
30
-
31
- const [restartAfterSave, setRestartAfterSave] = useState(true);
32
- const [error, setError] = useState<string | null>(null);
33
-
34
- // Initialize form when router changes
35
- useEffect(() => {
36
- if (router?.config) {
37
- setFormData({
38
- port: router.config.port,
39
- host: router.config.host,
40
- verbose: router.config.verbose,
41
- requestTimeout: router.config.requestTimeout,
42
- healthCheckInterval: router.config.healthCheckInterval,
43
- });
44
- setError(null);
45
- }
46
- }, [router]);
47
-
48
- const handleSubmit = async (e: React.FormEvent) => {
49
- e.preventDefault();
50
- if (!router) return;
51
-
52
- setError(null);
53
-
54
- try {
55
- const result = await updateRouter.mutateAsync({
56
- port: formData.port,
57
- host: formData.host,
58
- verbose: formData.verbose,
59
- requestTimeout: formData.requestTimeout,
60
- healthCheckInterval: formData.healthCheckInterval,
61
- });
62
-
63
- // If router is running and needs restart, prompt user
64
- if (result.needsRestart && router.isRunning && !restartAfterSave) {
65
- setError('Changes saved. Restart the router to apply them.');
66
- return;
67
- }
68
-
69
- onClose();
70
- } catch (err) {
71
- setError((err as Error).message);
72
- }
73
- };
74
-
75
- if (!isOpen || !router) return null;
76
-
77
- return (
78
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
79
- <div className="bg-white rounded-xl shadow-xl w-full max-w-md mx-4 max-h-[90vh] flex flex-col">
80
- {/* Header */}
81
- <div className="flex items-center justify-between px-4 py-3 border-b border-gray-200">
82
- <div>
83
- <h2 className="text-lg font-semibold text-gray-900">Configure Router</h2>
84
- <p className="text-sm text-gray-500">Unified model routing service</p>
85
- </div>
86
- <button
87
- onClick={onClose}
88
- className="p-1 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
89
- >
90
- <X className="w-5 h-5" />
91
- </button>
92
- </div>
93
-
94
- {/* Form */}
95
- <form onSubmit={handleSubmit} className="flex-1 overflow-y-auto p-4 space-y-4">
96
- {/* Port */}
97
- <div>
98
- <label className="block text-sm font-medium text-gray-700 mb-1">
99
- Port
100
- </label>
101
- <input
102
- type="number"
103
- value={formData.port}
104
- onChange={(e) => setFormData({ ...formData, port: parseInt(e.target.value) || 9100 })}
105
- min={1024}
106
- max={65535}
107
- className="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent"
108
- />
109
- <p className="text-xs text-gray-500 mt-1">Router service port (requires restart)</p>
110
- </div>
111
-
112
- {/* Host */}
113
- <div>
114
- <label className="block text-sm font-medium text-gray-700 mb-1">
115
- Host
116
- </label>
117
- <select
118
- value={formData.host}
119
- onChange={(e) => setFormData({ ...formData, host: e.target.value })}
120
- className="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent bg-white"
121
- >
122
- <option value="127.0.0.1">127.0.0.1 (localhost only)</option>
123
- <option value="0.0.0.0">0.0.0.0 (all interfaces)</option>
124
- </select>
125
- <p className="text-xs text-gray-500 mt-1">Network interface (requires restart)</p>
126
- </div>
127
-
128
- {/* Request Timeout */}
129
- <div>
130
- <label className="block text-sm font-medium text-gray-700 mb-1">
131
- Request Timeout
132
- </label>
133
- <input
134
- type="number"
135
- value={formData.requestTimeout / 1000}
136
- onChange={(e) => setFormData({ ...formData, requestTimeout: (parseInt(e.target.value) || 120) * 1000 })}
137
- min={10}
138
- max={600}
139
- step={10}
140
- className="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent"
141
- />
142
- <p className="text-xs text-gray-500 mt-1">
143
- {formData.requestTimeout / 1000}s - Maximum time to wait for backend responses
144
- </p>
145
- </div>
146
-
147
- {/* Health Check Interval */}
148
- <div>
149
- <label className="block text-sm font-medium text-gray-700 mb-1">
150
- Health Check Interval
151
- </label>
152
- <input
153
- type="number"
154
- value={formData.healthCheckInterval / 1000}
155
- onChange={(e) => setFormData({ ...formData, healthCheckInterval: (parseInt(e.target.value) || 5) * 1000 })}
156
- min={1}
157
- max={60}
158
- className="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent"
159
- />
160
- <p className="text-xs text-gray-500 mt-1">
161
- {formData.healthCheckInterval / 1000}s - How often to check backend server health
162
- </p>
163
- </div>
164
-
165
- {/* Verbose */}
166
- <div className="flex items-center justify-between">
167
- <div>
168
- <label className="text-sm font-medium text-gray-700">Verbose Logging</label>
169
- <p className="text-xs text-gray-500">Log detailed request information</p>
170
- </div>
171
- <button
172
- type="button"
173
- onClick={() => setFormData({ ...formData, verbose: !formData.verbose })}
174
- className={`relative w-11 h-6 rounded-full transition-colors cursor-pointer ${
175
- formData.verbose ? 'bg-gray-900' : 'bg-gray-200'
176
- }`}
177
- >
178
- <span
179
- className={`absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition-transform ${
180
- formData.verbose ? 'translate-x-5' : ''
181
- }`}
182
- />
183
- </button>
184
- </div>
185
-
186
- {/* Restart option (only show if router is running) */}
187
- {router.isRunning && (
188
- <div className="flex items-center gap-2 pt-2 border-t border-gray-100">
189
- <input
190
- type="checkbox"
191
- id="restartAfterSave"
192
- checked={restartAfterSave}
193
- onChange={(e) => setRestartAfterSave(e.target.checked)}
194
- className="w-4 h-4 text-gray-900 border-gray-300 rounded focus:ring-gray-200"
195
- />
196
- <label htmlFor="restartAfterSave" className="text-sm text-gray-700">
197
- Restart router to apply changes
198
- </label>
199
- </div>
200
- )}
201
-
202
- {/* Error */}
203
- {error && (
204
- <div className="p-3 bg-red-50 border border-red-200 rounded-lg">
205
- <p className="text-sm text-red-700">{error}</p>
206
- </div>
207
- )}
208
- </form>
209
-
210
- {/* Footer */}
211
- <div className="flex items-center justify-end gap-2 px-4 py-3 border-t border-gray-200">
212
- <button
213
- type="button"
214
- onClick={onClose}
215
- className="px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
216
- >
217
- Cancel
218
- </button>
219
- <button
220
- onClick={handleSubmit}
221
- disabled={updateRouter.isPending}
222
- className="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-gray-900 hover:bg-gray-800 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-wait cursor-pointer"
223
- >
224
- {updateRouter.isPending ? (
225
- <>
226
- <Loader2 className="w-4 h-4 animate-spin" />
227
- Saving...
228
- </>
229
- ) : (
230
- <>
231
- <Save className="w-4 h-4" />
232
- Save Changes
233
- </>
234
- )}
235
- </button>
236
- </div>
237
- </div>
238
- </div>
239
- );
240
- }