@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
package/src/commands/ps.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import Table from 'cli-table3';
|
|
3
|
-
import { stateManager } from '../lib/state-manager.js';
|
|
4
|
-
import { statusChecker } from '../lib/status-checker.js';
|
|
5
|
-
import { formatUptime, formatBytes } from '../utils/format-utils.js';
|
|
6
|
-
import { getProcessMemory } from '../utils/process-utils.js';
|
|
7
|
-
import { ServerConfig } from '../types/server-config.js';
|
|
8
|
-
|
|
9
|
-
const STATUS_CONFIG = {
|
|
10
|
-
running: { text: '✅ RUNNING', color: chalk.green },
|
|
11
|
-
crashed: { text: '❌ CRASHED', color: chalk.red },
|
|
12
|
-
stopped: { text: '⚠️ STOPPED', color: chalk.yellow },
|
|
13
|
-
} as const;
|
|
14
|
-
|
|
15
|
-
async function getServerMemory(server: ServerConfig): Promise<string> {
|
|
16
|
-
if (server.status !== 'running' || !server.pid) {
|
|
17
|
-
return '-';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const cpuMemoryBytes = await getProcessMemory(server.pid);
|
|
21
|
-
if (cpuMemoryBytes === null) {
|
|
22
|
-
return '-';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const metalMemoryBytes = server.metalMemoryMB ? server.metalMemoryMB * 1024 * 1024 : 0;
|
|
26
|
-
return formatBytes(cpuMemoryBytes + metalMemoryBytes);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function psCommand(): Promise<void> {
|
|
30
|
-
const servers = await stateManager.getAllServers();
|
|
31
|
-
|
|
32
|
-
if (servers.length === 0) {
|
|
33
|
-
console.log(chalk.yellow('No servers configured.'));
|
|
34
|
-
console.log(chalk.dim('\nCreate a server: llamacpp server create <model-filename>'));
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
console.log(chalk.dim('Checking server statuses...\n'));
|
|
39
|
-
const serversWithStatus = await statusChecker.updateAllServerStatuses();
|
|
40
|
-
|
|
41
|
-
const table = new Table({
|
|
42
|
-
head: ['SERVER ID', 'MODEL', 'PORT', 'STATUS', 'PID', 'MEMORY', 'UPTIME'],
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const counts = { running: 0, stopped: 0, crashed: 0 };
|
|
46
|
-
|
|
47
|
-
for (const server of serversWithStatus) {
|
|
48
|
-
const status = server.status || 'stopped';
|
|
49
|
-
const config = STATUS_CONFIG[status] || STATUS_CONFIG.stopped;
|
|
50
|
-
counts[status]++;
|
|
51
|
-
|
|
52
|
-
const uptime = server.status === 'running' && server.lastStarted
|
|
53
|
-
? formatUptime(server.lastStarted)
|
|
54
|
-
: '-';
|
|
55
|
-
|
|
56
|
-
const memoryText = await getServerMemory(server);
|
|
57
|
-
|
|
58
|
-
table.push([
|
|
59
|
-
server.id,
|
|
60
|
-
server.modelName,
|
|
61
|
-
server.port.toString(),
|
|
62
|
-
config.color(config.text),
|
|
63
|
-
server.pid?.toString() || '-',
|
|
64
|
-
memoryText,
|
|
65
|
-
uptime,
|
|
66
|
-
]);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
console.log(table.toString());
|
|
70
|
-
|
|
71
|
-
const summary = [
|
|
72
|
-
chalk.green(`${counts.running} running`),
|
|
73
|
-
chalk.yellow(`${counts.stopped} stopped`),
|
|
74
|
-
];
|
|
75
|
-
if (counts.crashed > 0) {
|
|
76
|
-
summary.push(chalk.red(`${counts.crashed} crashed`));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
console.log(chalk.dim(`\nTotal: ${servers.length} servers (${summary.join(', ')})`));
|
|
80
|
-
|
|
81
|
-
if (counts.crashed > 0) {
|
|
82
|
-
console.log(chalk.red('\n⚠️ Some servers have crashed. Check logs with: llamacpp server logs <id> --errors'));
|
|
83
|
-
}
|
|
84
|
-
}
|
package/src/commands/pull.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { modelDownloader } from '../lib/model-downloader';
|
|
3
|
-
import { ensureModelsDirectory } from '../lib/models-dir-setup';
|
|
4
|
-
|
|
5
|
-
interface PullOptions {
|
|
6
|
-
file?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export async function pullCommand(identifier: string, options: PullOptions): Promise<void> {
|
|
10
|
-
// Parse repository identifier
|
|
11
|
-
const parsed = modelDownloader.parseHFIdentifier(identifier);
|
|
12
|
-
|
|
13
|
-
// Determine filename - from --file flag or from identifier path
|
|
14
|
-
let filename = options.file || parsed.file;
|
|
15
|
-
|
|
16
|
-
if (!filename) {
|
|
17
|
-
throw new Error(
|
|
18
|
-
'Please specify a file to download:\n\n' +
|
|
19
|
-
'Option 1: llamacpp pull owner/repo/filename.gguf\n' +
|
|
20
|
-
'Option 2: llamacpp pull owner/repo --file filename.gguf'
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Ensure filename ends with .gguf
|
|
25
|
-
if (!filename.toLowerCase().endsWith('.gguf')) {
|
|
26
|
-
filename += '.gguf';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Ensure models directory exists (prompts user if needed)
|
|
30
|
-
const modelsDir = await ensureModelsDirectory();
|
|
31
|
-
|
|
32
|
-
// Download the model
|
|
33
|
-
try {
|
|
34
|
-
const modelPath = await modelDownloader.downloadModel(parsed.repo, filename, undefined, modelsDir);
|
|
35
|
-
|
|
36
|
-
console.log();
|
|
37
|
-
console.log(chalk.dim(`Create server: llamacpp server create ${filename}`));
|
|
38
|
-
} catch (error) {
|
|
39
|
-
if ((error as Error).message.includes('interrupted')) {
|
|
40
|
-
console.log(chalk.dim('\nDownload was interrupted. Run the same command again to retry.'));
|
|
41
|
-
}
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
}
|
package/src/commands/rm.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import * as readline from 'readline';
|
|
3
|
-
import * as fs from 'fs/promises';
|
|
4
|
-
import { modelScanner } from '../lib/model-scanner';
|
|
5
|
-
import { stateManager } from '../lib/state-manager';
|
|
6
|
-
import { launchctlManager } from '../lib/launchctl-manager';
|
|
7
|
-
|
|
8
|
-
export async function rmCommand(modelIdentifier: string): Promise<void> {
|
|
9
|
-
await stateManager.initialize();
|
|
10
|
-
|
|
11
|
-
// 1. Resolve model path
|
|
12
|
-
const modelPath = await modelScanner.resolveModelPath(modelIdentifier);
|
|
13
|
-
if (!modelPath) {
|
|
14
|
-
throw new Error(`Model not found: ${modelIdentifier}\n\nRun: llamacpp ls`);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// 2. Check if any servers are using this model
|
|
18
|
-
const allServers = await stateManager.getAllServers();
|
|
19
|
-
const serversUsingModel = allServers.filter((s) => s.modelPath === modelPath);
|
|
20
|
-
|
|
21
|
-
// 3. Confirm deletion
|
|
22
|
-
console.log(chalk.yellow(`⚠️ Delete model file: ${modelPath}`));
|
|
23
|
-
|
|
24
|
-
if (serversUsingModel.length > 0) {
|
|
25
|
-
console.log(chalk.yellow(`\n This model has ${serversUsingModel.length} server(s) configured:`));
|
|
26
|
-
for (const server of serversUsingModel) {
|
|
27
|
-
const statusColor = server.status === 'running' ? chalk.green : chalk.dim;
|
|
28
|
-
console.log(chalk.yellow(` - ${server.id} (${statusColor(server.status)})`));
|
|
29
|
-
}
|
|
30
|
-
console.log(chalk.yellow(`\n These servers will be removed before deleting the model.`));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
console.log();
|
|
34
|
-
|
|
35
|
-
const confirmed = await confirmDeletion();
|
|
36
|
-
if (!confirmed) {
|
|
37
|
-
console.log(chalk.dim('Cancelled'));
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
console.log();
|
|
42
|
-
|
|
43
|
-
// 4. Delete all servers using this model
|
|
44
|
-
if (serversUsingModel.length > 0) {
|
|
45
|
-
console.log(chalk.blue(`🗑️ Removing ${serversUsingModel.length} server(s)...\n`));
|
|
46
|
-
|
|
47
|
-
for (const server of serversUsingModel) {
|
|
48
|
-
console.log(chalk.dim(` Removing server: ${server.id}`));
|
|
49
|
-
|
|
50
|
-
// Unload service (stops and removes from launchd)
|
|
51
|
-
try {
|
|
52
|
-
await launchctlManager.unloadService(server.plistPath);
|
|
53
|
-
if (server.status === 'running') {
|
|
54
|
-
await launchctlManager.waitForServiceStop(server.label, 5000);
|
|
55
|
-
}
|
|
56
|
-
} catch (error) {
|
|
57
|
-
console.log(chalk.yellow(` ⚠️ Failed to unload service gracefully`));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Delete plist
|
|
61
|
-
await launchctlManager.deletePlist(server.plistPath);
|
|
62
|
-
|
|
63
|
-
// Delete server config
|
|
64
|
-
await stateManager.deleteServerConfig(server.id);
|
|
65
|
-
|
|
66
|
-
console.log(chalk.dim(` ✓ Server removed`));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
console.log();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 5. Delete model file
|
|
73
|
-
console.log(chalk.blue(`🗑️ Deleting model file...`));
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
await fs.unlink(modelPath);
|
|
77
|
-
} catch (error) {
|
|
78
|
-
throw new Error(`Failed to delete model file: ${(error as Error).message}`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Success
|
|
82
|
-
console.log();
|
|
83
|
-
console.log(chalk.green('✅ Model deleted successfully'));
|
|
84
|
-
|
|
85
|
-
if (serversUsingModel.length > 0) {
|
|
86
|
-
console.log(chalk.dim(` Removed ${serversUsingModel.length} server(s)`));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
console.log(chalk.dim(` Deleted: ${modelPath}`));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Prompt user for confirmation
|
|
94
|
-
*/
|
|
95
|
-
function confirmDeletion(): Promise<boolean> {
|
|
96
|
-
return new Promise((resolve) => {
|
|
97
|
-
const rl = readline.createInterface({
|
|
98
|
-
input: process.stdin,
|
|
99
|
-
output: process.stdout,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
rl.question(chalk.yellow(" Type 'yes' to confirm: "), (answer) => {
|
|
103
|
-
rl.close();
|
|
104
|
-
resolve(answer.toLowerCase() === 'yes');
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
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
|
-
verbose?: boolean;
|
|
10
|
-
restart?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export async function routerConfigCommand(options: ConfigOptions): Promise<void> {
|
|
14
|
-
try {
|
|
15
|
-
// Check if router exists
|
|
16
|
-
const config = await routerManager.loadConfig();
|
|
17
|
-
if (!config) {
|
|
18
|
-
throw new Error('Router configuration not found. Use "llamacpp router start" to create it.');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Check if any options were provided
|
|
22
|
-
const hasOptions = options.port || options.host || options.timeout || options.healthInterval || options.verbose !== undefined;
|
|
23
|
-
if (!hasOptions) {
|
|
24
|
-
throw new Error('No configuration options provided. Use --port, --host, --timeout, --health-interval, or --verbose');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const isRunning = config.status === 'running';
|
|
28
|
-
|
|
29
|
-
// Warn if running and no restart flag
|
|
30
|
-
if (isRunning && !options.restart) {
|
|
31
|
-
console.log(chalk.yellow('⚠️ Router is running. Changes will take effect after restart.'));
|
|
32
|
-
console.log(chalk.dim(' Use --restart flag to apply changes immediately.\n'));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Prepare updates
|
|
36
|
-
const updates: any = {};
|
|
37
|
-
const changes: string[] = [];
|
|
38
|
-
|
|
39
|
-
if (options.port !== undefined) {
|
|
40
|
-
changes.push(`Port: ${config.port} → ${options.port}`);
|
|
41
|
-
updates.port = options.port;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (options.host !== undefined) {
|
|
45
|
-
changes.push(`Host: ${config.host} → ${options.host}`);
|
|
46
|
-
updates.host = options.host;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (options.timeout !== undefined) {
|
|
50
|
-
changes.push(`Request Timeout: ${config.requestTimeout}ms → ${options.timeout}ms`);
|
|
51
|
-
updates.requestTimeout = options.timeout;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (options.healthInterval !== undefined) {
|
|
55
|
-
changes.push(`Health Check Interval: ${config.healthCheckInterval}ms → ${options.healthInterval}ms`);
|
|
56
|
-
updates.healthCheckInterval = options.healthInterval;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (options.verbose !== undefined) {
|
|
60
|
-
const verboseStr = (val: boolean) => val ? 'enabled' : 'disabled';
|
|
61
|
-
changes.push(`Verbose Logging: ${verboseStr(config.verbose)} → ${verboseStr(options.verbose)}`);
|
|
62
|
-
updates.verbose = options.verbose;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Display changes
|
|
66
|
-
console.log(chalk.blue('📝 Configuration changes:'));
|
|
67
|
-
console.log();
|
|
68
|
-
changes.forEach(change => {
|
|
69
|
-
console.log(chalk.dim(` ${change}`));
|
|
70
|
-
});
|
|
71
|
-
console.log();
|
|
72
|
-
|
|
73
|
-
// Apply changes
|
|
74
|
-
if (isRunning && options.restart) {
|
|
75
|
-
console.log(chalk.blue('⏹️ Stopping router...'));
|
|
76
|
-
await routerManager.stop();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Update config
|
|
80
|
-
await routerManager.updateConfig(updates);
|
|
81
|
-
|
|
82
|
-
// Regenerate plist if port or host changed
|
|
83
|
-
if (options.port !== undefined || options.host !== undefined) {
|
|
84
|
-
const updatedConfig = await routerManager.loadConfig();
|
|
85
|
-
if (updatedConfig) {
|
|
86
|
-
await routerManager.createPlist(updatedConfig);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Restart if requested
|
|
91
|
-
if (isRunning && options.restart) {
|
|
92
|
-
console.log(chalk.blue('▶️ Starting router...'));
|
|
93
|
-
await routerManager.start();
|
|
94
|
-
|
|
95
|
-
const finalConfig = await routerManager.loadConfig();
|
|
96
|
-
console.log();
|
|
97
|
-
console.log(chalk.green('✅ Router restarted with new configuration'));
|
|
98
|
-
console.log();
|
|
99
|
-
console.log(chalk.dim(`Endpoint: http://${finalConfig?.host}:${finalConfig?.port}`));
|
|
100
|
-
} else {
|
|
101
|
-
console.log(chalk.green('✅ Configuration updated'));
|
|
102
|
-
|
|
103
|
-
if (isRunning) {
|
|
104
|
-
console.log();
|
|
105
|
-
console.log(chalk.yellow('⚠️ Restart required to apply changes:'));
|
|
106
|
-
console.log(chalk.dim(' llamacpp router restart'));
|
|
107
|
-
} else {
|
|
108
|
-
console.log();
|
|
109
|
-
console.log(chalk.dim('Start router to use new configuration:'));
|
|
110
|
-
console.log(chalk.dim(' llamacpp router start'));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
} catch (error) {
|
|
114
|
-
throw new Error(`Failed to update router configuration: ${(error as Error).message}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { spawn } from 'child_process';
|
|
3
|
-
import * as readline from 'readline';
|
|
4
|
-
import * as fs from 'fs';
|
|
5
|
-
import { routerManager } from '../../lib/router-manager';
|
|
6
|
-
import { fileExists } from '../../utils/file-utils';
|
|
7
|
-
import {
|
|
8
|
-
getFileSize,
|
|
9
|
-
formatFileSize,
|
|
10
|
-
rotateLogFile,
|
|
11
|
-
clearLogFile,
|
|
12
|
-
} from '../../utils/log-utils';
|
|
13
|
-
|
|
14
|
-
interface RouterLogsOptions {
|
|
15
|
-
follow?: boolean;
|
|
16
|
-
lines?: number;
|
|
17
|
-
stderr?: boolean; // View system logs (stderr) instead of activity logs (stdout)
|
|
18
|
-
verbose?: boolean;
|
|
19
|
-
clear?: boolean;
|
|
20
|
-
rotate?: boolean;
|
|
21
|
-
clearAll?: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function routerLogsCommand(options: RouterLogsOptions): Promise<void> {
|
|
25
|
-
// Load router config
|
|
26
|
-
const config = await routerManager.loadConfig();
|
|
27
|
-
if (!config) {
|
|
28
|
-
throw new Error('Router configuration not found. Use "llamacpp router start" to create it.');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Determine log file (default to stdout for activity logs, stderr for system logs)
|
|
32
|
-
const logPath = options.stderr ? config.stderrPath : config.stdoutPath;
|
|
33
|
-
const logType = options.stderr ? 'system' : 'activity';
|
|
34
|
-
|
|
35
|
-
// Also check for verbose JSON log file if --verbose flag is used
|
|
36
|
-
const verboseLogPath = '/Users/dweaver/.llamacpp/logs/router.log';
|
|
37
|
-
const useVerboseLog = options.verbose && (await fileExists(verboseLogPath));
|
|
38
|
-
|
|
39
|
-
// Handle --clear-all option (clears both stderr and stdout)
|
|
40
|
-
if (options.clearAll) {
|
|
41
|
-
let totalFreed = 0;
|
|
42
|
-
|
|
43
|
-
// Clear stderr
|
|
44
|
-
if (await fileExists(config.stderrPath)) {
|
|
45
|
-
totalFreed += await getFileSize(config.stderrPath);
|
|
46
|
-
await clearLogFile(config.stderrPath);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Clear stdout
|
|
50
|
-
if (await fileExists(config.stdoutPath)) {
|
|
51
|
-
totalFreed += await getFileSize(config.stdoutPath);
|
|
52
|
-
await clearLogFile(config.stdoutPath);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Clear verbose log file
|
|
56
|
-
if (await fileExists(verboseLogPath)) {
|
|
57
|
-
totalFreed += await getFileSize(verboseLogPath);
|
|
58
|
-
await clearLogFile(verboseLogPath);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
console.log(chalk.green('✅ Cleared all router logs'));
|
|
62
|
-
console.log(chalk.dim(` Total freed: ${formatFileSize(totalFreed)}`));
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Handle --clear option
|
|
67
|
-
if (options.clear) {
|
|
68
|
-
const targetPath = useVerboseLog ? verboseLogPath : logPath;
|
|
69
|
-
|
|
70
|
-
if (!(await fileExists(targetPath))) {
|
|
71
|
-
console.log(chalk.yellow(`⚠️ No ${useVerboseLog ? 'verbose log' : logType} found for router`));
|
|
72
|
-
console.log(chalk.dim(` Log file does not exist: ${targetPath}`));
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const sizeBefore = await getFileSize(targetPath);
|
|
77
|
-
await clearLogFile(targetPath);
|
|
78
|
-
|
|
79
|
-
console.log(chalk.green(`✅ Cleared router ${useVerboseLog ? 'verbose log' : logType}`));
|
|
80
|
-
console.log(chalk.dim(` Freed: ${formatFileSize(sizeBefore)}`));
|
|
81
|
-
console.log(chalk.dim(` ${targetPath}`));
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Handle --rotate option
|
|
86
|
-
if (options.rotate) {
|
|
87
|
-
const targetPath = useVerboseLog ? verboseLogPath : logPath;
|
|
88
|
-
|
|
89
|
-
if (!(await fileExists(targetPath))) {
|
|
90
|
-
console.log(chalk.yellow(`⚠️ No ${useVerboseLog ? 'verbose log' : logType} found for router`));
|
|
91
|
-
console.log(chalk.dim(` Log file does not exist: ${targetPath}`));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const archivedPath = await rotateLogFile(targetPath);
|
|
97
|
-
const size = await getFileSize(archivedPath);
|
|
98
|
-
|
|
99
|
-
console.log(chalk.green(`✅ Rotated router ${useVerboseLog ? 'verbose log' : logType}`));
|
|
100
|
-
console.log(chalk.dim(` Archived: ${formatFileSize(size)}`));
|
|
101
|
-
console.log(chalk.dim(` → ${archivedPath}`));
|
|
102
|
-
} catch (error) {
|
|
103
|
-
throw new Error(`Failed to rotate log: ${(error as Error).message}`);
|
|
104
|
-
}
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Determine which log to display
|
|
109
|
-
const displayPath = useVerboseLog ? verboseLogPath : logPath;
|
|
110
|
-
const displayType = useVerboseLog ? 'verbose JSON log' : logType;
|
|
111
|
-
|
|
112
|
-
// Check if log file exists
|
|
113
|
-
if (!(await fileExists(displayPath))) {
|
|
114
|
-
console.log(chalk.yellow(`⚠️ No ${displayType} found for router`));
|
|
115
|
-
console.log(chalk.dim(` Log file does not exist: ${displayPath}`));
|
|
116
|
-
|
|
117
|
-
if (useVerboseLog) {
|
|
118
|
-
console.log();
|
|
119
|
-
console.log(chalk.dim(' Verbose logging is disabled. Enable with:'));
|
|
120
|
-
console.log(chalk.dim(' llamacpp router config --verbose true --restart'));
|
|
121
|
-
}
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
console.log(chalk.blue(`📋 Router logs (${displayType})`));
|
|
126
|
-
console.log(chalk.dim(` ${displayPath}`));
|
|
127
|
-
|
|
128
|
-
// Show log size information
|
|
129
|
-
const currentSize = await getFileSize(displayPath);
|
|
130
|
-
console.log(chalk.dim(` Size: ${formatFileSize(currentSize)}`));
|
|
131
|
-
|
|
132
|
-
if (!useVerboseLog && config.verbose) {
|
|
133
|
-
console.log(chalk.dim(` Verbose logging is enabled (use --verbose to view JSON log)`));
|
|
134
|
-
} else if (!useVerboseLog && !config.verbose) {
|
|
135
|
-
console.log(chalk.dim(` Verbose logging is disabled`));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
console.log();
|
|
139
|
-
|
|
140
|
-
if (options.follow) {
|
|
141
|
-
// Follow logs in real-time
|
|
142
|
-
if (useVerboseLog) {
|
|
143
|
-
// Pretty-print JSON logs
|
|
144
|
-
const tailProcess = spawn('tail', ['-f', displayPath]);
|
|
145
|
-
const rl = readline.createInterface({
|
|
146
|
-
input: tailProcess.stdout,
|
|
147
|
-
crlfDelay: Infinity,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
rl.on('line', (line) => {
|
|
151
|
-
try {
|
|
152
|
-
const entry = JSON.parse(line);
|
|
153
|
-
// Format timestamp
|
|
154
|
-
const timestamp = new Date(entry.timestamp).toLocaleTimeString();
|
|
155
|
-
// Color code status
|
|
156
|
-
const statusColor = entry.status === 'success' ? chalk.green : chalk.red;
|
|
157
|
-
|
|
158
|
-
console.log(
|
|
159
|
-
chalk.dim(`[${timestamp}]`),
|
|
160
|
-
statusColor(entry.statusCode),
|
|
161
|
-
entry.method,
|
|
162
|
-
entry.endpoint,
|
|
163
|
-
'→',
|
|
164
|
-
chalk.cyan(entry.model),
|
|
165
|
-
chalk.dim(`(${entry.backend || 'N/A'})`),
|
|
166
|
-
chalk.yellow(`${entry.durationMs}ms`)
|
|
167
|
-
);
|
|
168
|
-
if (entry.prompt) {
|
|
169
|
-
console.log(chalk.dim(` Prompt: "${entry.prompt}"`));
|
|
170
|
-
}
|
|
171
|
-
if (entry.error) {
|
|
172
|
-
console.log(chalk.red(` Error: ${entry.error}`));
|
|
173
|
-
}
|
|
174
|
-
} catch {
|
|
175
|
-
// Not JSON, just print raw line
|
|
176
|
-
console.log(line);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
tailProcess.on('close', () => {
|
|
181
|
-
process.exit(0);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Handle Ctrl+C gracefully
|
|
185
|
-
process.on('SIGINT', () => {
|
|
186
|
-
tailProcess.kill();
|
|
187
|
-
process.exit(0);
|
|
188
|
-
});
|
|
189
|
-
} else {
|
|
190
|
-
// Standard tail for stderr/stdout
|
|
191
|
-
const tailProcess = spawn('tail', ['-f', displayPath]);
|
|
192
|
-
tailProcess.stdout.pipe(process.stdout);
|
|
193
|
-
tailProcess.stderr.pipe(process.stderr);
|
|
194
|
-
|
|
195
|
-
tailProcess.on('close', () => {
|
|
196
|
-
process.exit(0);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Handle Ctrl+C gracefully
|
|
200
|
-
process.on('SIGINT', () => {
|
|
201
|
-
tailProcess.kill();
|
|
202
|
-
process.exit(0);
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
} else {
|
|
206
|
-
// Show last N lines (default 50)
|
|
207
|
-
const linesToShow = options.lines || 50;
|
|
208
|
-
|
|
209
|
-
if (useVerboseLog) {
|
|
210
|
-
// Pretty-print JSON logs
|
|
211
|
-
const lines = fs.readFileSync(displayPath, 'utf-8')
|
|
212
|
-
.split('\n')
|
|
213
|
-
.filter(line => line.trim())
|
|
214
|
-
.slice(-linesToShow);
|
|
215
|
-
|
|
216
|
-
for (const line of lines) {
|
|
217
|
-
try {
|
|
218
|
-
const entry = JSON.parse(line);
|
|
219
|
-
// Format timestamp
|
|
220
|
-
const timestamp = new Date(entry.timestamp).toLocaleTimeString();
|
|
221
|
-
// Color code status
|
|
222
|
-
const statusColor = entry.status === 'success' ? chalk.green : chalk.red;
|
|
223
|
-
|
|
224
|
-
console.log(
|
|
225
|
-
chalk.dim(`[${timestamp}]`),
|
|
226
|
-
statusColor(entry.statusCode),
|
|
227
|
-
entry.method,
|
|
228
|
-
entry.endpoint,
|
|
229
|
-
'→',
|
|
230
|
-
chalk.cyan(entry.model),
|
|
231
|
-
chalk.dim(`(${entry.backend || 'N/A'})`),
|
|
232
|
-
chalk.yellow(`${entry.durationMs}ms`)
|
|
233
|
-
);
|
|
234
|
-
if (entry.prompt) {
|
|
235
|
-
console.log(chalk.dim(` Prompt: "${entry.prompt}"`));
|
|
236
|
-
}
|
|
237
|
-
if (entry.error) {
|
|
238
|
-
console.log(chalk.red(` Error: ${entry.error}`));
|
|
239
|
-
}
|
|
240
|
-
} catch {
|
|
241
|
-
// Not JSON, just print raw line
|
|
242
|
-
console.log(line);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
} else {
|
|
246
|
-
// Standard tail for stderr/stdout
|
|
247
|
-
const { execSync } = require('child_process');
|
|
248
|
-
try {
|
|
249
|
-
const output = execSync(`tail -n ${linesToShow} "${displayPath}"`, { encoding: 'utf-8' });
|
|
250
|
-
process.stdout.write(output);
|
|
251
|
-
} catch (error) {
|
|
252
|
-
throw new Error(`Failed to read log file: ${(error as Error).message}`);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
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
|
-
}
|