@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.
- package/README.md +572 -170
- package/dist/cli.js +99 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/admin/config.d.ts +10 -0
- package/dist/commands/admin/config.d.ts.map +1 -0
- package/dist/commands/admin/config.js +100 -0
- package/dist/commands/admin/config.js.map +1 -0
- package/dist/commands/admin/logs.d.ts +10 -0
- package/dist/commands/admin/logs.d.ts.map +1 -0
- package/dist/commands/admin/logs.js +114 -0
- package/dist/commands/admin/logs.js.map +1 -0
- package/dist/commands/admin/restart.d.ts +2 -0
- package/dist/commands/admin/restart.d.ts.map +1 -0
- package/dist/commands/admin/restart.js +29 -0
- package/dist/commands/admin/restart.js.map +1 -0
- package/dist/commands/admin/start.d.ts +2 -0
- package/dist/commands/admin/start.d.ts.map +1 -0
- package/dist/commands/admin/start.js +30 -0
- package/dist/commands/admin/start.js.map +1 -0
- package/dist/commands/admin/status.d.ts +2 -0
- package/dist/commands/admin/status.d.ts.map +1 -0
- package/dist/commands/admin/status.js +82 -0
- package/dist/commands/admin/status.js.map +1 -0
- package/dist/commands/admin/stop.d.ts +2 -0
- package/dist/commands/admin/stop.d.ts.map +1 -0
- package/dist/commands/admin/stop.js +21 -0
- package/dist/commands/admin/stop.js.map +1 -0
- package/dist/commands/logs.d.ts +1 -0
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +22 -0
- package/dist/commands/logs.js.map +1 -1
- package/dist/lib/admin-manager.d.ts +111 -0
- package/dist/lib/admin-manager.d.ts.map +1 -0
- package/dist/lib/admin-manager.js +413 -0
- package/dist/lib/admin-manager.js.map +1 -0
- package/dist/lib/admin-server.d.ts +148 -0
- package/dist/lib/admin-server.d.ts.map +1 -0
- package/dist/lib/admin-server.js +1161 -0
- package/dist/lib/admin-server.js.map +1 -0
- package/dist/lib/download-job-manager.d.ts +64 -0
- package/dist/lib/download-job-manager.d.ts.map +1 -0
- package/dist/lib/download-job-manager.js +164 -0
- package/dist/lib/download-job-manager.js.map +1 -0
- package/dist/tui/MultiServerMonitorApp.js +1 -1
- package/dist/types/admin-config.d.ts +19 -0
- package/dist/types/admin-config.d.ts.map +1 -0
- package/dist/types/admin-config.js +3 -0
- package/dist/types/admin-config.js.map +1 -0
- package/dist/utils/log-parser.d.ts +9 -0
- package/dist/utils/log-parser.d.ts.map +1 -1
- package/dist/utils/log-parser.js +11 -0
- package/dist/utils/log-parser.js.map +1 -1
- package/package.json +10 -2
- package/web/README.md +429 -0
- package/web/dist/assets/index-Bin89Lwr.css +1 -0
- package/web/dist/assets/index-CVmonw3T.js +17 -0
- package/web/dist/index.html +14 -0
- package/web/dist/vite.svg +1 -0
- package/.versionrc.json +0 -16
- package/CHANGELOG.md +0 -203
- package/MONITORING-ACCURACY-FIX.md +0 -199
- package/PER-PROCESS-METRICS.md +0 -190
- package/docs/images/.gitkeep +0 -1
- package/src/cli.ts +0 -423
- package/src/commands/config-global.ts +0 -38
- package/src/commands/config.ts +0 -323
- package/src/commands/create.ts +0 -183
- package/src/commands/delete.ts +0 -74
- package/src/commands/list.ts +0 -37
- package/src/commands/logs-all.ts +0 -251
- package/src/commands/logs.ts +0 -321
- package/src/commands/monitor.ts +0 -110
- package/src/commands/ps.ts +0 -84
- package/src/commands/pull.ts +0 -44
- package/src/commands/rm.ts +0 -107
- package/src/commands/router/config.ts +0 -116
- package/src/commands/router/logs.ts +0 -256
- package/src/commands/router/restart.ts +0 -36
- package/src/commands/router/start.ts +0 -60
- package/src/commands/router/status.ts +0 -119
- package/src/commands/router/stop.ts +0 -33
- package/src/commands/run.ts +0 -233
- package/src/commands/search.ts +0 -107
- package/src/commands/server-show.ts +0 -161
- package/src/commands/show.ts +0 -207
- package/src/commands/start.ts +0 -101
- package/src/commands/stop.ts +0 -39
- package/src/commands/tui.ts +0 -25
- package/src/lib/config-generator.ts +0 -130
- package/src/lib/history-manager.ts +0 -172
- package/src/lib/launchctl-manager.ts +0 -225
- package/src/lib/metrics-aggregator.ts +0 -257
- package/src/lib/model-downloader.ts +0 -328
- package/src/lib/model-scanner.ts +0 -157
- package/src/lib/model-search.ts +0 -114
- package/src/lib/models-dir-setup.ts +0 -46
- package/src/lib/port-manager.ts +0 -80
- package/src/lib/router-logger.ts +0 -201
- package/src/lib/router-manager.ts +0 -414
- package/src/lib/router-server.ts +0 -538
- package/src/lib/state-manager.ts +0 -206
- package/src/lib/status-checker.ts +0 -113
- package/src/lib/system-collector.ts +0 -315
- package/src/tui/ConfigApp.ts +0 -1085
- package/src/tui/HistoricalMonitorApp.ts +0 -587
- package/src/tui/ModelsApp.ts +0 -368
- package/src/tui/MonitorApp.ts +0 -386
- package/src/tui/MultiServerMonitorApp.ts +0 -1833
- package/src/tui/RootNavigator.ts +0 -74
- package/src/tui/SearchApp.ts +0 -511
- package/src/tui/SplashScreen.ts +0 -149
- package/src/types/global-config.ts +0 -26
- package/src/types/history-types.ts +0 -39
- package/src/types/model-info.ts +0 -8
- package/src/types/monitor-types.ts +0 -162
- package/src/types/router-config.ts +0 -25
- package/src/types/server-config.ts +0 -46
- package/src/utils/downsample-utils.ts +0 -128
- package/src/utils/file-utils.ts +0 -146
- package/src/utils/format-utils.ts +0 -98
- package/src/utils/log-parser.ts +0 -271
- package/src/utils/log-utils.ts +0 -178
- package/src/utils/process-utils.ts +0 -316
- package/src/utils/prompt-utils.ts +0 -47
- package/test-load.sh +0 -100
- package/tsconfig.json +0 -20
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { stateManager } from '../lib/state-manager';
|
|
3
|
-
import { statusChecker } from '../lib/status-checker';
|
|
4
|
-
import { formatUptime, formatBytes, formatContextSize } from '../utils/format-utils';
|
|
5
|
-
import { getProcessMemory } from '../utils/process-utils';
|
|
6
|
-
import { getFileSize, formatFileSize, getArchivedLogInfo } from '../utils/log-utils';
|
|
7
|
-
import { fileExists } from '../utils/file-utils';
|
|
8
|
-
|
|
9
|
-
export async function serverShowCommand(identifier: string): Promise<void> {
|
|
10
|
-
// Find the server
|
|
11
|
-
const server = await stateManager.findServer(identifier);
|
|
12
|
-
|
|
13
|
-
if (!server) {
|
|
14
|
-
console.error(chalk.red(`❌ Server not found: ${identifier}`));
|
|
15
|
-
console.log(chalk.dim('\nAvailable servers:'));
|
|
16
|
-
const allServers = await stateManager.getAllServers();
|
|
17
|
-
if (allServers.length === 0) {
|
|
18
|
-
console.log(chalk.dim(' (none)'));
|
|
19
|
-
console.log(chalk.dim('\nCreate a server: llamacpp server create <model-filename>'));
|
|
20
|
-
} else {
|
|
21
|
-
allServers.forEach(s => {
|
|
22
|
-
console.log(chalk.dim(` - ${s.id} (port ${s.port})`));
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Update status to get real-time info
|
|
29
|
-
console.log(chalk.dim('Checking server status...\n'));
|
|
30
|
-
const updatedServer = await statusChecker.updateServerStatus(server);
|
|
31
|
-
|
|
32
|
-
// Display server information
|
|
33
|
-
console.log(chalk.bold('Server Configuration:'));
|
|
34
|
-
console.log('─'.repeat(70));
|
|
35
|
-
|
|
36
|
-
// Basic info
|
|
37
|
-
console.log(`${chalk.bold('Server ID:')} ${updatedServer.id}`);
|
|
38
|
-
console.log(`${chalk.bold('Model Name:')} ${updatedServer.modelName}`);
|
|
39
|
-
console.log(`${chalk.bold('Model Path:')} ${chalk.dim(updatedServer.modelPath)}`);
|
|
40
|
-
console.log(`${chalk.bold('Host:')} ${updatedServer.host}`);
|
|
41
|
-
console.log(`${chalk.bold('Port:')} http://${updatedServer.host}:${updatedServer.port}`);
|
|
42
|
-
|
|
43
|
-
// Status with color
|
|
44
|
-
let statusText: string;
|
|
45
|
-
let statusColor: (text: string) => string;
|
|
46
|
-
switch (updatedServer.status) {
|
|
47
|
-
case 'running':
|
|
48
|
-
statusText = '✅ RUNNING';
|
|
49
|
-
statusColor = chalk.green;
|
|
50
|
-
break;
|
|
51
|
-
case 'crashed':
|
|
52
|
-
statusText = '❌ CRASHED';
|
|
53
|
-
statusColor = chalk.red;
|
|
54
|
-
break;
|
|
55
|
-
default:
|
|
56
|
-
statusText = '⚠️ STOPPED';
|
|
57
|
-
statusColor = chalk.yellow;
|
|
58
|
-
}
|
|
59
|
-
console.log(`${chalk.bold('Status:')} ${statusColor(statusText)}`);
|
|
60
|
-
|
|
61
|
-
if (updatedServer.pid) {
|
|
62
|
-
console.log(`${chalk.bold('PID:')} ${updatedServer.pid}`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Runtime info for running servers
|
|
66
|
-
if (updatedServer.status === 'running') {
|
|
67
|
-
if (updatedServer.lastStarted) {
|
|
68
|
-
const uptime = formatUptime(updatedServer.lastStarted);
|
|
69
|
-
console.log(`${chalk.bold('Uptime:')} ${uptime}`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (updatedServer.pid) {
|
|
73
|
-
const cpuMemoryBytes = await getProcessMemory(updatedServer.pid);
|
|
74
|
-
if (cpuMemoryBytes !== null) {
|
|
75
|
-
const metalMemoryBytes = updatedServer.metalMemoryMB ? updatedServer.metalMemoryMB * 1024 * 1024 : 0;
|
|
76
|
-
const totalMemoryBytes = cpuMemoryBytes + metalMemoryBytes;
|
|
77
|
-
|
|
78
|
-
if (metalMemoryBytes > 0) {
|
|
79
|
-
console.log(`${chalk.bold('Memory:')} ${formatBytes(totalMemoryBytes)} (CPU: ${formatBytes(cpuMemoryBytes)}, GPU: ${formatBytes(metalMemoryBytes)})`);
|
|
80
|
-
} else {
|
|
81
|
-
console.log(`${chalk.bold('Memory:')} ${formatBytes(cpuMemoryBytes)} (CPU only)`);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Configuration section
|
|
88
|
-
console.log('\n' + '─'.repeat(70));
|
|
89
|
-
console.log(chalk.bold('Configuration:'));
|
|
90
|
-
console.log('─'.repeat(70));
|
|
91
|
-
console.log(`${chalk.bold('Threads:')} ${updatedServer.threads}`);
|
|
92
|
-
console.log(`${chalk.bold('Context Size:')} ${formatContextSize(updatedServer.ctxSize)} (total)`);
|
|
93
|
-
console.log(`${chalk.bold('GPU Layers:')} ${updatedServer.gpuLayers}`);
|
|
94
|
-
console.log(`${chalk.bold('Embeddings:')} ${updatedServer.embeddings ? 'enabled' : 'disabled'}`);
|
|
95
|
-
console.log(`${chalk.bold('Jinja:')} ${updatedServer.jinja ? 'enabled' : 'disabled'}`);
|
|
96
|
-
console.log(`${chalk.bold('Verbose Logs:')} ${updatedServer.verbose ? chalk.green('enabled') : chalk.dim('disabled')}`);
|
|
97
|
-
if (updatedServer.customFlags && updatedServer.customFlags.length > 0) {
|
|
98
|
-
console.log(`${chalk.bold('Custom Flags:')} ${updatedServer.customFlags.join(' ')}`);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Logs section
|
|
102
|
-
console.log('\n' + '─'.repeat(70));
|
|
103
|
-
console.log(chalk.bold('Logs:'));
|
|
104
|
-
console.log('─'.repeat(70));
|
|
105
|
-
|
|
106
|
-
// Get current log sizes
|
|
107
|
-
const stderrSize = (await fileExists(updatedServer.stderrPath))
|
|
108
|
-
? await getFileSize(updatedServer.stderrPath)
|
|
109
|
-
: 0;
|
|
110
|
-
const stdoutSize = (await fileExists(updatedServer.stdoutPath))
|
|
111
|
-
? await getFileSize(updatedServer.stdoutPath)
|
|
112
|
-
: 0;
|
|
113
|
-
|
|
114
|
-
// Get archived log info
|
|
115
|
-
const archivedInfo = await getArchivedLogInfo(updatedServer.id);
|
|
116
|
-
|
|
117
|
-
console.log(`${chalk.bold('Stderr:')} ${formatFileSize(stderrSize)} (current)`);
|
|
118
|
-
console.log(`${chalk.bold('Stdout:')} ${formatFileSize(stdoutSize)} (current)`);
|
|
119
|
-
|
|
120
|
-
if (archivedInfo.count > 0) {
|
|
121
|
-
console.log(`${chalk.bold('Archived:')} ${formatFileSize(archivedInfo.totalSize)} (${archivedInfo.count} file${archivedInfo.count > 1 ? 's' : ''})`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Timestamps section
|
|
125
|
-
console.log('\n' + '─'.repeat(70));
|
|
126
|
-
console.log(chalk.bold('Timestamps:'));
|
|
127
|
-
console.log('─'.repeat(70));
|
|
128
|
-
console.log(`${chalk.bold('Created:')} ${new Date(updatedServer.createdAt).toLocaleString()}`);
|
|
129
|
-
if (updatedServer.lastStarted) {
|
|
130
|
-
console.log(`${chalk.bold('Last Started:')} ${new Date(updatedServer.lastStarted).toLocaleString()}`);
|
|
131
|
-
}
|
|
132
|
-
if (updatedServer.lastStopped) {
|
|
133
|
-
console.log(`${chalk.bold('Last Stopped:')} ${new Date(updatedServer.lastStopped).toLocaleString()}`);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// System paths section
|
|
137
|
-
console.log('\n' + '─'.repeat(70));
|
|
138
|
-
console.log(chalk.bold('System Paths:'));
|
|
139
|
-
console.log('─'.repeat(70));
|
|
140
|
-
console.log(`${chalk.bold('Service Label:')} ${updatedServer.label}`);
|
|
141
|
-
console.log(`${chalk.bold('Plist File:')} ${chalk.dim(updatedServer.plistPath)}`);
|
|
142
|
-
console.log(`${chalk.bold('Stdout Log:')} ${chalk.dim(updatedServer.stdoutPath)}`);
|
|
143
|
-
console.log(`${chalk.bold('Stderr Log:')} ${chalk.dim(updatedServer.stderrPath)}`);
|
|
144
|
-
|
|
145
|
-
// Helpful commands
|
|
146
|
-
console.log('\n' + '─'.repeat(70));
|
|
147
|
-
console.log(chalk.bold('Quick Commands:'));
|
|
148
|
-
console.log('─'.repeat(70));
|
|
149
|
-
|
|
150
|
-
if (updatedServer.status === 'running') {
|
|
151
|
-
console.log(chalk.dim(' View logs: ') + `llamacpp server logs ${updatedServer.id}`);
|
|
152
|
-
console.log(chalk.dim(' Interactive chat: ') + `llamacpp server run ${updatedServer.id}`);
|
|
153
|
-
console.log(chalk.dim(' Stop server: ') + `llamacpp server stop ${updatedServer.id}`);
|
|
154
|
-
} else {
|
|
155
|
-
console.log(chalk.dim(' Start server: ') + `llamacpp server start ${updatedServer.id}`);
|
|
156
|
-
if (updatedServer.status === 'crashed') {
|
|
157
|
-
console.log(chalk.dim(' View error logs: ') + `llamacpp server logs ${updatedServer.id} --errors`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
console.log(chalk.dim(' Remove server: ') + `llamacpp server rm ${updatedServer.id}`);
|
|
161
|
-
}
|
package/src/commands/show.ts
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import Table from 'cli-table3';
|
|
3
|
-
import { modelSearch } from '../lib/model-search';
|
|
4
|
-
import { modelDownloader } from '../lib/model-downloader';
|
|
5
|
-
import { formatBytes } from '../utils/format-utils';
|
|
6
|
-
import * as https from 'https';
|
|
7
|
-
|
|
8
|
-
interface ShowOptions {
|
|
9
|
-
file?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface ModelDetails {
|
|
13
|
-
modelId: string;
|
|
14
|
-
author: string;
|
|
15
|
-
modelName: string;
|
|
16
|
-
downloads: number;
|
|
17
|
-
likes: number;
|
|
18
|
-
lastModified: string;
|
|
19
|
-
tags: string[];
|
|
20
|
-
library?: string;
|
|
21
|
-
license?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface FileDetails {
|
|
25
|
-
filename: string;
|
|
26
|
-
size: number;
|
|
27
|
-
lfs?: {
|
|
28
|
-
oid: string;
|
|
29
|
-
size: number;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function showCommand(identifier: string, options: ShowOptions): Promise<void> {
|
|
34
|
-
// Parse identifier
|
|
35
|
-
const parsed = modelDownloader.parseHFIdentifier(identifier);
|
|
36
|
-
const filename = options.file || parsed.file;
|
|
37
|
-
|
|
38
|
-
console.log(chalk.blue('📋 Fetching model information...\n'));
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
// Get model details
|
|
42
|
-
const modelDetails = await getModelDetails(parsed.repo);
|
|
43
|
-
|
|
44
|
-
// Display model information
|
|
45
|
-
displayModelInfo(modelDetails);
|
|
46
|
-
|
|
47
|
-
// If specific file requested, show file details
|
|
48
|
-
if (filename) {
|
|
49
|
-
console.log(chalk.blue('\n📄 File Details:\n'));
|
|
50
|
-
await displayFileInfo(parsed.repo, filename);
|
|
51
|
-
} else {
|
|
52
|
-
// Show all GGUF files
|
|
53
|
-
console.log(chalk.blue('\n📦 Available GGUF Files:\n'));
|
|
54
|
-
await displayAllFiles(parsed.repo);
|
|
55
|
-
}
|
|
56
|
-
} catch (error) {
|
|
57
|
-
throw new Error(`Failed to fetch model details: ${(error as Error).message}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function getModelDetails(modelId: string): Promise<ModelDetails> {
|
|
62
|
-
return new Promise((resolve, reject) => {
|
|
63
|
-
const url = `https://huggingface.co/api/models/${modelId}`;
|
|
64
|
-
|
|
65
|
-
https.get(url, (response) => {
|
|
66
|
-
let data = '';
|
|
67
|
-
|
|
68
|
-
response.on('data', (chunk) => {
|
|
69
|
-
data += chunk;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
response.on('end', () => {
|
|
73
|
-
try {
|
|
74
|
-
const json = JSON.parse(data);
|
|
75
|
-
const parts = modelId.split('/');
|
|
76
|
-
|
|
77
|
-
resolve({
|
|
78
|
-
modelId,
|
|
79
|
-
author: parts[0] || '',
|
|
80
|
-
modelName: parts.slice(1).join('/') || '',
|
|
81
|
-
downloads: json.downloads || 0,
|
|
82
|
-
likes: json.likes || 0,
|
|
83
|
-
lastModified: json.lastModified || '',
|
|
84
|
-
tags: json.tags || [],
|
|
85
|
-
library: json.library_name,
|
|
86
|
-
license: json.cardData?.license,
|
|
87
|
-
});
|
|
88
|
-
} catch (error) {
|
|
89
|
-
reject(new Error(`Failed to parse model data: ${(error as Error).message}`));
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}).on('error', (error) => {
|
|
93
|
-
reject(error);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function displayModelInfo(details: ModelDetails): void {
|
|
99
|
-
console.log(chalk.bold('Model Information:'));
|
|
100
|
-
console.log(chalk.dim('─'.repeat(60)));
|
|
101
|
-
console.log(`${chalk.bold('ID:')} ${details.modelId}`);
|
|
102
|
-
console.log(`${chalk.bold('Author:')} ${details.author}`);
|
|
103
|
-
console.log(`${chalk.bold('Downloads:')} ${details.downloads.toLocaleString()}`);
|
|
104
|
-
console.log(`${chalk.bold('Likes:')} ${details.likes.toLocaleString()}`);
|
|
105
|
-
console.log(`${chalk.bold('Last Updated:')} ${new Date(details.lastModified).toLocaleDateString()}`);
|
|
106
|
-
|
|
107
|
-
if (details.license) {
|
|
108
|
-
console.log(`${chalk.bold('License:')} ${details.license}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (details.tags.length > 0) {
|
|
112
|
-
const relevantTags = details.tags
|
|
113
|
-
.filter(tag => !tag.startsWith('arxiv:') && !tag.startsWith('dataset:'))
|
|
114
|
-
.slice(0, 5);
|
|
115
|
-
if (relevantTags.length > 0) {
|
|
116
|
-
console.log(`${chalk.bold('Tags:')} ${relevantTags.join(', ')}`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async function displayFileInfo(modelId: string, filename: string): Promise<void> {
|
|
122
|
-
const files = await getModelFiles(modelId);
|
|
123
|
-
const file = files.find(f => f.filename === filename);
|
|
124
|
-
|
|
125
|
-
if (!file) {
|
|
126
|
-
console.log(chalk.yellow(`⚠️ File not found: ${filename}`));
|
|
127
|
-
console.log(chalk.dim('\nAvailable files:'));
|
|
128
|
-
files.forEach(f => console.log(chalk.dim(` - ${f.filename}`)));
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const size = file.lfs?.size || file.size || 0;
|
|
133
|
-
|
|
134
|
-
console.log(`${chalk.bold('Filename:')} ${file.filename}`);
|
|
135
|
-
console.log(`${chalk.bold('Size:')} ${formatBytes(size)}`);
|
|
136
|
-
|
|
137
|
-
if (file.lfs) {
|
|
138
|
-
console.log(`${chalk.bold('SHA256:')} ${file.lfs.oid.substring(0, 16)}...`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
console.log(chalk.dim('\nTo download:'));
|
|
142
|
-
console.log(chalk.dim(` llamacpp pull ${modelId}/${filename}`));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async function displayAllFiles(modelId: string): Promise<void> {
|
|
146
|
-
const files = await getModelFiles(modelId);
|
|
147
|
-
const ggufFiles = files.filter(f => f.filename.toLowerCase().endsWith('.gguf'));
|
|
148
|
-
|
|
149
|
-
if (ggufFiles.length === 0) {
|
|
150
|
-
console.log(chalk.yellow('No GGUF files found in this model.'));
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const table = new Table({
|
|
155
|
-
head: ['FILENAME', 'SIZE'],
|
|
156
|
-
colWidths: [55, 12],
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
for (const file of ggufFiles) {
|
|
160
|
-
// LFS files store size in the lfs object, regular files in size field
|
|
161
|
-
const size = (file.lfs && typeof file.lfs.size === 'number') ? file.lfs.size : file.size;
|
|
162
|
-
table.push([
|
|
163
|
-
file.filename,
|
|
164
|
-
size > 0 ? formatBytes(size) : chalk.dim('Unknown'),
|
|
165
|
-
]);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
console.log(table.toString());
|
|
169
|
-
|
|
170
|
-
const totalSize = ggufFiles.reduce((sum, f) => {
|
|
171
|
-
const size = (f.lfs && typeof f.lfs.size === 'number') ? f.lfs.size : f.size;
|
|
172
|
-
return sum + size;
|
|
173
|
-
}, 0);
|
|
174
|
-
console.log(chalk.dim(`\nTotal: ${ggufFiles.length} files (${formatBytes(totalSize)})`));
|
|
175
|
-
console.log(chalk.dim('\nTo download a specific file:'));
|
|
176
|
-
console.log(chalk.dim(` llamacpp pull ${modelId}/<filename>`));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async function getModelFiles(modelId: string): Promise<FileDetails[]> {
|
|
180
|
-
return new Promise((resolve, reject) => {
|
|
181
|
-
const url = `https://huggingface.co/api/models/${modelId}`;
|
|
182
|
-
|
|
183
|
-
https.get(url, (response) => {
|
|
184
|
-
let data = '';
|
|
185
|
-
|
|
186
|
-
response.on('data', (chunk) => {
|
|
187
|
-
data += chunk;
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
response.on('end', () => {
|
|
191
|
-
try {
|
|
192
|
-
const json = JSON.parse(data);
|
|
193
|
-
const files: FileDetails[] = (json.siblings || []).map((file: any) => ({
|
|
194
|
-
filename: file.rfilename,
|
|
195
|
-
size: file.size || 0,
|
|
196
|
-
lfs: file.lfs,
|
|
197
|
-
}));
|
|
198
|
-
resolve(files);
|
|
199
|
-
} catch (error) {
|
|
200
|
-
reject(new Error(`Failed to parse file data: ${(error as Error).message}`));
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}).on('error', (error) => {
|
|
204
|
-
reject(error);
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
}
|
package/src/commands/start.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { stateManager } from '../lib/state-manager';
|
|
3
|
-
import { launchctlManager } from '../lib/launchctl-manager';
|
|
4
|
-
import { statusChecker } from '../lib/status-checker';
|
|
5
|
-
import { parseMetalMemoryFromLog } from '../utils/file-utils';
|
|
6
|
-
import { autoRotateIfNeeded, formatFileSize } from '../utils/log-utils';
|
|
7
|
-
|
|
8
|
-
export async function startCommand(identifier: string): Promise<void> {
|
|
9
|
-
// Initialize state manager
|
|
10
|
-
await stateManager.initialize();
|
|
11
|
-
|
|
12
|
-
// 1. Find server by identifier
|
|
13
|
-
const server = await stateManager.findServer(identifier);
|
|
14
|
-
if (!server) {
|
|
15
|
-
throw new Error(
|
|
16
|
-
`Server not found: ${identifier}\n\n` +
|
|
17
|
-
`Use: llamacpp ps\n` +
|
|
18
|
-
`Or create a new server: llamacpp server create <model>`
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 2. Check if already running
|
|
23
|
-
if (server.status === 'running') {
|
|
24
|
-
console.log(
|
|
25
|
-
chalk.yellow(
|
|
26
|
-
`⚠️ Server ${server.modelName} is already running on port ${server.port}`
|
|
27
|
-
)
|
|
28
|
-
);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
console.log(chalk.blue(`▶️ Starting ${server.modelName} (port ${server.port})...`));
|
|
33
|
-
|
|
34
|
-
// 3. Auto-rotate logs if they exceed 100MB
|
|
35
|
-
try {
|
|
36
|
-
const result = await autoRotateIfNeeded(server.stdoutPath, server.stderrPath, 100);
|
|
37
|
-
if (result.rotated) {
|
|
38
|
-
console.log(chalk.dim('Auto-rotated large log files:'));
|
|
39
|
-
for (const file of result.files) {
|
|
40
|
-
console.log(chalk.dim(` → ${file}`));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
} catch (error) {
|
|
44
|
-
// Non-fatal, just warn
|
|
45
|
-
console.log(chalk.yellow(`⚠️ Failed to rotate logs: ${(error as Error).message}`));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// 4. Ensure plist exists (recreate if missing)
|
|
49
|
-
try {
|
|
50
|
-
await launchctlManager.createPlist(server);
|
|
51
|
-
} catch (error) {
|
|
52
|
-
// May already exist, that's okay
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 5. Load service if needed
|
|
56
|
-
try {
|
|
57
|
-
await launchctlManager.loadService(server.plistPath);
|
|
58
|
-
} catch (error) {
|
|
59
|
-
// May already be loaded, that's okay
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 6. Start the service
|
|
63
|
-
try {
|
|
64
|
-
await launchctlManager.startService(server.label);
|
|
65
|
-
} catch (error) {
|
|
66
|
-
throw new Error(`Failed to start service: ${(error as Error).message}`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// 7. Wait for startup
|
|
70
|
-
console.log(chalk.dim('Waiting for server to start...'));
|
|
71
|
-
const started = await launchctlManager.waitForServiceStart(server.label, 5000);
|
|
72
|
-
|
|
73
|
-
if (!started) {
|
|
74
|
-
throw new Error(
|
|
75
|
-
`Server failed to start. Check logs with: llamacpp server logs ${server.id}`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// 8. Update server status
|
|
80
|
-
let updatedServer = await statusChecker.updateServerStatus(server);
|
|
81
|
-
|
|
82
|
-
// 9. Parse Metal (GPU) memory allocation if not already captured
|
|
83
|
-
if (!updatedServer.metalMemoryMB) {
|
|
84
|
-
console.log(chalk.dim('Detecting Metal (GPU) memory allocation...'));
|
|
85
|
-
await new Promise(resolve => setTimeout(resolve, 8000)); // 8 second delay
|
|
86
|
-
const metalMemoryMB = await parseMetalMemoryFromLog(updatedServer.stderrPath);
|
|
87
|
-
if (metalMemoryMB) {
|
|
88
|
-
updatedServer = { ...updatedServer, metalMemoryMB };
|
|
89
|
-
await stateManager.saveServerConfig(updatedServer);
|
|
90
|
-
console.log(chalk.dim(`Metal memory: ${metalMemoryMB.toFixed(0)} MB`));
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// 10. Display success
|
|
95
|
-
console.log();
|
|
96
|
-
console.log(chalk.green('✅ Server started successfully!'));
|
|
97
|
-
console.log();
|
|
98
|
-
console.log(chalk.dim(`Connect: http://localhost:${server.port}`));
|
|
99
|
-
console.log(chalk.dim(`View logs: llamacpp server logs ${server.id}`));
|
|
100
|
-
console.log(chalk.dim(`Stop: llamacpp server stop ${server.id}`));
|
|
101
|
-
}
|
package/src/commands/stop.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { stateManager } from '../lib/state-manager';
|
|
3
|
-
import { launchctlManager } from '../lib/launchctl-manager';
|
|
4
|
-
import { statusChecker } from '../lib/status-checker';
|
|
5
|
-
|
|
6
|
-
export async function stopCommand(identifier: string): Promise<void> {
|
|
7
|
-
// Find server
|
|
8
|
-
const server = await stateManager.findServer(identifier);
|
|
9
|
-
if (!server) {
|
|
10
|
-
throw new Error(`Server not found: ${identifier}\n\nUse: llamacpp ps`);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Check if already stopped
|
|
14
|
-
if (server.status === 'stopped') {
|
|
15
|
-
console.log(chalk.yellow(`⚠️ Server ${server.modelName} is already stopped`));
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
console.log(chalk.blue(`⏹️ Stopping ${server.modelName} (port ${server.port})...`));
|
|
20
|
-
|
|
21
|
-
// Unload the service (removes from launchd management - won't auto-restart)
|
|
22
|
-
try {
|
|
23
|
-
await launchctlManager.unloadService(server.plistPath);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
throw new Error(`Failed to unload service: ${(error as Error).message}`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Wait for clean shutdown
|
|
29
|
-
const stopped = await launchctlManager.waitForServiceStop(server.label, 5000);
|
|
30
|
-
|
|
31
|
-
if (!stopped) {
|
|
32
|
-
console.log(chalk.yellow('⚠️ Server did not stop cleanly (timeout)'));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Update server status
|
|
36
|
-
await statusChecker.updateServerStatus(server);
|
|
37
|
-
|
|
38
|
-
console.log(chalk.green('✅ Server stopped'));
|
|
39
|
-
}
|
package/src/commands/tui.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import blessed from 'blessed';
|
|
3
|
-
import { stateManager } from '../lib/state-manager.js';
|
|
4
|
-
import { statusChecker } from '../lib/status-checker.js';
|
|
5
|
-
import { createRootNavigator } from '../tui/RootNavigator.js';
|
|
6
|
-
|
|
7
|
-
export async function tuiCommand(): Promise<void> {
|
|
8
|
-
const servers = await stateManager.getAllServers();
|
|
9
|
-
|
|
10
|
-
if (servers.length === 0) {
|
|
11
|
-
console.log(chalk.yellow('No servers configured.'));
|
|
12
|
-
console.log(chalk.dim('\nCreate a server: llamacpp server create <model-filename>'));
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const serversWithStatus = await statusChecker.updateAllServerStatuses();
|
|
17
|
-
|
|
18
|
-
const screen = blessed.screen({
|
|
19
|
-
smartCSR: true,
|
|
20
|
-
title: 'llama.cpp Server Monitor',
|
|
21
|
-
fullUnicode: true,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
await createRootNavigator(screen, serversWithStatus);
|
|
25
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import * as os from 'os';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { ServerConfig, sanitizeModelName } from '../types/server-config';
|
|
4
|
-
import { getLogsDir, getLaunchAgentsDir } from '../utils/file-utils';
|
|
5
|
-
import { stateManager } from './state-manager';
|
|
6
|
-
|
|
7
|
-
export interface ServerOptions {
|
|
8
|
-
port?: number;
|
|
9
|
-
host?: string;
|
|
10
|
-
threads?: number;
|
|
11
|
-
ctxSize?: number;
|
|
12
|
-
gpuLayers?: number;
|
|
13
|
-
embeddings?: boolean;
|
|
14
|
-
jinja?: boolean;
|
|
15
|
-
verbose?: boolean;
|
|
16
|
-
customFlags?: string[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface SmartDefaults {
|
|
20
|
-
threads: number;
|
|
21
|
-
ctxSize: number;
|
|
22
|
-
gpuLayers: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class ConfigGenerator {
|
|
26
|
-
/**
|
|
27
|
-
* Calculate smart defaults based on model size
|
|
28
|
-
*/
|
|
29
|
-
calculateSmartDefaults(modelSizeBytes: number): SmartDefaults {
|
|
30
|
-
const sizeGB = modelSizeBytes / (1024 ** 3);
|
|
31
|
-
|
|
32
|
-
// Context size based on model size
|
|
33
|
-
let ctxSize: number;
|
|
34
|
-
if (sizeGB < 1) {
|
|
35
|
-
ctxSize = 2048; // < 1GB: small context
|
|
36
|
-
} else if (sizeGB < 3) {
|
|
37
|
-
ctxSize = 4096; // 1-3GB: medium
|
|
38
|
-
} else if (sizeGB < 6) {
|
|
39
|
-
ctxSize = 8192; // 3-6GB: large
|
|
40
|
-
} else {
|
|
41
|
-
ctxSize = 16384; // 6GB+: very large
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// GPU layers - always max for Metal (macOS)
|
|
45
|
-
const gpuLayers = 60; // llama.cpp auto-detects optimal value
|
|
46
|
-
|
|
47
|
-
// Threads - use half of available cores (better performance)
|
|
48
|
-
const cpuCount = os.cpus().length;
|
|
49
|
-
const threads = Math.max(4, Math.floor(cpuCount / 2));
|
|
50
|
-
|
|
51
|
-
return { threads, ctxSize, gpuLayers };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Generate server configuration
|
|
56
|
-
*/
|
|
57
|
-
async generateConfig(
|
|
58
|
-
modelPath: string,
|
|
59
|
-
modelName: string,
|
|
60
|
-
modelSize: number,
|
|
61
|
-
port: number,
|
|
62
|
-
options?: ServerOptions
|
|
63
|
-
): Promise<ServerConfig> {
|
|
64
|
-
// Calculate smart defaults
|
|
65
|
-
const smartDefaults = this.calculateSmartDefaults(modelSize);
|
|
66
|
-
|
|
67
|
-
// Apply user overrides
|
|
68
|
-
const host = options?.host ?? '127.0.0.1'; // Default to localhost (secure)
|
|
69
|
-
const threads = options?.threads ?? smartDefaults.threads;
|
|
70
|
-
const ctxSize = options?.ctxSize ?? smartDefaults.ctxSize;
|
|
71
|
-
const gpuLayers = options?.gpuLayers ?? smartDefaults.gpuLayers;
|
|
72
|
-
const embeddings = options?.embeddings ?? true;
|
|
73
|
-
const jinja = options?.jinja ?? true;
|
|
74
|
-
const verbose = options?.verbose ?? true; // Default to true (HTTP request logging)
|
|
75
|
-
const customFlags = options?.customFlags; // Optional custom flags
|
|
76
|
-
|
|
77
|
-
// Generate server ID
|
|
78
|
-
const id = sanitizeModelName(modelName);
|
|
79
|
-
|
|
80
|
-
// Generate paths
|
|
81
|
-
const label = `com.llama.${id}`;
|
|
82
|
-
const plistPath = path.join(getLaunchAgentsDir(), `${label}.plist`);
|
|
83
|
-
const logsDir = getLogsDir();
|
|
84
|
-
const stdoutPath = path.join(logsDir, `${id}.stdout`);
|
|
85
|
-
const stderrPath = path.join(logsDir, `${id}.stderr`);
|
|
86
|
-
|
|
87
|
-
const config: ServerConfig = {
|
|
88
|
-
id,
|
|
89
|
-
modelPath,
|
|
90
|
-
modelName,
|
|
91
|
-
port,
|
|
92
|
-
host,
|
|
93
|
-
threads,
|
|
94
|
-
ctxSize,
|
|
95
|
-
gpuLayers,
|
|
96
|
-
embeddings,
|
|
97
|
-
jinja,
|
|
98
|
-
verbose,
|
|
99
|
-
customFlags,
|
|
100
|
-
status: 'stopped',
|
|
101
|
-
createdAt: new Date().toISOString(),
|
|
102
|
-
plistPath,
|
|
103
|
-
label,
|
|
104
|
-
stdoutPath,
|
|
105
|
-
stderrPath,
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
return config;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Merge global defaults with user options
|
|
113
|
-
*/
|
|
114
|
-
async mergeWithGlobalDefaults(options?: ServerOptions): Promise<Partial<ServerOptions>> {
|
|
115
|
-
const globalConfig = await stateManager.loadGlobalConfig();
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
host: options?.host ?? '127.0.0.1',
|
|
119
|
-
threads: options?.threads ?? globalConfig.defaults.threads,
|
|
120
|
-
ctxSize: options?.ctxSize ?? globalConfig.defaults.ctxSize,
|
|
121
|
-
gpuLayers: options?.gpuLayers ?? globalConfig.defaults.gpuLayers,
|
|
122
|
-
embeddings: options?.embeddings ?? true,
|
|
123
|
-
jinja: options?.jinja ?? true,
|
|
124
|
-
verbose: options?.verbose ?? true,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Export singleton instance
|
|
130
|
-
export const configGenerator = new ConfigGenerator();
|