@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.
- package/README.md +294 -168
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/launch/claude.d.ts +6 -0
- package/dist/commands/launch/claude.d.ts.map +1 -0
- package/dist/commands/launch/claude.js +277 -0
- package/dist/commands/launch/claude.js.map +1 -0
- package/dist/lib/integration-checker.d.ts +26 -0
- package/dist/lib/integration-checker.d.ts.map +1 -0
- package/dist/lib/integration-checker.js +77 -0
- package/dist/lib/integration-checker.js.map +1 -0
- package/dist/lib/router-manager.d.ts +4 -0
- package/dist/lib/router-manager.d.ts.map +1 -1
- package/dist/lib/router-manager.js +10 -0
- package/dist/lib/router-manager.js.map +1 -1
- package/dist/lib/router-server.d.ts +13 -0
- package/dist/lib/router-server.d.ts.map +1 -1
- package/dist/lib/router-server.js +267 -7
- package/dist/lib/router-server.js.map +1 -1
- package/dist/types/integration-config.d.ts +28 -0
- package/dist/types/integration-config.d.ts.map +1 -0
- package/dist/types/integration-config.js +3 -0
- package/dist/types/integration-config.js.map +1 -0
- package/package.json +10 -2
- package/web/dist/assets/index-Bin89Lwr.css +1 -0
- package/web/dist/assets/index-CVmonw3T.js +17 -0
- package/web/{index.html → dist/index.html} +2 -1
- package/.versionrc.json +0 -16
- package/CHANGELOG.md +0 -213
- package/docs/images/.gitkeep +0 -1
- package/docs/images/web-ui-servers.png +0 -0
- package/src/cli.ts +0 -523
- package/src/commands/admin/config.ts +0 -121
- package/src/commands/admin/logs.ts +0 -91
- package/src/commands/admin/restart.ts +0 -26
- package/src/commands/admin/start.ts +0 -27
- package/src/commands/admin/status.ts +0 -84
- package/src/commands/admin/stop.ts +0 -16
- 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 -345
- 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/admin-manager.ts +0 -435
- package/src/lib/admin-server.ts +0 -1243
- package/src/lib/config-generator.ts +0 -130
- package/src/lib/download-job-manager.ts +0 -213
- 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/admin-config.ts +0 -25
- 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 -284
- 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
- package/web/eslint.config.js +0 -23
- package/web/llamacpp-web-dist.tar.gz +0 -0
- package/web/package-lock.json +0 -4017
- package/web/package.json +0 -38
- package/web/postcss.config.js +0 -6
- package/web/src/App.css +0 -42
- package/web/src/App.tsx +0 -86
- package/web/src/assets/react.svg +0 -1
- package/web/src/components/ApiKeyPrompt.tsx +0 -71
- package/web/src/components/CreateServerModal.tsx +0 -372
- package/web/src/components/DownloadProgress.tsx +0 -123
- package/web/src/components/Nav.tsx +0 -89
- package/web/src/components/RouterConfigModal.tsx +0 -240
- package/web/src/components/SearchModal.tsx +0 -306
- package/web/src/components/ServerConfigModal.tsx +0 -291
- package/web/src/hooks/useApi.ts +0 -259
- package/web/src/index.css +0 -42
- package/web/src/lib/api.ts +0 -226
- package/web/src/main.tsx +0 -10
- package/web/src/pages/Dashboard.tsx +0 -103
- package/web/src/pages/Models.tsx +0 -258
- package/web/src/pages/Router.tsx +0 -270
- package/web/src/pages/RouterLogs.tsx +0 -201
- package/web/src/pages/ServerLogs.tsx +0 -553
- package/web/src/pages/Servers.tsx +0 -358
- package/web/src/types/api.ts +0 -140
- package/web/tailwind.config.js +0 -31
- package/web/tsconfig.app.json +0 -28
- package/web/tsconfig.json +0 -7
- package/web/tsconfig.node.json +0 -26
- package/web/vite.config.ts +0 -25
- /package/web/{public → dist}/vite.svg +0 -0
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { spawn } from 'child_process';
|
|
3
|
-
import * as fs from 'fs/promises';
|
|
4
|
-
import { adminManager } from '../../lib/admin-manager';
|
|
5
|
-
import { fileExists } from '../../utils/file-utils';
|
|
6
|
-
|
|
7
|
-
interface LogsOptions {
|
|
8
|
-
stdout?: boolean;
|
|
9
|
-
stderr?: boolean;
|
|
10
|
-
follow?: boolean;
|
|
11
|
-
clear?: boolean;
|
|
12
|
-
lines?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function adminLogsCommand(options: LogsOptions): Promise<void> {
|
|
16
|
-
try {
|
|
17
|
-
const result = await adminManager.getStatus();
|
|
18
|
-
|
|
19
|
-
if (!result) {
|
|
20
|
-
console.error(chalk.red('✗ Admin service is not configured'));
|
|
21
|
-
console.log(chalk.gray('\nRun: llamacpp admin start'));
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const { config } = result;
|
|
26
|
-
|
|
27
|
-
// Default to stdout if neither specified
|
|
28
|
-
const showStdout = options.stdout || (!options.stdout && !options.stderr);
|
|
29
|
-
const showStderr = options.stderr || (!options.stdout && !options.stderr);
|
|
30
|
-
|
|
31
|
-
// Handle clear operation
|
|
32
|
-
if (options.clear) {
|
|
33
|
-
if (showStdout && (await fileExists(config.stdoutPath))) {
|
|
34
|
-
await fs.writeFile(config.stdoutPath, '');
|
|
35
|
-
console.log(chalk.green('✓ Cleared stdout log'));
|
|
36
|
-
}
|
|
37
|
-
if (showStderr && (await fileExists(config.stderrPath))) {
|
|
38
|
-
await fs.writeFile(config.stderrPath, '');
|
|
39
|
-
console.log(chalk.green('✓ Cleared stderr log'));
|
|
40
|
-
}
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Determine which logs to show
|
|
45
|
-
const logPaths: string[] = [];
|
|
46
|
-
if (showStdout) logPaths.push(config.stdoutPath);
|
|
47
|
-
if (showStderr) logPaths.push(config.stderrPath);
|
|
48
|
-
|
|
49
|
-
// Check if log files exist
|
|
50
|
-
for (const logPath of logPaths) {
|
|
51
|
-
if (!(await fileExists(logPath))) {
|
|
52
|
-
console.log(chalk.yellow(`Log file does not exist: ${logPath}`));
|
|
53
|
-
console.log(chalk.gray('No logs available yet'));
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Follow mode (tail -f)
|
|
59
|
-
if (options.follow) {
|
|
60
|
-
console.log(chalk.blue(`📋 Following admin logs (Ctrl+C to exit)\n`));
|
|
61
|
-
|
|
62
|
-
const tailArgs = ['-f', ...logPaths];
|
|
63
|
-
const tail = spawn('tail', tailArgs, { stdio: 'inherit' });
|
|
64
|
-
|
|
65
|
-
// Handle Ctrl+C gracefully
|
|
66
|
-
process.on('SIGINT', () => {
|
|
67
|
-
tail.kill();
|
|
68
|
-
console.log(chalk.gray('\n\nStopped following logs'));
|
|
69
|
-
process.exit(0);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
tail.on('exit', (code) => {
|
|
73
|
-
process.exit(code || 0);
|
|
74
|
-
});
|
|
75
|
-
} else {
|
|
76
|
-
// Static mode (tail -n)
|
|
77
|
-
const lines = options.lines || 100;
|
|
78
|
-
const tailArgs = ['-n', lines.toString(), ...logPaths];
|
|
79
|
-
|
|
80
|
-
const tail = spawn('tail', tailArgs, { stdio: 'inherit' });
|
|
81
|
-
|
|
82
|
-
tail.on('exit', (code) => {
|
|
83
|
-
process.exit(code || 0);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.error(chalk.red('✗ Failed to read admin logs'));
|
|
88
|
-
console.error(chalk.gray((error as Error).message));
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { adminManager } from '../../lib/admin-manager';
|
|
3
|
-
|
|
4
|
-
export async function adminRestartCommand(): Promise<void> {
|
|
5
|
-
try {
|
|
6
|
-
console.log(chalk.blue('🔄 Restarting admin service...\n'));
|
|
7
|
-
|
|
8
|
-
await adminManager.restart();
|
|
9
|
-
|
|
10
|
-
const result = await adminManager.getStatus();
|
|
11
|
-
if (!result) {
|
|
12
|
-
throw new Error('Failed to retrieve admin status after restart');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const { config, status } = result;
|
|
16
|
-
|
|
17
|
-
console.log(chalk.green('✓ Admin service restarted successfully\n'));
|
|
18
|
-
console.log(chalk.bold(' Endpoint:'), chalk.cyan(`http://${config.host}:${config.port}`));
|
|
19
|
-
console.log(chalk.bold(' PID: '), status.pid);
|
|
20
|
-
console.log();
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error(chalk.red('✗ Failed to restart admin service'));
|
|
23
|
-
console.error(chalk.gray((error as Error).message));
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { adminManager } from '../../lib/admin-manager';
|
|
3
|
-
|
|
4
|
-
export async function adminStartCommand(): Promise<void> {
|
|
5
|
-
try {
|
|
6
|
-
console.log(chalk.blue('🚀 Starting admin service...\n'));
|
|
7
|
-
|
|
8
|
-
await adminManager.start();
|
|
9
|
-
|
|
10
|
-
const result = await adminManager.getStatus();
|
|
11
|
-
if (!result) {
|
|
12
|
-
throw new Error('Failed to retrieve admin status after start');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const { config, status } = result;
|
|
16
|
-
|
|
17
|
-
console.log(chalk.green('✓ Admin service started successfully\n'));
|
|
18
|
-
console.log(chalk.bold(' Endpoint:'), chalk.cyan(`http://${config.host}:${config.port}`));
|
|
19
|
-
console.log(chalk.bold(' API Key: '), chalk.yellow(config.apiKey), chalk.gray('(use for authentication)'));
|
|
20
|
-
console.log(chalk.bold(' PID: '), status.pid);
|
|
21
|
-
console.log();
|
|
22
|
-
} catch (error) {
|
|
23
|
-
console.error(chalk.red('✗ Failed to start admin service'));
|
|
24
|
-
console.error(chalk.gray((error as Error).message));
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { adminManager } from '../../lib/admin-manager';
|
|
3
|
-
|
|
4
|
-
function formatUptime(lastStarted: string): string {
|
|
5
|
-
const start = new Date(lastStarted).getTime();
|
|
6
|
-
const now = Date.now();
|
|
7
|
-
const uptimeSeconds = Math.floor((now - start) / 1000);
|
|
8
|
-
|
|
9
|
-
const hours = Math.floor(uptimeSeconds / 3600);
|
|
10
|
-
const minutes = Math.floor((uptimeSeconds % 3600) / 60);
|
|
11
|
-
|
|
12
|
-
if (hours > 0) {
|
|
13
|
-
return `${hours}h ${minutes}m`;
|
|
14
|
-
}
|
|
15
|
-
return `${minutes}m`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export async function adminStatusCommand(): Promise<void> {
|
|
19
|
-
try {
|
|
20
|
-
const result = await adminManager.getStatus();
|
|
21
|
-
|
|
22
|
-
if (!result) {
|
|
23
|
-
console.log(chalk.yellow('Admin service is not configured'));
|
|
24
|
-
console.log(chalk.gray('\nRun: llamacpp admin start'));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const { config, status } = result;
|
|
29
|
-
|
|
30
|
-
console.log(chalk.bold.underline('Admin Service Status'));
|
|
31
|
-
console.log();
|
|
32
|
-
|
|
33
|
-
// Status
|
|
34
|
-
if (status.isRunning) {
|
|
35
|
-
console.log(chalk.bold(' Status: '), chalk.green('● RUNNING'));
|
|
36
|
-
console.log(chalk.bold(' PID: '), status.pid);
|
|
37
|
-
if (config.lastStarted) {
|
|
38
|
-
console.log(chalk.bold(' Uptime: '), formatUptime(config.lastStarted));
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
console.log(chalk.bold(' Status: '), chalk.gray('○ STOPPED'));
|
|
42
|
-
if (status.lastExitReason) {
|
|
43
|
-
console.log(chalk.bold(' Last Exit:'), chalk.yellow(status.lastExitReason));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
console.log(chalk.bold(' Port: '), config.port);
|
|
48
|
-
console.log(chalk.bold(' Host: '), config.host);
|
|
49
|
-
console.log(chalk.bold(' API Key: '), chalk.yellow(config.apiKey));
|
|
50
|
-
console.log();
|
|
51
|
-
|
|
52
|
-
// Endpoints
|
|
53
|
-
if (status.isRunning) {
|
|
54
|
-
console.log(chalk.bold(' Endpoints:'));
|
|
55
|
-
console.log(chalk.bold(' Health: '), chalk.cyan(`GET http://${config.host}:${config.port}/health`));
|
|
56
|
-
console.log(chalk.bold(' Servers: '), chalk.cyan(`GET http://${config.host}:${config.port}/api/servers`));
|
|
57
|
-
console.log(chalk.bold(' Models: '), chalk.cyan(`GET http://${config.host}:${config.port}/api/models`));
|
|
58
|
-
console.log();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Configuration
|
|
62
|
-
console.log(chalk.bold(' Configuration:'));
|
|
63
|
-
console.log(chalk.bold(' Config: '), chalk.gray(config.plistPath.replace(process.env.HOME || '', '~')));
|
|
64
|
-
console.log(chalk.bold(' Plist: '), chalk.gray(config.plistPath.replace(process.env.HOME || '', '~')));
|
|
65
|
-
console.log(chalk.bold(' Logs: '), chalk.gray(config.stdoutPath.replace('.stdout', '.{stdout,stderr}').replace(process.env.HOME || '', '~')));
|
|
66
|
-
console.log();
|
|
67
|
-
|
|
68
|
-
// Quick commands
|
|
69
|
-
console.log(chalk.bold(' Quick Commands:'));
|
|
70
|
-
if (status.isRunning) {
|
|
71
|
-
console.log(chalk.bold(' Stop: '), chalk.gray('llamacpp admin stop'));
|
|
72
|
-
console.log(chalk.bold(' Restart: '), chalk.gray('llamacpp admin restart'));
|
|
73
|
-
console.log(chalk.bold(' Logs: '), chalk.gray('llamacpp admin logs --follow'));
|
|
74
|
-
} else {
|
|
75
|
-
console.log(chalk.bold(' Start: '), chalk.gray('llamacpp admin start'));
|
|
76
|
-
console.log(chalk.bold(' Logs: '), chalk.gray('llamacpp admin logs'));
|
|
77
|
-
}
|
|
78
|
-
console.log();
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error(chalk.red('✗ Failed to get admin status'));
|
|
81
|
-
console.error(chalk.gray((error as Error).message));
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { adminManager } from '../../lib/admin-manager';
|
|
3
|
-
|
|
4
|
-
export async function adminStopCommand(): Promise<void> {
|
|
5
|
-
try {
|
|
6
|
-
console.log(chalk.blue('⏸ Stopping admin service...\n'));
|
|
7
|
-
|
|
8
|
-
await adminManager.stop();
|
|
9
|
-
|
|
10
|
-
console.log(chalk.green('✓ Admin service stopped successfully'));
|
|
11
|
-
} catch (error) {
|
|
12
|
-
console.error(chalk.red('✗ Failed to stop admin service'));
|
|
13
|
-
console.error(chalk.gray((error as Error).message));
|
|
14
|
-
process.exit(1);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { stateManager } from '../lib/state-manager';
|
|
3
|
-
import { expandHome } from '../utils/file-utils';
|
|
4
|
-
|
|
5
|
-
interface ConfigOptions {
|
|
6
|
-
modelsDir?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export async function configGlobalCommand(options: ConfigOptions): Promise<void> {
|
|
10
|
-
// If no options provided, show current config
|
|
11
|
-
if (!options.modelsDir) {
|
|
12
|
-
const config = await stateManager.loadGlobalConfig();
|
|
13
|
-
|
|
14
|
-
console.log(chalk.blue('⚙️ Global Configuration\n'));
|
|
15
|
-
console.log(chalk.bold('Models Directory:'));
|
|
16
|
-
console.log(` ${config.modelsDirectory}`);
|
|
17
|
-
console.log();
|
|
18
|
-
console.log(chalk.bold('Defaults:'));
|
|
19
|
-
console.log(` Port: ${config.defaultPort}`);
|
|
20
|
-
console.log(` Threads: ${config.defaults.threads}`);
|
|
21
|
-
console.log(` Context: ${config.defaults.ctxSize}`);
|
|
22
|
-
console.log(` GPU Layers: ${config.defaults.gpuLayers}`);
|
|
23
|
-
console.log();
|
|
24
|
-
console.log(chalk.dim('Change models directory: llamacpp config --models-dir <path>'));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Update models directory
|
|
29
|
-
if (options.modelsDir) {
|
|
30
|
-
const newPath = expandHome(options.modelsDir);
|
|
31
|
-
await stateManager.setModelsDirectory(newPath);
|
|
32
|
-
console.log(chalk.green('✅ Models directory updated'));
|
|
33
|
-
console.log(chalk.dim(` New path: ${newPath}`));
|
|
34
|
-
console.log();
|
|
35
|
-
console.log(chalk.dim('Note: This does not move existing models. Use:'));
|
|
36
|
-
console.log(chalk.dim(` mv ~/.llamacpp/models/* ${newPath}/`));
|
|
37
|
-
}
|
|
38
|
-
}
|
package/src/commands/config.ts
DELETED
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as fs from 'fs/promises';
|
|
4
|
-
import { stateManager } from '../lib/state-manager';
|
|
5
|
-
import { statusChecker } from '../lib/status-checker';
|
|
6
|
-
import { launchctlManager } from '../lib/launchctl-manager';
|
|
7
|
-
import { configGenerator } from '../lib/config-generator';
|
|
8
|
-
import { autoRotateIfNeeded } from '../utils/log-utils';
|
|
9
|
-
import { modelScanner } from '../lib/model-scanner';
|
|
10
|
-
import { sanitizeModelName } from '../types/server-config';
|
|
11
|
-
import { getLogsDir, getLaunchAgentsDir } from '../utils/file-utils';
|
|
12
|
-
|
|
13
|
-
export interface ConfigUpdateOptions {
|
|
14
|
-
model?: string;
|
|
15
|
-
host?: string;
|
|
16
|
-
threads?: number;
|
|
17
|
-
ctxSize?: number;
|
|
18
|
-
gpuLayers?: number;
|
|
19
|
-
verbose?: boolean;
|
|
20
|
-
flags?: string;
|
|
21
|
-
restart?: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function serverConfigCommand(
|
|
25
|
-
identifier: string,
|
|
26
|
-
options: ConfigUpdateOptions
|
|
27
|
-
): Promise<void> {
|
|
28
|
-
// Find the server
|
|
29
|
-
const server = await stateManager.findServer(identifier);
|
|
30
|
-
|
|
31
|
-
if (!server) {
|
|
32
|
-
console.error(chalk.red(`❌ Server not found: ${identifier}`));
|
|
33
|
-
console.log(chalk.dim('\nAvailable servers:'));
|
|
34
|
-
const allServers = await stateManager.getAllServers();
|
|
35
|
-
if (allServers.length === 0) {
|
|
36
|
-
console.log(chalk.dim(' (none)'));
|
|
37
|
-
console.log(chalk.dim('\nCreate a server: llamacpp server create <model-filename>'));
|
|
38
|
-
} else {
|
|
39
|
-
allServers.forEach(s => {
|
|
40
|
-
console.log(chalk.dim(` - ${s.id} (port ${s.port})`));
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Check if any config options were provided
|
|
47
|
-
const hasChanges = options.model !== undefined ||
|
|
48
|
-
options.host !== undefined ||
|
|
49
|
-
options.threads !== undefined ||
|
|
50
|
-
options.ctxSize !== undefined ||
|
|
51
|
-
options.gpuLayers !== undefined ||
|
|
52
|
-
options.verbose !== undefined ||
|
|
53
|
-
options.flags !== undefined;
|
|
54
|
-
|
|
55
|
-
if (!hasChanges) {
|
|
56
|
-
console.error(chalk.red('❌ No configuration changes specified'));
|
|
57
|
-
console.log(chalk.dim('\nAvailable options:'));
|
|
58
|
-
console.log(chalk.dim(' --model <filename> Model filename or path'));
|
|
59
|
-
console.log(chalk.dim(' --host <address> Bind address (127.0.0.1 or 0.0.0.0)'));
|
|
60
|
-
console.log(chalk.dim(' --threads <n> Number of threads'));
|
|
61
|
-
console.log(chalk.dim(' --ctx-size <n> Context size'));
|
|
62
|
-
console.log(chalk.dim(' --gpu-layers <n> GPU layers'));
|
|
63
|
-
console.log(chalk.dim(' --verbose Enable verbose logging'));
|
|
64
|
-
console.log(chalk.dim(' --no-verbose Disable verbose logging'));
|
|
65
|
-
console.log(chalk.dim(' --flags <flags> Custom llama-server flags (comma-separated)'));
|
|
66
|
-
console.log(chalk.dim(' --restart Auto-restart if running'));
|
|
67
|
-
console.log(chalk.dim('\nExamples:'));
|
|
68
|
-
console.log(chalk.dim(` llamacpp server config ${server.id} --model llama-3.2-1b.gguf --restart`));
|
|
69
|
-
console.log(chalk.dim(` llamacpp server config ${server.id} --ctx-size 8192 --restart`));
|
|
70
|
-
console.log(chalk.dim(` llamacpp server config ${server.id} --flags="--pooling,mean" --restart`));
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Resolve model path if model option is provided
|
|
75
|
-
let newModelPath: string | undefined;
|
|
76
|
-
let newModelName: string | undefined;
|
|
77
|
-
let newServerId: string | undefined;
|
|
78
|
-
let isModelMigration = false;
|
|
79
|
-
|
|
80
|
-
if (options.model !== undefined) {
|
|
81
|
-
const resolvedPath = await modelScanner.resolveModelPath(options.model);
|
|
82
|
-
if (!resolvedPath) {
|
|
83
|
-
console.error(chalk.red(`❌ Model not found: ${options.model}`));
|
|
84
|
-
console.log(chalk.dim('\nRun: llamacpp ls'));
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
87
|
-
newModelPath = resolvedPath;
|
|
88
|
-
newModelName = path.basename(resolvedPath);
|
|
89
|
-
newServerId = sanitizeModelName(newModelName);
|
|
90
|
-
|
|
91
|
-
// Check if this is a model migration (ID will change)
|
|
92
|
-
if (newServerId !== server.id) {
|
|
93
|
-
isModelMigration = true;
|
|
94
|
-
|
|
95
|
-
// Check for ID conflict
|
|
96
|
-
const existingServer = await stateManager.loadServerConfig(newServerId);
|
|
97
|
-
if (existingServer) {
|
|
98
|
-
console.error(chalk.red(`❌ A server with ID "${newServerId}" already exists`));
|
|
99
|
-
console.log(chalk.dim('\nChanging the model would create this server ID, but it conflicts with an existing server.'));
|
|
100
|
-
console.log(chalk.dim('Delete the existing server first:'));
|
|
101
|
-
console.log(chalk.dim(` llamacpp server rm ${newServerId}`));
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
console.log(chalk.yellow('⚠️ Changing the model will migrate to a new server ID'));
|
|
106
|
-
console.log(chalk.dim(` Old ID: ${server.id}`));
|
|
107
|
-
console.log(chalk.dim(` New ID: ${newServerId}\n`));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Check current status
|
|
112
|
-
const updatedServer = await statusChecker.updateServerStatus(server);
|
|
113
|
-
const wasRunning = updatedServer.status === 'running';
|
|
114
|
-
|
|
115
|
-
if (wasRunning && !options.restart) {
|
|
116
|
-
console.warn(chalk.yellow('⚠️ Server is currently running'));
|
|
117
|
-
console.log(chalk.dim('Changes will require a restart to take effect.'));
|
|
118
|
-
console.log(chalk.dim('Use --restart flag to automatically restart the server.\n'));
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Show what will change
|
|
122
|
-
console.log(chalk.bold('Configuration Changes:'));
|
|
123
|
-
console.log('─'.repeat(70));
|
|
124
|
-
|
|
125
|
-
if (newModelPath !== undefined && newModelName !== undefined) {
|
|
126
|
-
const oldModelName = path.basename(server.modelPath);
|
|
127
|
-
console.log(`${chalk.bold('Model:')} ${chalk.dim(oldModelName)} → ${chalk.green(newModelName)}`);
|
|
128
|
-
console.log(`${chalk.dim(' ')}${chalk.dim(server.modelPath)}`);
|
|
129
|
-
console.log(`${chalk.dim(' ')}${chalk.dim(newModelPath)}`);
|
|
130
|
-
if (isModelMigration && newServerId) {
|
|
131
|
-
console.log(`${chalk.bold('Server ID:')} ${chalk.dim(server.id)} → ${chalk.green(newServerId)}`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
if (options.host !== undefined) {
|
|
135
|
-
console.log(`${chalk.bold('Host:')} ${chalk.dim(server.host)} → ${chalk.green(options.host)}`);
|
|
136
|
-
|
|
137
|
-
// Security warning for 0.0.0.0
|
|
138
|
-
if (options.host === '0.0.0.0') {
|
|
139
|
-
console.log(chalk.yellow('\n⚠️ WARNING: Binding to 0.0.0.0 allows remote access from any network interface.'));
|
|
140
|
-
console.log(chalk.yellow(' This exposes your server to your local network and potentially the internet.'));
|
|
141
|
-
console.log(chalk.yellow(' Use 127.0.0.1 for localhost-only access (recommended for local development).\n'));
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (options.threads !== undefined) {
|
|
145
|
-
console.log(`${chalk.bold('Threads:')} ${chalk.dim(server.threads.toString())} → ${chalk.green(options.threads.toString())}`);
|
|
146
|
-
}
|
|
147
|
-
if (options.ctxSize !== undefined) {
|
|
148
|
-
console.log(`${chalk.bold('Context Size:')} ${chalk.dim(server.ctxSize.toLocaleString())} → ${chalk.green(options.ctxSize.toLocaleString())}`);
|
|
149
|
-
}
|
|
150
|
-
if (options.gpuLayers !== undefined) {
|
|
151
|
-
console.log(`${chalk.bold('GPU Layers:')} ${chalk.dim(server.gpuLayers.toString())} → ${chalk.green(options.gpuLayers.toString())}`);
|
|
152
|
-
}
|
|
153
|
-
if (options.verbose !== undefined) {
|
|
154
|
-
const oldValue = server.verbose ? 'enabled' : 'disabled';
|
|
155
|
-
const newValue = options.verbose ? 'enabled' : 'disabled';
|
|
156
|
-
console.log(`${chalk.bold('Verbose Logs:')} ${chalk.dim(oldValue)} → ${chalk.green(newValue)}`);
|
|
157
|
-
}
|
|
158
|
-
if (options.flags !== undefined) {
|
|
159
|
-
const oldValue = server.customFlags?.join(' ') || 'none';
|
|
160
|
-
const newValue = options.flags || 'none';
|
|
161
|
-
console.log(`${chalk.bold('Custom Flags:')} ${chalk.dim(oldValue)} → ${chalk.green(newValue)}`);
|
|
162
|
-
}
|
|
163
|
-
console.log('');
|
|
164
|
-
|
|
165
|
-
// Parse custom flags if provided
|
|
166
|
-
let customFlags: string[] | undefined;
|
|
167
|
-
if (options.flags !== undefined) {
|
|
168
|
-
if (options.flags === '') {
|
|
169
|
-
customFlags = undefined;
|
|
170
|
-
} else {
|
|
171
|
-
customFlags = options.flags.split(',').map(f => f.trim()).filter(f => f.length > 0);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Handle model migration (different code path when server ID changes)
|
|
176
|
-
if (isModelMigration && newServerId && newModelPath && newModelName) {
|
|
177
|
-
// Stop old server if running
|
|
178
|
-
if (wasRunning) {
|
|
179
|
-
console.log(chalk.dim('Stopping old server...'));
|
|
180
|
-
await launchctlManager.unloadService(server.plistPath);
|
|
181
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Delete old plist and config
|
|
185
|
-
console.log(chalk.dim('Removing old server configuration...'));
|
|
186
|
-
try {
|
|
187
|
-
await fs.unlink(server.plistPath);
|
|
188
|
-
} catch (err) {
|
|
189
|
-
// Plist might not exist, that's ok
|
|
190
|
-
}
|
|
191
|
-
await stateManager.deleteServerConfig(server.id);
|
|
192
|
-
|
|
193
|
-
// Create new config with new ID and all settings
|
|
194
|
-
const logsDir = getLogsDir();
|
|
195
|
-
const plistDir = getLaunchAgentsDir();
|
|
196
|
-
|
|
197
|
-
const newConfig = {
|
|
198
|
-
...server,
|
|
199
|
-
id: newServerId,
|
|
200
|
-
modelPath: newModelPath,
|
|
201
|
-
modelName: newModelName,
|
|
202
|
-
...(options.host !== undefined && { host: options.host }),
|
|
203
|
-
...(options.threads !== undefined && { threads: options.threads }),
|
|
204
|
-
...(options.ctxSize !== undefined && { ctxSize: options.ctxSize }),
|
|
205
|
-
...(options.gpuLayers !== undefined && { gpuLayers: options.gpuLayers }),
|
|
206
|
-
...(options.verbose !== undefined && { verbose: options.verbose }),
|
|
207
|
-
...(options.flags !== undefined && { customFlags }),
|
|
208
|
-
// Update plist-related paths
|
|
209
|
-
label: `com.llama.${newServerId}`,
|
|
210
|
-
plistPath: path.join(plistDir, `com.llama.${newServerId}.plist`),
|
|
211
|
-
stdoutPath: path.join(logsDir, `${newServerId}.stdout`),
|
|
212
|
-
stderrPath: path.join(logsDir, `${newServerId}.stderr`),
|
|
213
|
-
status: 'stopped' as const,
|
|
214
|
-
pid: undefined,
|
|
215
|
-
lastStopped: new Date().toISOString(),
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
console.log(chalk.dim('Creating new server configuration...'));
|
|
219
|
-
await stateManager.saveServerConfig(newConfig);
|
|
220
|
-
await launchctlManager.createPlist(newConfig);
|
|
221
|
-
|
|
222
|
-
// Start new server if restart flag is set
|
|
223
|
-
if (wasRunning && options.restart) {
|
|
224
|
-
console.log(chalk.dim('Starting new server...'));
|
|
225
|
-
await launchctlManager.loadService(newConfig.plistPath);
|
|
226
|
-
await launchctlManager.startService(newConfig.label);
|
|
227
|
-
|
|
228
|
-
// Wait and verify
|
|
229
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
230
|
-
const finalStatus = await statusChecker.updateServerStatus(newConfig);
|
|
231
|
-
|
|
232
|
-
if (finalStatus.status === 'running') {
|
|
233
|
-
console.log(chalk.green(`✅ Server migrated successfully to new ID: ${newServerId}`));
|
|
234
|
-
console.log(chalk.dim(` Port: http://localhost:${finalStatus.port}`));
|
|
235
|
-
if (finalStatus.pid) {
|
|
236
|
-
console.log(chalk.dim(` PID: ${finalStatus.pid}`));
|
|
237
|
-
}
|
|
238
|
-
} else {
|
|
239
|
-
console.error(chalk.red('❌ Server failed to start with new configuration'));
|
|
240
|
-
console.log(chalk.dim(' Check logs: ') + `llamacpp server logs ${newServerId} --errors`);
|
|
241
|
-
process.exit(1);
|
|
242
|
-
}
|
|
243
|
-
} else {
|
|
244
|
-
console.log(chalk.green(`✅ Server migrated successfully to new ID: ${newServerId}`));
|
|
245
|
-
if (!wasRunning) {
|
|
246
|
-
console.log(chalk.dim('\n Start server: ') + `llamacpp server start ${newServerId}`);
|
|
247
|
-
} else {
|
|
248
|
-
console.log(chalk.dim('\n Start server: ') + `llamacpp server start ${newServerId}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return; // Exit early for migration path
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Normal config update (no model migration)
|
|
256
|
-
// Unload service if running and restart flag is set
|
|
257
|
-
if (wasRunning && options.restart) {
|
|
258
|
-
console.log(chalk.dim('Stopping server...'));
|
|
259
|
-
await launchctlManager.unloadService(server.plistPath);
|
|
260
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const updatedConfig = {
|
|
264
|
-
...server,
|
|
265
|
-
...(newModelPath !== undefined && { modelPath: newModelPath, modelName: newModelName }),
|
|
266
|
-
...(options.host !== undefined && { host: options.host }),
|
|
267
|
-
...(options.threads !== undefined && { threads: options.threads }),
|
|
268
|
-
...(options.ctxSize !== undefined && { ctxSize: options.ctxSize }),
|
|
269
|
-
...(options.gpuLayers !== undefined && { gpuLayers: options.gpuLayers }),
|
|
270
|
-
...(options.verbose !== undefined && { verbose: options.verbose }),
|
|
271
|
-
...(options.flags !== undefined && { customFlags }),
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
await stateManager.updateServerConfig(server.id, updatedConfig);
|
|
275
|
-
|
|
276
|
-
console.log(chalk.dim('Regenerating service configuration...'));
|
|
277
|
-
await launchctlManager.createPlist(updatedConfig);
|
|
278
|
-
|
|
279
|
-
// Restart server if it was running and restart flag is set
|
|
280
|
-
if (wasRunning && options.restart) {
|
|
281
|
-
// Auto-rotate logs if they exceed 100MB
|
|
282
|
-
try {
|
|
283
|
-
const result = await autoRotateIfNeeded(updatedConfig.stdoutPath, updatedConfig.stderrPath, 100);
|
|
284
|
-
if (result.rotated) {
|
|
285
|
-
console.log(chalk.dim('Auto-rotated large log files:'));
|
|
286
|
-
for (const file of result.files) {
|
|
287
|
-
console.log(chalk.dim(` → ${file}`));
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
} catch (error) {
|
|
291
|
-
// Non-fatal, just warn
|
|
292
|
-
console.log(chalk.yellow(`⚠️ Failed to rotate logs: ${(error as Error).message}`));
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
console.log(chalk.dim('Starting server with new configuration...'));
|
|
296
|
-
await launchctlManager.loadService(updatedConfig.plistPath);
|
|
297
|
-
await launchctlManager.startService(updatedConfig.label);
|
|
298
|
-
|
|
299
|
-
// Wait and verify
|
|
300
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
301
|
-
const finalStatus = await statusChecker.updateServerStatus(updatedConfig);
|
|
302
|
-
|
|
303
|
-
if (finalStatus.status === 'running') {
|
|
304
|
-
console.log(chalk.green(`✅ Server restarted successfully with new configuration`));
|
|
305
|
-
console.log(chalk.dim(` Port: http://localhost:${finalStatus.port}`));
|
|
306
|
-
if (finalStatus.pid) {
|
|
307
|
-
console.log(chalk.dim(` PID: ${finalStatus.pid}`));
|
|
308
|
-
}
|
|
309
|
-
} else {
|
|
310
|
-
console.error(chalk.red('❌ Server failed to start with new configuration'));
|
|
311
|
-
console.log(chalk.dim(' Check logs: ') + `llamacpp server logs ${server.id} --errors`);
|
|
312
|
-
process.exit(1);
|
|
313
|
-
}
|
|
314
|
-
} else {
|
|
315
|
-
console.log(chalk.green('✅ Configuration updated successfully'));
|
|
316
|
-
if (wasRunning && !options.restart) {
|
|
317
|
-
console.log(chalk.yellow('\n⚠️ Server is still running with old configuration'));
|
|
318
|
-
console.log(chalk.dim(' Restart to apply changes: ') + `llamacpp server stop ${server.id} && llamacpp server start ${server.id}`);
|
|
319
|
-
} else if (!wasRunning) {
|
|
320
|
-
console.log(chalk.dim('\n Start server: ') + `llamacpp server start ${server.id}`);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|