@appkit/llamacpp-cli 1.7.0 → 1.9.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/CHANGELOG.md +42 -0
- package/README.md +84 -0
- package/dist/cli.js +80 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/config.d.ts +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +167 -12
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/router/config.d.ts +10 -0
- package/dist/commands/router/config.d.ts.map +1 -0
- package/dist/commands/router/config.js +95 -0
- package/dist/commands/router/config.js.map +1 -0
- package/dist/commands/router/restart.d.ts +2 -0
- package/dist/commands/router/restart.d.ts.map +1 -0
- package/dist/commands/router/restart.js +39 -0
- package/dist/commands/router/restart.js.map +1 -0
- package/dist/commands/router/start.d.ts +2 -0
- package/dist/commands/router/start.d.ts.map +1 -0
- package/dist/commands/router/start.js +60 -0
- package/dist/commands/router/start.js.map +1 -0
- package/dist/commands/router/status.d.ts +2 -0
- package/dist/commands/router/status.d.ts.map +1 -0
- package/dist/commands/router/status.js +116 -0
- package/dist/commands/router/status.js.map +1 -0
- package/dist/commands/router/stop.d.ts +2 -0
- package/dist/commands/router/stop.d.ts.map +1 -0
- package/dist/commands/router/stop.js +36 -0
- package/dist/commands/router/stop.js.map +1 -0
- package/dist/lib/router-manager.d.ts +103 -0
- package/dist/lib/router-manager.d.ts.map +1 -0
- package/dist/lib/router-manager.js +393 -0
- package/dist/lib/router-manager.js.map +1 -0
- package/dist/lib/router-server.d.ts +52 -0
- package/dist/lib/router-server.d.ts.map +1 -0
- package/dist/lib/router-server.js +373 -0
- package/dist/lib/router-server.js.map +1 -0
- package/dist/types/router-config.d.ts +18 -0
- package/dist/types/router-config.d.ts.map +1 -0
- package/dist/types/router-config.js +3 -0
- package/dist/types/router-config.js.map +1 -0
- package/package.json +1 -1
- package/src/cli.ts +81 -0
- package/src/commands/config.ts +146 -14
- package/src/commands/router/config.ts +109 -0
- package/src/commands/router/restart.ts +36 -0
- package/src/commands/router/start.ts +60 -0
- package/src/commands/router/status.ts +119 -0
- package/src/commands/router/stop.ts +33 -0
- package/src/lib/router-manager.ts +413 -0
- package/src/lib/router-server.ts +407 -0
- package/src/types/router-config.ts +24 -0
package/src/commands/config.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as fs from 'fs/promises';
|
|
2
4
|
import { stateManager } from '../lib/state-manager';
|
|
3
5
|
import { statusChecker } from '../lib/status-checker';
|
|
4
6
|
import { launchctlManager } from '../lib/launchctl-manager';
|
|
5
7
|
import { configGenerator } from '../lib/config-generator';
|
|
6
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';
|
|
7
12
|
|
|
8
13
|
export interface ConfigUpdateOptions {
|
|
14
|
+
model?: string;
|
|
9
15
|
host?: string;
|
|
10
16
|
threads?: number;
|
|
11
17
|
ctxSize?: number;
|
|
@@ -38,7 +44,8 @@ export async function serverConfigCommand(
|
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
// Check if any config options were provided
|
|
41
|
-
const hasChanges = options.
|
|
47
|
+
const hasChanges = options.model !== undefined ||
|
|
48
|
+
options.host !== undefined ||
|
|
42
49
|
options.threads !== undefined ||
|
|
43
50
|
options.ctxSize !== undefined ||
|
|
44
51
|
options.gpuLayers !== undefined ||
|
|
@@ -48,6 +55,7 @@ export async function serverConfigCommand(
|
|
|
48
55
|
if (!hasChanges) {
|
|
49
56
|
console.error(chalk.red('❌ No configuration changes specified'));
|
|
50
57
|
console.log(chalk.dim('\nAvailable options:'));
|
|
58
|
+
console.log(chalk.dim(' --model <filename> Model filename or path'));
|
|
51
59
|
console.log(chalk.dim(' --host <address> Bind address (127.0.0.1 or 0.0.0.0)'));
|
|
52
60
|
console.log(chalk.dim(' --threads <n> Number of threads'));
|
|
53
61
|
console.log(chalk.dim(' --ctx-size <n> Context size'));
|
|
@@ -56,12 +64,50 @@ export async function serverConfigCommand(
|
|
|
56
64
|
console.log(chalk.dim(' --no-verbose Disable verbose logging'));
|
|
57
65
|
console.log(chalk.dim(' --flags <flags> Custom llama-server flags (comma-separated)'));
|
|
58
66
|
console.log(chalk.dim(' --restart Auto-restart if running'));
|
|
59
|
-
console.log(chalk.dim('\
|
|
67
|
+
console.log(chalk.dim('\nExamples:'));
|
|
68
|
+
console.log(chalk.dim(` llamacpp server config ${server.id} --model llama-3.2-1b.gguf --restart`));
|
|
60
69
|
console.log(chalk.dim(` llamacpp server config ${server.id} --ctx-size 8192 --restart`));
|
|
61
70
|
console.log(chalk.dim(` llamacpp server config ${server.id} --flags="--pooling,mean" --restart`));
|
|
62
71
|
process.exit(1);
|
|
63
72
|
}
|
|
64
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
|
+
|
|
65
111
|
// Check current status
|
|
66
112
|
const updatedServer = await statusChecker.updateServerStatus(server);
|
|
67
113
|
const wasRunning = updatedServer.status === 'running';
|
|
@@ -76,6 +122,15 @@ export async function serverConfigCommand(
|
|
|
76
122
|
console.log(chalk.bold('Configuration Changes:'));
|
|
77
123
|
console.log('─'.repeat(70));
|
|
78
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
|
+
}
|
|
79
134
|
if (options.host !== undefined) {
|
|
80
135
|
console.log(`${chalk.bold('Host:')} ${chalk.dim(server.host)} → ${chalk.green(options.host)}`);
|
|
81
136
|
|
|
@@ -107,29 +162,107 @@ export async function serverConfigCommand(
|
|
|
107
162
|
}
|
|
108
163
|
console.log('');
|
|
109
164
|
|
|
110
|
-
// Unload service if running and restart flag is set (forces plist re-read)
|
|
111
|
-
if (wasRunning && options.restart) {
|
|
112
|
-
console.log(chalk.dim('Stopping server...'));
|
|
113
|
-
await launchctlManager.unloadService(server.plistPath);
|
|
114
|
-
|
|
115
|
-
// Wait a moment for clean shutdown
|
|
116
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
165
|
// Parse custom flags if provided
|
|
120
166
|
let customFlags: string[] | undefined;
|
|
121
167
|
if (options.flags !== undefined) {
|
|
122
168
|
if (options.flags === '') {
|
|
123
|
-
// Empty string means clear flags
|
|
124
169
|
customFlags = undefined;
|
|
125
170
|
} else {
|
|
126
171
|
customFlags = options.flags.split(',').map(f => f.trim()).filter(f => f.length > 0);
|
|
127
172
|
}
|
|
128
173
|
}
|
|
129
174
|
|
|
130
|
-
//
|
|
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
|
+
|
|
131
263
|
const updatedConfig = {
|
|
132
264
|
...server,
|
|
265
|
+
...(newModelPath !== undefined && { modelPath: newModelPath, modelName: newModelName }),
|
|
133
266
|
...(options.host !== undefined && { host: options.host }),
|
|
134
267
|
...(options.threads !== undefined && { threads: options.threads }),
|
|
135
268
|
...(options.ctxSize !== undefined && { ctxSize: options.ctxSize }),
|
|
@@ -140,7 +273,6 @@ export async function serverConfigCommand(
|
|
|
140
273
|
|
|
141
274
|
await stateManager.updateServerConfig(server.id, updatedConfig);
|
|
142
275
|
|
|
143
|
-
// Regenerate plist with new configuration
|
|
144
276
|
console.log(chalk.dim('Regenerating service configuration...'));
|
|
145
277
|
await launchctlManager.createPlist(updatedConfig);
|
|
146
278
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { routerManager } from '../../lib/router-manager';
|
|
3
|
+
|
|
4
|
+
interface ConfigOptions {
|
|
5
|
+
port?: number;
|
|
6
|
+
host?: string;
|
|
7
|
+
timeout?: number;
|
|
8
|
+
healthInterval?: number;
|
|
9
|
+
restart?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function routerConfigCommand(options: ConfigOptions): Promise<void> {
|
|
13
|
+
try {
|
|
14
|
+
// Check if router exists
|
|
15
|
+
const config = await routerManager.loadConfig();
|
|
16
|
+
if (!config) {
|
|
17
|
+
throw new Error('Router configuration not found. Use "llamacpp router start" to create it.');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Check if any options were provided
|
|
21
|
+
const hasOptions = options.port || options.host || options.timeout || options.healthInterval;
|
|
22
|
+
if (!hasOptions) {
|
|
23
|
+
throw new Error('No configuration options provided. Use --port, --host, --timeout, or --health-interval');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isRunning = config.status === 'running';
|
|
27
|
+
|
|
28
|
+
// Warn if running and no restart flag
|
|
29
|
+
if (isRunning && !options.restart) {
|
|
30
|
+
console.log(chalk.yellow('⚠️ Router is running. Changes will take effect after restart.'));
|
|
31
|
+
console.log(chalk.dim(' Use --restart flag to apply changes immediately.\n'));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Prepare updates
|
|
35
|
+
const updates: any = {};
|
|
36
|
+
const changes: string[] = [];
|
|
37
|
+
|
|
38
|
+
if (options.port !== undefined) {
|
|
39
|
+
changes.push(`Port: ${config.port} → ${options.port}`);
|
|
40
|
+
updates.port = options.port;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (options.host !== undefined) {
|
|
44
|
+
changes.push(`Host: ${config.host} → ${options.host}`);
|
|
45
|
+
updates.host = options.host;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (options.timeout !== undefined) {
|
|
49
|
+
changes.push(`Request Timeout: ${config.requestTimeout}ms → ${options.timeout}ms`);
|
|
50
|
+
updates.requestTimeout = options.timeout;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (options.healthInterval !== undefined) {
|
|
54
|
+
changes.push(`Health Check Interval: ${config.healthCheckInterval}ms → ${options.healthInterval}ms`);
|
|
55
|
+
updates.healthCheckInterval = options.healthInterval;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Display changes
|
|
59
|
+
console.log(chalk.blue('📝 Configuration changes:'));
|
|
60
|
+
console.log();
|
|
61
|
+
changes.forEach(change => {
|
|
62
|
+
console.log(chalk.dim(` ${change}`));
|
|
63
|
+
});
|
|
64
|
+
console.log();
|
|
65
|
+
|
|
66
|
+
// Apply changes
|
|
67
|
+
if (isRunning && options.restart) {
|
|
68
|
+
console.log(chalk.blue('⏹️ Stopping router...'));
|
|
69
|
+
await routerManager.stop();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Update config
|
|
73
|
+
await routerManager.updateConfig(updates);
|
|
74
|
+
|
|
75
|
+
// Regenerate plist if port or host changed
|
|
76
|
+
if (options.port !== undefined || options.host !== undefined) {
|
|
77
|
+
const updatedConfig = await routerManager.loadConfig();
|
|
78
|
+
if (updatedConfig) {
|
|
79
|
+
await routerManager.createPlist(updatedConfig);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Restart if requested
|
|
84
|
+
if (isRunning && options.restart) {
|
|
85
|
+
console.log(chalk.blue('▶️ Starting router...'));
|
|
86
|
+
await routerManager.start();
|
|
87
|
+
|
|
88
|
+
const finalConfig = await routerManager.loadConfig();
|
|
89
|
+
console.log();
|
|
90
|
+
console.log(chalk.green('✅ Router restarted with new configuration'));
|
|
91
|
+
console.log();
|
|
92
|
+
console.log(chalk.dim(`Endpoint: http://${finalConfig?.host}:${finalConfig?.port}`));
|
|
93
|
+
} else {
|
|
94
|
+
console.log(chalk.green('✅ Configuration updated'));
|
|
95
|
+
|
|
96
|
+
if (isRunning) {
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(chalk.yellow('⚠️ Restart required to apply changes:'));
|
|
99
|
+
console.log(chalk.dim(' llamacpp router restart'));
|
|
100
|
+
} else {
|
|
101
|
+
console.log();
|
|
102
|
+
console.log(chalk.dim('Start router to use new configuration:'));
|
|
103
|
+
console.log(chalk.dim(' llamacpp router start'));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
throw new Error(`Failed to update router configuration: ${(error as Error).message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { routerManager } from '../../lib/router-manager';
|
|
3
|
+
|
|
4
|
+
export async function routerRestartCommand(): Promise<void> {
|
|
5
|
+
console.log(chalk.blue('🔄 Restarting router...'));
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
// Check if router exists
|
|
9
|
+
const config = await routerManager.loadConfig();
|
|
10
|
+
if (!config) {
|
|
11
|
+
throw new Error('Router configuration not found. Use "llamacpp router start" to create it.');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Restart router
|
|
15
|
+
await routerManager.restart();
|
|
16
|
+
|
|
17
|
+
// Get updated config
|
|
18
|
+
const updatedConfig = await routerManager.loadConfig();
|
|
19
|
+
if (!updatedConfig) {
|
|
20
|
+
throw new Error('Failed to load router configuration after restart');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Display success
|
|
24
|
+
console.log();
|
|
25
|
+
console.log(chalk.green('✅ Router restarted successfully!'));
|
|
26
|
+
console.log();
|
|
27
|
+
console.log(chalk.dim(`Endpoint: http://${updatedConfig.host}:${updatedConfig.port}`));
|
|
28
|
+
console.log();
|
|
29
|
+
console.log(chalk.dim('Quick commands:'));
|
|
30
|
+
console.log(chalk.dim(' Status: llamacpp router status'));
|
|
31
|
+
console.log(chalk.dim(' Stop: llamacpp router stop'));
|
|
32
|
+
console.log(chalk.dim(` Logs: tail -f ${updatedConfig.stderrPath}`));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Failed to restart router: ${(error as Error).message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { routerManager } from '../../lib/router-manager';
|
|
3
|
+
import { stateManager } from '../../lib/state-manager';
|
|
4
|
+
|
|
5
|
+
export async function routerStartCommand(): Promise<void> {
|
|
6
|
+
console.log(chalk.blue('▶️ Starting router...'));
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
// Initialize
|
|
10
|
+
await routerManager.initialize();
|
|
11
|
+
await stateManager.initialize();
|
|
12
|
+
|
|
13
|
+
// Check if router already exists
|
|
14
|
+
const existingConfig = await routerManager.loadConfig();
|
|
15
|
+
if (existingConfig && existingConfig.status === 'running') {
|
|
16
|
+
console.log(chalk.yellow(`⚠️ Router is already running on port ${existingConfig.port}`));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Start router
|
|
21
|
+
await routerManager.start();
|
|
22
|
+
|
|
23
|
+
// Get updated config
|
|
24
|
+
const config = await routerManager.loadConfig();
|
|
25
|
+
if (!config) {
|
|
26
|
+
throw new Error('Failed to load router configuration after start');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Get running servers to show available models
|
|
30
|
+
const servers = await stateManager.getAllServers();
|
|
31
|
+
const runningServers = servers.filter(s => s.status === 'running');
|
|
32
|
+
|
|
33
|
+
// Display success
|
|
34
|
+
console.log();
|
|
35
|
+
console.log(chalk.green('✅ Router started successfully!'));
|
|
36
|
+
console.log();
|
|
37
|
+
console.log(chalk.dim(`Endpoint: http://${config.host}:${config.port}`));
|
|
38
|
+
console.log(chalk.dim(`Available models: ${runningServers.length}`));
|
|
39
|
+
|
|
40
|
+
if (runningServers.length > 0) {
|
|
41
|
+
console.log();
|
|
42
|
+
console.log(chalk.dim('Models:'));
|
|
43
|
+
runningServers.forEach(server => {
|
|
44
|
+
console.log(chalk.dim(` • ${server.modelName} (port ${server.port})`));
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
console.log();
|
|
48
|
+
console.log(chalk.yellow('⚠️ No running servers found. Start a server first:'));
|
|
49
|
+
console.log(chalk.dim(' llamacpp server create <model>'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(chalk.dim('Quick commands:'));
|
|
54
|
+
console.log(chalk.dim(` Status: llamacpp router status`));
|
|
55
|
+
console.log(chalk.dim(` Stop: llamacpp router stop`));
|
|
56
|
+
console.log(chalk.dim(` Logs: tail -f ${config.stderrPath}`));
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw new Error(`Failed to start router: ${(error as Error).message}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { routerManager } from '../../lib/router-manager';
|
|
3
|
+
import { stateManager } from '../../lib/state-manager';
|
|
4
|
+
|
|
5
|
+
export async function routerStatusCommand(): Promise<void> {
|
|
6
|
+
try {
|
|
7
|
+
// Get router status
|
|
8
|
+
const result = await routerManager.getStatus();
|
|
9
|
+
if (!result) {
|
|
10
|
+
console.log(chalk.yellow('Router not configured'));
|
|
11
|
+
console.log();
|
|
12
|
+
console.log(chalk.dim('Create and start router:'));
|
|
13
|
+
console.log(chalk.dim(' llamacpp router start'));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { config, status } = result;
|
|
18
|
+
|
|
19
|
+
// Calculate uptime if running
|
|
20
|
+
let uptime = 'N/A';
|
|
21
|
+
if (status.isRunning && config.lastStarted) {
|
|
22
|
+
const startTime = new Date(config.lastStarted).getTime();
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
const uptimeSeconds = Math.floor((now - startTime) / 1000);
|
|
25
|
+
const hours = Math.floor(uptimeSeconds / 3600);
|
|
26
|
+
const minutes = Math.floor((uptimeSeconds % 3600) / 60);
|
|
27
|
+
const seconds = uptimeSeconds % 60;
|
|
28
|
+
|
|
29
|
+
if (hours > 0) {
|
|
30
|
+
uptime = `${hours}h ${minutes}m`;
|
|
31
|
+
} else if (minutes > 0) {
|
|
32
|
+
uptime = `${minutes}m ${seconds}s`;
|
|
33
|
+
} else {
|
|
34
|
+
uptime = `${seconds}s`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Get running servers
|
|
39
|
+
const servers = await stateManager.getAllServers();
|
|
40
|
+
const runningServers = servers.filter(s => s.status === 'running');
|
|
41
|
+
|
|
42
|
+
// Display status
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(chalk.bold('Router Status'));
|
|
45
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
46
|
+
console.log();
|
|
47
|
+
|
|
48
|
+
// Status badge
|
|
49
|
+
const statusColor = status.isRunning ? chalk.green : chalk.gray;
|
|
50
|
+
const statusBadge = status.isRunning ? '● RUN' : '○ OFF';
|
|
51
|
+
console.log(`Status: ${statusColor(statusBadge)}`);
|
|
52
|
+
|
|
53
|
+
if (status.isRunning) {
|
|
54
|
+
console.log(`PID: ${status.pid || 'N/A'}`);
|
|
55
|
+
console.log(`Uptime: ${uptime}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log(`Port: ${config.port}`);
|
|
59
|
+
console.log(`Host: ${config.host}`);
|
|
60
|
+
console.log(`Endpoint: http://${config.host}:${config.port}`);
|
|
61
|
+
console.log();
|
|
62
|
+
|
|
63
|
+
// Available models
|
|
64
|
+
console.log(chalk.bold('Available Models'));
|
|
65
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
66
|
+
console.log();
|
|
67
|
+
|
|
68
|
+
if (runningServers.length === 0) {
|
|
69
|
+
console.log(chalk.dim('No running servers found'));
|
|
70
|
+
console.log();
|
|
71
|
+
console.log(chalk.yellow('⚠️ Start a server first:'));
|
|
72
|
+
console.log(chalk.dim(' llamacpp server create <model>'));
|
|
73
|
+
} else {
|
|
74
|
+
runningServers.forEach(server => {
|
|
75
|
+
console.log(` ${chalk.green('●')} ${server.modelName}`);
|
|
76
|
+
console.log(chalk.dim(` Port: ${server.port}`));
|
|
77
|
+
console.log(chalk.dim(` Backend: http://${server.host}:${server.port}`));
|
|
78
|
+
console.log();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Configuration
|
|
83
|
+
console.log(chalk.bold('Configuration'));
|
|
84
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
85
|
+
console.log();
|
|
86
|
+
console.log(`Health Check Interval: ${config.healthCheckInterval}ms`);
|
|
87
|
+
console.log(`Request Timeout: ${config.requestTimeout}ms`);
|
|
88
|
+
console.log();
|
|
89
|
+
|
|
90
|
+
// System paths
|
|
91
|
+
console.log(chalk.bold('System Paths'));
|
|
92
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
93
|
+
console.log();
|
|
94
|
+
console.log(chalk.dim(`Config: ${config.plistPath.replace(config.label + '.plist', 'router.json').replace('LaunchAgents', '.llamacpp')}`));
|
|
95
|
+
console.log(chalk.dim(`Plist: ${config.plistPath}`));
|
|
96
|
+
console.log(chalk.dim(`Stdout: ${config.stdoutPath}`));
|
|
97
|
+
console.log(chalk.dim(`Stderr: ${config.stderrPath}`));
|
|
98
|
+
console.log();
|
|
99
|
+
|
|
100
|
+
// Quick commands
|
|
101
|
+
console.log(chalk.bold('Quick Commands'));
|
|
102
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
103
|
+
console.log();
|
|
104
|
+
|
|
105
|
+
if (status.isRunning) {
|
|
106
|
+
console.log(chalk.dim(' Stop: llamacpp router stop'));
|
|
107
|
+
console.log(chalk.dim(' Restart: llamacpp router restart'));
|
|
108
|
+
console.log(chalk.dim(` Logs: tail -f ${config.stderrPath}`));
|
|
109
|
+
console.log(chalk.dim(' Config: llamacpp router config --port <port> --restart'));
|
|
110
|
+
} else {
|
|
111
|
+
console.log(chalk.dim(' Start: llamacpp router start'));
|
|
112
|
+
console.log(chalk.dim(' Config: llamacpp router config --port <port>'));
|
|
113
|
+
console.log(chalk.dim(` Logs: cat ${config.stderrPath}`));
|
|
114
|
+
}
|
|
115
|
+
console.log();
|
|
116
|
+
} catch (error) {
|
|
117
|
+
throw new Error(`Failed to get router status: ${(error as Error).message}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { routerManager } from '../../lib/router-manager';
|
|
3
|
+
|
|
4
|
+
export async function routerStopCommand(): Promise<void> {
|
|
5
|
+
console.log(chalk.blue('⏹️ Stopping router...'));
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
// Check if router exists
|
|
9
|
+
const config = await routerManager.loadConfig();
|
|
10
|
+
if (!config) {
|
|
11
|
+
throw new Error('Router configuration not found. Use "llamacpp router start" to create it.');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Check if already stopped
|
|
15
|
+
if (config.status !== 'running') {
|
|
16
|
+
console.log(chalk.yellow('⚠️ Router is not running'));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Stop router
|
|
21
|
+
await routerManager.stop();
|
|
22
|
+
|
|
23
|
+
// Display success
|
|
24
|
+
console.log();
|
|
25
|
+
console.log(chalk.green('✅ Router stopped successfully'));
|
|
26
|
+
console.log();
|
|
27
|
+
console.log(chalk.dim('Quick commands:'));
|
|
28
|
+
console.log(chalk.dim(' Start: llamacpp router start'));
|
|
29
|
+
console.log(chalk.dim(' Status: llamacpp router status'));
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new Error(`Failed to stop router: ${(error as Error).message}`);
|
|
32
|
+
}
|
|
33
|
+
}
|