@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.
Files changed (126) hide show
  1. package/README.md +572 -170
  2. package/dist/cli.js +99 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/admin/config.d.ts +10 -0
  5. package/dist/commands/admin/config.d.ts.map +1 -0
  6. package/dist/commands/admin/config.js +100 -0
  7. package/dist/commands/admin/config.js.map +1 -0
  8. package/dist/commands/admin/logs.d.ts +10 -0
  9. package/dist/commands/admin/logs.d.ts.map +1 -0
  10. package/dist/commands/admin/logs.js +114 -0
  11. package/dist/commands/admin/logs.js.map +1 -0
  12. package/dist/commands/admin/restart.d.ts +2 -0
  13. package/dist/commands/admin/restart.d.ts.map +1 -0
  14. package/dist/commands/admin/restart.js +29 -0
  15. package/dist/commands/admin/restart.js.map +1 -0
  16. package/dist/commands/admin/start.d.ts +2 -0
  17. package/dist/commands/admin/start.d.ts.map +1 -0
  18. package/dist/commands/admin/start.js +30 -0
  19. package/dist/commands/admin/start.js.map +1 -0
  20. package/dist/commands/admin/status.d.ts +2 -0
  21. package/dist/commands/admin/status.d.ts.map +1 -0
  22. package/dist/commands/admin/status.js +82 -0
  23. package/dist/commands/admin/status.js.map +1 -0
  24. package/dist/commands/admin/stop.d.ts +2 -0
  25. package/dist/commands/admin/stop.d.ts.map +1 -0
  26. package/dist/commands/admin/stop.js +21 -0
  27. package/dist/commands/admin/stop.js.map +1 -0
  28. package/dist/commands/logs.d.ts +1 -0
  29. package/dist/commands/logs.d.ts.map +1 -1
  30. package/dist/commands/logs.js +22 -0
  31. package/dist/commands/logs.js.map +1 -1
  32. package/dist/lib/admin-manager.d.ts +111 -0
  33. package/dist/lib/admin-manager.d.ts.map +1 -0
  34. package/dist/lib/admin-manager.js +413 -0
  35. package/dist/lib/admin-manager.js.map +1 -0
  36. package/dist/lib/admin-server.d.ts +148 -0
  37. package/dist/lib/admin-server.d.ts.map +1 -0
  38. package/dist/lib/admin-server.js +1161 -0
  39. package/dist/lib/admin-server.js.map +1 -0
  40. package/dist/lib/download-job-manager.d.ts +64 -0
  41. package/dist/lib/download-job-manager.d.ts.map +1 -0
  42. package/dist/lib/download-job-manager.js +164 -0
  43. package/dist/lib/download-job-manager.js.map +1 -0
  44. package/dist/tui/MultiServerMonitorApp.js +1 -1
  45. package/dist/types/admin-config.d.ts +19 -0
  46. package/dist/types/admin-config.d.ts.map +1 -0
  47. package/dist/types/admin-config.js +3 -0
  48. package/dist/types/admin-config.js.map +1 -0
  49. package/dist/utils/log-parser.d.ts +9 -0
  50. package/dist/utils/log-parser.d.ts.map +1 -1
  51. package/dist/utils/log-parser.js +11 -0
  52. package/dist/utils/log-parser.js.map +1 -1
  53. package/package.json +10 -2
  54. package/web/README.md +429 -0
  55. package/web/dist/assets/index-Bin89Lwr.css +1 -0
  56. package/web/dist/assets/index-CVmonw3T.js +17 -0
  57. package/web/dist/index.html +14 -0
  58. package/web/dist/vite.svg +1 -0
  59. package/.versionrc.json +0 -16
  60. package/CHANGELOG.md +0 -203
  61. package/MONITORING-ACCURACY-FIX.md +0 -199
  62. package/PER-PROCESS-METRICS.md +0 -190
  63. package/docs/images/.gitkeep +0 -1
  64. package/src/cli.ts +0 -423
  65. package/src/commands/config-global.ts +0 -38
  66. package/src/commands/config.ts +0 -323
  67. package/src/commands/create.ts +0 -183
  68. package/src/commands/delete.ts +0 -74
  69. package/src/commands/list.ts +0 -37
  70. package/src/commands/logs-all.ts +0 -251
  71. package/src/commands/logs.ts +0 -321
  72. package/src/commands/monitor.ts +0 -110
  73. package/src/commands/ps.ts +0 -84
  74. package/src/commands/pull.ts +0 -44
  75. package/src/commands/rm.ts +0 -107
  76. package/src/commands/router/config.ts +0 -116
  77. package/src/commands/router/logs.ts +0 -256
  78. package/src/commands/router/restart.ts +0 -36
  79. package/src/commands/router/start.ts +0 -60
  80. package/src/commands/router/status.ts +0 -119
  81. package/src/commands/router/stop.ts +0 -33
  82. package/src/commands/run.ts +0 -233
  83. package/src/commands/search.ts +0 -107
  84. package/src/commands/server-show.ts +0 -161
  85. package/src/commands/show.ts +0 -207
  86. package/src/commands/start.ts +0 -101
  87. package/src/commands/stop.ts +0 -39
  88. package/src/commands/tui.ts +0 -25
  89. package/src/lib/config-generator.ts +0 -130
  90. package/src/lib/history-manager.ts +0 -172
  91. package/src/lib/launchctl-manager.ts +0 -225
  92. package/src/lib/metrics-aggregator.ts +0 -257
  93. package/src/lib/model-downloader.ts +0 -328
  94. package/src/lib/model-scanner.ts +0 -157
  95. package/src/lib/model-search.ts +0 -114
  96. package/src/lib/models-dir-setup.ts +0 -46
  97. package/src/lib/port-manager.ts +0 -80
  98. package/src/lib/router-logger.ts +0 -201
  99. package/src/lib/router-manager.ts +0 -414
  100. package/src/lib/router-server.ts +0 -538
  101. package/src/lib/state-manager.ts +0 -206
  102. package/src/lib/status-checker.ts +0 -113
  103. package/src/lib/system-collector.ts +0 -315
  104. package/src/tui/ConfigApp.ts +0 -1085
  105. package/src/tui/HistoricalMonitorApp.ts +0 -587
  106. package/src/tui/ModelsApp.ts +0 -368
  107. package/src/tui/MonitorApp.ts +0 -386
  108. package/src/tui/MultiServerMonitorApp.ts +0 -1833
  109. package/src/tui/RootNavigator.ts +0 -74
  110. package/src/tui/SearchApp.ts +0 -511
  111. package/src/tui/SplashScreen.ts +0 -149
  112. package/src/types/global-config.ts +0 -26
  113. package/src/types/history-types.ts +0 -39
  114. package/src/types/model-info.ts +0 -8
  115. package/src/types/monitor-types.ts +0 -162
  116. package/src/types/router-config.ts +0 -25
  117. package/src/types/server-config.ts +0 -46
  118. package/src/utils/downsample-utils.ts +0 -128
  119. package/src/utils/file-utils.ts +0 -146
  120. package/src/utils/format-utils.ts +0 -98
  121. package/src/utils/log-parser.ts +0 -271
  122. package/src/utils/log-utils.ts +0 -178
  123. package/src/utils/process-utils.ts +0 -316
  124. package/src/utils/prompt-utils.ts +0 -47
  125. package/test-load.sh +0 -100
  126. package/tsconfig.json +0 -20
@@ -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
- }
@@ -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
- }
@@ -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
- }