@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.
Files changed (136) hide show
  1. package/README.md +294 -168
  2. package/dist/cli.js +35 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/launch/claude.d.ts +6 -0
  5. package/dist/commands/launch/claude.d.ts.map +1 -0
  6. package/dist/commands/launch/claude.js +277 -0
  7. package/dist/commands/launch/claude.js.map +1 -0
  8. package/dist/lib/integration-checker.d.ts +26 -0
  9. package/dist/lib/integration-checker.d.ts.map +1 -0
  10. package/dist/lib/integration-checker.js +77 -0
  11. package/dist/lib/integration-checker.js.map +1 -0
  12. package/dist/lib/router-manager.d.ts +4 -0
  13. package/dist/lib/router-manager.d.ts.map +1 -1
  14. package/dist/lib/router-manager.js +10 -0
  15. package/dist/lib/router-manager.js.map +1 -1
  16. package/dist/lib/router-server.d.ts +13 -0
  17. package/dist/lib/router-server.d.ts.map +1 -1
  18. package/dist/lib/router-server.js +267 -7
  19. package/dist/lib/router-server.js.map +1 -1
  20. package/dist/types/integration-config.d.ts +28 -0
  21. package/dist/types/integration-config.d.ts.map +1 -0
  22. package/dist/types/integration-config.js +3 -0
  23. package/dist/types/integration-config.js.map +1 -0
  24. package/package.json +10 -2
  25. package/web/dist/assets/index-Bin89Lwr.css +1 -0
  26. package/web/dist/assets/index-CVmonw3T.js +17 -0
  27. package/web/{index.html → dist/index.html} +2 -1
  28. package/.versionrc.json +0 -16
  29. package/CHANGELOG.md +0 -213
  30. package/docs/images/.gitkeep +0 -1
  31. package/docs/images/web-ui-servers.png +0 -0
  32. package/src/cli.ts +0 -523
  33. package/src/commands/admin/config.ts +0 -121
  34. package/src/commands/admin/logs.ts +0 -91
  35. package/src/commands/admin/restart.ts +0 -26
  36. package/src/commands/admin/start.ts +0 -27
  37. package/src/commands/admin/status.ts +0 -84
  38. package/src/commands/admin/stop.ts +0 -16
  39. package/src/commands/config-global.ts +0 -38
  40. package/src/commands/config.ts +0 -323
  41. package/src/commands/create.ts +0 -183
  42. package/src/commands/delete.ts +0 -74
  43. package/src/commands/list.ts +0 -37
  44. package/src/commands/logs-all.ts +0 -251
  45. package/src/commands/logs.ts +0 -345
  46. package/src/commands/monitor.ts +0 -110
  47. package/src/commands/ps.ts +0 -84
  48. package/src/commands/pull.ts +0 -44
  49. package/src/commands/rm.ts +0 -107
  50. package/src/commands/router/config.ts +0 -116
  51. package/src/commands/router/logs.ts +0 -256
  52. package/src/commands/router/restart.ts +0 -36
  53. package/src/commands/router/start.ts +0 -60
  54. package/src/commands/router/status.ts +0 -119
  55. package/src/commands/router/stop.ts +0 -33
  56. package/src/commands/run.ts +0 -233
  57. package/src/commands/search.ts +0 -107
  58. package/src/commands/server-show.ts +0 -161
  59. package/src/commands/show.ts +0 -207
  60. package/src/commands/start.ts +0 -101
  61. package/src/commands/stop.ts +0 -39
  62. package/src/commands/tui.ts +0 -25
  63. package/src/lib/admin-manager.ts +0 -435
  64. package/src/lib/admin-server.ts +0 -1243
  65. package/src/lib/config-generator.ts +0 -130
  66. package/src/lib/download-job-manager.ts +0 -213
  67. package/src/lib/history-manager.ts +0 -172
  68. package/src/lib/launchctl-manager.ts +0 -225
  69. package/src/lib/metrics-aggregator.ts +0 -257
  70. package/src/lib/model-downloader.ts +0 -328
  71. package/src/lib/model-scanner.ts +0 -157
  72. package/src/lib/model-search.ts +0 -114
  73. package/src/lib/models-dir-setup.ts +0 -46
  74. package/src/lib/port-manager.ts +0 -80
  75. package/src/lib/router-logger.ts +0 -201
  76. package/src/lib/router-manager.ts +0 -414
  77. package/src/lib/router-server.ts +0 -538
  78. package/src/lib/state-manager.ts +0 -206
  79. package/src/lib/status-checker.ts +0 -113
  80. package/src/lib/system-collector.ts +0 -315
  81. package/src/tui/ConfigApp.ts +0 -1085
  82. package/src/tui/HistoricalMonitorApp.ts +0 -587
  83. package/src/tui/ModelsApp.ts +0 -368
  84. package/src/tui/MonitorApp.ts +0 -386
  85. package/src/tui/MultiServerMonitorApp.ts +0 -1833
  86. package/src/tui/RootNavigator.ts +0 -74
  87. package/src/tui/SearchApp.ts +0 -511
  88. package/src/tui/SplashScreen.ts +0 -149
  89. package/src/types/admin-config.ts +0 -25
  90. package/src/types/global-config.ts +0 -26
  91. package/src/types/history-types.ts +0 -39
  92. package/src/types/model-info.ts +0 -8
  93. package/src/types/monitor-types.ts +0 -162
  94. package/src/types/router-config.ts +0 -25
  95. package/src/types/server-config.ts +0 -46
  96. package/src/utils/downsample-utils.ts +0 -128
  97. package/src/utils/file-utils.ts +0 -146
  98. package/src/utils/format-utils.ts +0 -98
  99. package/src/utils/log-parser.ts +0 -284
  100. package/src/utils/log-utils.ts +0 -178
  101. package/src/utils/process-utils.ts +0 -316
  102. package/src/utils/prompt-utils.ts +0 -47
  103. package/test-load.sh +0 -100
  104. package/tsconfig.json +0 -20
  105. package/web/eslint.config.js +0 -23
  106. package/web/llamacpp-web-dist.tar.gz +0 -0
  107. package/web/package-lock.json +0 -4017
  108. package/web/package.json +0 -38
  109. package/web/postcss.config.js +0 -6
  110. package/web/src/App.css +0 -42
  111. package/web/src/App.tsx +0 -86
  112. package/web/src/assets/react.svg +0 -1
  113. package/web/src/components/ApiKeyPrompt.tsx +0 -71
  114. package/web/src/components/CreateServerModal.tsx +0 -372
  115. package/web/src/components/DownloadProgress.tsx +0 -123
  116. package/web/src/components/Nav.tsx +0 -89
  117. package/web/src/components/RouterConfigModal.tsx +0 -240
  118. package/web/src/components/SearchModal.tsx +0 -306
  119. package/web/src/components/ServerConfigModal.tsx +0 -291
  120. package/web/src/hooks/useApi.ts +0 -259
  121. package/web/src/index.css +0 -42
  122. package/web/src/lib/api.ts +0 -226
  123. package/web/src/main.tsx +0 -10
  124. package/web/src/pages/Dashboard.tsx +0 -103
  125. package/web/src/pages/Models.tsx +0 -258
  126. package/web/src/pages/Router.tsx +0 -270
  127. package/web/src/pages/RouterLogs.tsx +0 -201
  128. package/web/src/pages/ServerLogs.tsx +0 -553
  129. package/web/src/pages/Servers.tsx +0 -358
  130. package/web/src/types/api.ts +0 -140
  131. package/web/tailwind.config.js +0 -31
  132. package/web/tsconfig.app.json +0 -28
  133. package/web/tsconfig.json +0 -7
  134. package/web/tsconfig.node.json +0 -26
  135. package/web/vite.config.ts +0 -25
  136. /package/web/{public → dist}/vite.svg +0 -0
@@ -1,183 +0,0 @@
1
- import chalk from 'chalk';
2
- import * as path from 'path';
3
- import * as fs from 'fs';
4
- import { modelScanner } from '../lib/model-scanner';
5
- import { stateManager } from '../lib/state-manager';
6
- import { configGenerator, ServerOptions } from '../lib/config-generator';
7
- import { portManager } from '../lib/port-manager';
8
- import { launchctlManager } from '../lib/launchctl-manager';
9
- import { statusChecker } from '../lib/status-checker';
10
- import { commandExists } from '../utils/process-utils';
11
- import { formatBytes } from '../utils/format-utils';
12
- import { ensureDir, parseMetalMemoryFromLog } from '../utils/file-utils';
13
- import { ensureModelsDirectory } from '../lib/models-dir-setup';
14
-
15
- interface CreateOptions {
16
- port?: number;
17
- host?: string;
18
- threads?: number;
19
- ctxSize?: number;
20
- gpuLayers?: number;
21
- verbose?: boolean;
22
- flags?: string;
23
- }
24
-
25
- export async function createCommand(model: string, options: CreateOptions): Promise<void> {
26
- // Initialize state manager
27
- await stateManager.initialize();
28
-
29
- // 1. Check if llama-server exists
30
- if (!(await commandExists('llama-server'))) {
31
- throw new Error('llama-server not found. Install with: brew install llama.cpp');
32
- }
33
-
34
- // 2. Ensure models directory exists if model is not an absolute path
35
- if (!path.isAbsolute(model)) {
36
- const modelsDir = await stateManager.getModelsDirectory();
37
- if (!fs.existsSync(modelsDir)) {
38
- await ensureModelsDirectory();
39
- }
40
- }
41
-
42
- // 3. Resolve model path
43
- const modelPath = await modelScanner.resolveModelPath(model);
44
- if (!modelPath) {
45
- throw new Error(`Model not found: ${model}\n\nRun: llamacpp ls`);
46
- }
47
-
48
- const modelName = path.basename(modelPath);
49
-
50
- // 4. Check if server already exists for this model
51
- const existingServer = await stateManager.serverExistsForModel(modelPath);
52
- if (existingServer) {
53
- throw new Error(`Server already exists for ${modelName}\n\nUse: llamacpp server start ${modelName}`);
54
- }
55
-
56
- // 5. Get model size
57
- const modelSize = await modelScanner.getModelSize(modelName);
58
- if (!modelSize) {
59
- throw new Error(`Failed to read model file: ${modelPath}`);
60
- }
61
-
62
- // 6. Determine port
63
- let port: number;
64
- if (options.port) {
65
- portManager.validatePort(options.port);
66
- const available = await portManager.isPortAvailable(options.port);
67
- if (!available) {
68
- throw new Error(`Port ${options.port} is already in use`);
69
- }
70
- port = options.port;
71
- } else {
72
- port = await portManager.findAvailablePort();
73
- }
74
-
75
- // 7. Generate server configuration
76
- console.log(chalk.blue(`🚀 Creating server for ${modelName}\n`));
77
-
78
- // Parse custom flags if provided
79
- let customFlags: string[] | undefined;
80
- if (options.flags) {
81
- customFlags = options.flags.split(',').map(f => f.trim()).filter(f => f.length > 0);
82
- }
83
-
84
- const serverOptions: ServerOptions = {
85
- port: options.port,
86
- host: options.host,
87
- threads: options.threads,
88
- ctxSize: options.ctxSize,
89
- gpuLayers: options.gpuLayers,
90
- verbose: options.verbose,
91
- customFlags,
92
- };
93
-
94
- const config = await configGenerator.generateConfig(
95
- modelPath,
96
- modelName,
97
- modelSize,
98
- port,
99
- serverOptions
100
- );
101
-
102
- // Security warning for 0.0.0.0
103
- if (config.host === '0.0.0.0') {
104
- console.log(chalk.yellow('⚠️ WARNING: Binding to 0.0.0.0 allows remote access from any network interface.'));
105
- console.log(chalk.yellow(' This exposes your server to your local network and potentially the internet.'));
106
- console.log(chalk.yellow(' Use 127.0.0.1 for localhost-only access (recommended for local development).\n'));
107
- }
108
-
109
- // Display configuration
110
- console.log(chalk.dim(`Model: ${modelPath}`));
111
- console.log(chalk.dim(`Size: ${formatBytes(modelSize)}`));
112
- console.log(chalk.dim(`Host: ${config.host}`));
113
- console.log(chalk.dim(`Port: ${config.port}${options.port ? '' : ' (auto-assigned)'}`));
114
- console.log(chalk.dim(`Threads: ${config.threads}`));
115
- console.log(chalk.dim(`Context Size: ${config.ctxSize}`));
116
- console.log(chalk.dim(`GPU Layers: ${config.gpuLayers}`));
117
- console.log(chalk.dim(`Verbose Logging: ${config.verbose ? 'enabled' : 'disabled'}`));
118
- if (config.customFlags && config.customFlags.length > 0) {
119
- console.log(chalk.dim(`Custom Flags: ${config.customFlags.join(' ')}`));
120
- }
121
- console.log();
122
-
123
- // 7. Ensure log directory exists
124
- await ensureDir(path.dirname(config.stdoutPath));
125
-
126
- // 8. Create plist file
127
- console.log(chalk.dim('Creating launchctl service...'));
128
- await launchctlManager.createPlist(config);
129
-
130
- // 9. Load service
131
- try {
132
- await launchctlManager.loadService(config.plistPath);
133
- } catch (error) {
134
- // Clean up plist if load fails
135
- await launchctlManager.deletePlist(config.plistPath);
136
- throw new Error(`Failed to load service: ${(error as Error).message}`);
137
- }
138
-
139
- // 10. Start service
140
- try {
141
- await launchctlManager.startService(config.label);
142
- } catch (error) {
143
- // Clean up if start fails
144
- await launchctlManager.unloadService(config.plistPath);
145
- await launchctlManager.deletePlist(config.plistPath);
146
- throw new Error(`Failed to start service: ${(error as Error).message}`);
147
- }
148
-
149
- // 11. Wait for startup
150
- console.log(chalk.dim('Waiting for server to start...'));
151
- const started = await launchctlManager.waitForServiceStart(config.label, 5000);
152
-
153
- if (!started) {
154
- // Clean up if startup fails
155
- await launchctlManager.unloadService(config.plistPath);
156
- await launchctlManager.deletePlist(config.plistPath);
157
- throw new Error('Server failed to start. Check logs with: llamacpp server logs --errors');
158
- }
159
-
160
- // 12. Update config with running status
161
- let updatedConfig = await statusChecker.updateServerStatus(config);
162
-
163
- // 13. Parse Metal (GPU) memory allocation from logs
164
- // Wait a few seconds for model to start loading (large models take time)
165
- console.log(chalk.dim('Detecting Metal (GPU) memory allocation...'));
166
- await new Promise(resolve => setTimeout(resolve, 8000)); // 8 second delay
167
- const metalMemoryMB = await parseMetalMemoryFromLog(updatedConfig.stderrPath);
168
- if (metalMemoryMB) {
169
- updatedConfig = { ...updatedConfig, metalMemoryMB };
170
- console.log(chalk.dim(`Metal memory: ${metalMemoryMB.toFixed(0)} MB`));
171
- }
172
-
173
- // 14. Save server config
174
- await stateManager.saveServerConfig(updatedConfig);
175
-
176
- // 15. Display success message
177
- console.log();
178
- console.log(chalk.green('✅ Server created and started successfully!'));
179
- console.log();
180
- console.log(chalk.dim(`Connect: http://${config.host}:${config.port}`));
181
- console.log(chalk.dim(`View logs: llamacpp server logs ${config.id}`));
182
- console.log(chalk.dim(`Stop: llamacpp server stop ${config.id}`));
183
- }
@@ -1,74 +0,0 @@
1
- import chalk from 'chalk';
2
- import * as readline from 'readline';
3
- import { stateManager } from '../lib/state-manager';
4
- import { launchctlManager } from '../lib/launchctl-manager';
5
-
6
- export async function deleteCommand(identifier: string): Promise<void> {
7
- // Find server
8
- const server = await stateManager.findServer(identifier);
9
- if (!server) {
10
- throw new Error(`Server not found: ${identifier}\n\nUse: llamacpp ps`);
11
- }
12
-
13
- // Confirm deletion
14
- console.log(chalk.yellow(`⚠️ Delete server configuration for ${server.modelName}?`));
15
- console.log(chalk.dim(' This will remove the launchd service but keep the model file.'));
16
- console.log();
17
-
18
- const confirmed = await confirmDeletion();
19
- if (!confirmed) {
20
- console.log(chalk.dim('Cancelled'));
21
- return;
22
- }
23
-
24
- console.log();
25
- console.log(chalk.blue(`🗑️ Deleting server ${server.modelName}...`));
26
-
27
- // Unload service (stops and removes from launchd)
28
- if (server.status === 'running') {
29
- console.log(chalk.dim('Stopping and unloading service...'));
30
- } else {
31
- console.log(chalk.dim('Unloading service...'));
32
- }
33
- try {
34
- await launchctlManager.unloadService(server.plistPath);
35
- if (server.status === 'running') {
36
- await launchctlManager.waitForServiceStop(server.label, 5000);
37
- }
38
- } catch (error) {
39
- console.log(chalk.yellow('⚠️ Failed to unload service gracefully'));
40
- }
41
-
42
- // Delete plist
43
- console.log(chalk.dim('Deleting plist file...'));
44
- await launchctlManager.deletePlist(server.plistPath);
45
-
46
- // Delete server config
47
- console.log(chalk.dim('Deleting server configuration...'));
48
- await stateManager.deleteServerConfig(server.id);
49
-
50
- // Success
51
- console.log();
52
- console.log(chalk.green('✅ Server deleted'));
53
- console.log(chalk.dim(` Plist removed: ${server.plistPath}`));
54
- console.log(chalk.dim(` Config removed`));
55
- console.log();
56
- console.log(chalk.dim(` Model file preserved at: ${server.modelPath}`));
57
- }
58
-
59
- /**
60
- * Prompt user for confirmation
61
- */
62
- function confirmDeletion(): Promise<boolean> {
63
- return new Promise((resolve) => {
64
- const rl = readline.createInterface({
65
- input: process.stdin,
66
- output: process.stdout,
67
- });
68
-
69
- rl.question(chalk.yellow(" Type 'yes' to confirm: "), (answer) => {
70
- rl.close();
71
- resolve(answer.toLowerCase() === 'yes');
72
- });
73
- });
74
- }
@@ -1,37 +0,0 @@
1
- import chalk from 'chalk';
2
- import Table from 'cli-table3';
3
- import { modelScanner } from '../lib/model-scanner';
4
- import { formatBytes, formatDateShort } from '../utils/format-utils';
5
- import { stateManager } from '../lib/state-manager';
6
-
7
- export async function listCommand(): Promise<void> {
8
- const modelsDir = await stateManager.getModelsDirectory();
9
- console.log(chalk.blue(`📦 Available models in ${modelsDir}\n`));
10
-
11
- const models = await modelScanner.scanModels();
12
-
13
- if (models.length === 0) {
14
- console.log(chalk.yellow('No GGUF models found.'));
15
- console.log(chalk.dim(`\nDownload models with: llamacpp pull <repo> --file <filename>`));
16
- return;
17
- }
18
-
19
- const table = new Table({
20
- head: ['MODEL', 'SIZE', 'MODIFIED'],
21
- colWidths: [50, 12, 15],
22
- });
23
-
24
- for (const model of models) {
25
- table.push([
26
- model.filename,
27
- model.sizeFormatted,
28
- formatDateShort(model.modified),
29
- ]);
30
- }
31
-
32
- console.log(table.toString());
33
-
34
- const totalSize = models.reduce((sum, m) => sum + m.size, 0);
35
- console.log(chalk.dim(`\nTotal: ${models.length} models (${formatBytes(totalSize)})`));
36
- console.log(chalk.dim(`\nCreate a server: llamacpp server create <model-filename>`));
37
- }
@@ -1,251 +0,0 @@
1
- import chalk from 'chalk';
2
- import Table from 'cli-table3';
3
- import { stateManager } from '../lib/state-manager';
4
- import { fileExists } from '../utils/file-utils';
5
- import {
6
- getFileSize,
7
- formatFileSize,
8
- getArchivedLogInfo,
9
- clearLogFile,
10
- rotateLogFile,
11
- deleteArchivedLogs,
12
- } from '../utils/log-utils';
13
-
14
- interface LogsAllOptions {
15
- clear?: boolean;
16
- clearArchived?: boolean;
17
- clearAll?: boolean;
18
- rotate?: boolean;
19
- }
20
-
21
- export async function logsAllCommand(options: LogsAllOptions): Promise<void> {
22
- // Get all servers
23
- const servers = await stateManager.getAllServers();
24
-
25
- if (servers.length === 0) {
26
- console.log(chalk.yellow('⚠️ No servers found'));
27
- console.log(chalk.dim('\nCreate a server: llamacpp server create <model-filename>'));
28
- return;
29
- }
30
-
31
- // Handle batch operations
32
- if (options.clear || options.clearArchived || options.clearAll || options.rotate) {
33
- await handleBatchOperation(servers, options);
34
- return;
35
- }
36
-
37
- // Show table of log information
38
- await showLogsTable(servers);
39
- }
40
-
41
- async function showLogsTable(servers: any[]): Promise<void> {
42
- const table = new Table({
43
- head: [
44
- chalk.bold('Server ID'),
45
- chalk.bold('Current Stderr'),
46
- chalk.bold('Current Stdout'),
47
- chalk.bold('Archived'),
48
- chalk.bold('Total'),
49
- ],
50
- colWidths: [30, 18, 18, 18, 18],
51
- });
52
-
53
- let totalCurrent = 0;
54
- let totalArchived = 0;
55
-
56
- for (const server of servers) {
57
- // Get current log sizes
58
- const stderrSize = (await fileExists(server.stderrPath))
59
- ? await getFileSize(server.stderrPath)
60
- : 0;
61
- const stdoutSize = (await fileExists(server.stdoutPath))
62
- ? await getFileSize(server.stdoutPath)
63
- : 0;
64
-
65
- // Get archived info
66
- const archivedInfo = await getArchivedLogInfo(server.id);
67
-
68
- const currentTotal = stderrSize + stdoutSize;
69
- const total = currentTotal + archivedInfo.totalSize;
70
-
71
- totalCurrent += currentTotal;
72
- totalArchived += archivedInfo.totalSize;
73
-
74
- table.push([
75
- server.id,
76
- formatFileSize(stderrSize),
77
- formatFileSize(stdoutSize),
78
- archivedInfo.count > 0
79
- ? `${formatFileSize(archivedInfo.totalSize)} (${archivedInfo.count})`
80
- : formatFileSize(0),
81
- formatFileSize(total),
82
- ]);
83
- }
84
-
85
- console.log(chalk.bold('\nServer Logs Overview:'));
86
- console.log(table.toString());
87
-
88
- console.log(chalk.dim('\nTotals:'));
89
- console.log(chalk.dim(` Current logs: ${formatFileSize(totalCurrent)}`));
90
- console.log(chalk.dim(` Archived logs: ${formatFileSize(totalArchived)}`));
91
- console.log(chalk.dim(` Grand total: ${formatFileSize(totalCurrent + totalArchived)}`));
92
-
93
- console.log(chalk.dim('\nBatch operations:'));
94
- console.log(chalk.dim(' llamacpp logs --clear Clear all current logs'));
95
- console.log(chalk.dim(' llamacpp logs --clear-archived Delete only archived logs'));
96
- console.log(chalk.dim(' llamacpp logs --clear-all Clear current + delete archives'));
97
- console.log(chalk.dim(' llamacpp logs --rotate Rotate all logs with timestamps'));
98
- }
99
-
100
- async function handleBatchOperation(
101
- servers: any[],
102
- options: LogsAllOptions
103
- ): Promise<void> {
104
- if (options.clearArchived) {
105
- console.log(chalk.blue('🗑️ Deleting archived logs for all servers...'));
106
- console.log();
107
-
108
- let totalFreed = 0;
109
- let totalFiles = 0;
110
- let serversProcessed = 0;
111
-
112
- for (const server of servers) {
113
- const archivedInfo = await deleteArchivedLogs(server.id);
114
-
115
- if (archivedInfo.count > 0) {
116
- console.log(chalk.dim(` ${server.id}: ${formatFileSize(archivedInfo.totalSize)} (${archivedInfo.count} file${archivedInfo.count !== 1 ? 's' : ''})`));
117
- totalFreed += archivedInfo.totalSize;
118
- totalFiles += archivedInfo.count;
119
- serversProcessed++;
120
- }
121
- }
122
-
123
- console.log();
124
- if (serversProcessed === 0) {
125
- console.log(chalk.yellow('⚠️ No archived logs found'));
126
- console.log(chalk.dim(' Archived logs are created via --rotate or automatic rotation'));
127
- } else {
128
- console.log(chalk.green(`✅ Deleted archived logs for ${serversProcessed} server${serversProcessed !== 1 ? 's' : ''}`));
129
- console.log(chalk.dim(` Files deleted: ${totalFiles}`));
130
- console.log(chalk.dim(` Total freed: ${formatFileSize(totalFreed)}`));
131
- console.log(chalk.dim(` Current logs preserved`));
132
- }
133
- } else if (options.clearAll) {
134
- console.log(chalk.blue('🗑️ Clearing all logs (current + archived) for all servers...'));
135
- console.log();
136
-
137
- let totalFreed = 0;
138
- let serversProcessed = 0;
139
-
140
- for (const server of servers) {
141
- let serverTotal = 0;
142
-
143
- // Clear current stderr
144
- if (await fileExists(server.stderrPath)) {
145
- serverTotal += await getFileSize(server.stderrPath);
146
- await clearLogFile(server.stderrPath);
147
- }
148
-
149
- // Clear current stdout
150
- if (await fileExists(server.stdoutPath)) {
151
- serverTotal += await getFileSize(server.stdoutPath);
152
- await clearLogFile(server.stdoutPath);
153
- }
154
-
155
- // Delete archived logs
156
- const archivedInfo = await deleteArchivedLogs(server.id);
157
- serverTotal += archivedInfo.totalSize;
158
-
159
- if (serverTotal > 0) {
160
- console.log(chalk.dim(` ${server.id}: ${formatFileSize(serverTotal)}`));
161
- totalFreed += serverTotal;
162
- serversProcessed++;
163
- }
164
- }
165
-
166
- console.log();
167
- console.log(chalk.green(`✅ Cleared all logs for ${serversProcessed} server${serversProcessed !== 1 ? 's' : ''}`));
168
- console.log(chalk.dim(` Total freed: ${formatFileSize(totalFreed)}`));
169
- } else if (options.clear) {
170
- console.log(chalk.blue('🗑️ Clearing current logs for all servers...'));
171
- console.log();
172
-
173
- let totalFreed = 0;
174
- let serversProcessed = 0;
175
-
176
- for (const server of servers) {
177
- let serverTotal = 0;
178
-
179
- // Clear current stderr
180
- if (await fileExists(server.stderrPath)) {
181
- serverTotal += await getFileSize(server.stderrPath);
182
- await clearLogFile(server.stderrPath);
183
- }
184
-
185
- // Clear current stdout
186
- if (await fileExists(server.stdoutPath)) {
187
- serverTotal += await getFileSize(server.stdoutPath);
188
- await clearLogFile(server.stdoutPath);
189
- }
190
-
191
- if (serverTotal > 0) {
192
- console.log(chalk.dim(` ${server.id}: ${formatFileSize(serverTotal)}`));
193
- totalFreed += serverTotal;
194
- serversProcessed++;
195
- }
196
- }
197
-
198
- console.log();
199
- console.log(chalk.green(`✅ Cleared current logs for ${serversProcessed} server${serversProcessed !== 1 ? 's' : ''}`));
200
- console.log(chalk.dim(` Total freed: ${formatFileSize(totalFreed)}`));
201
- console.log(chalk.dim(` Archived logs preserved`));
202
- } else if (options.rotate) {
203
- console.log(chalk.blue('🔄 Rotating logs for all servers...'));
204
- console.log();
205
-
206
- let totalRotated = 0;
207
- let filesRotated = 0;
208
-
209
- for (const server of servers) {
210
- const rotatedFiles: string[] = [];
211
-
212
- // Rotate stderr if it has content
213
- if (await fileExists(server.stderrPath)) {
214
- const size = await getFileSize(server.stderrPath);
215
- if (size > 0) {
216
- try {
217
- const archivedPath = await rotateLogFile(server.stderrPath);
218
- rotatedFiles.push(archivedPath);
219
- totalRotated += size;
220
- filesRotated++;
221
- } catch {
222
- // Ignore empty files
223
- }
224
- }
225
- }
226
-
227
- // Rotate stdout if it has content
228
- if (await fileExists(server.stdoutPath)) {
229
- const size = await getFileSize(server.stdoutPath);
230
- if (size > 0) {
231
- try {
232
- const archivedPath = await rotateLogFile(server.stdoutPath);
233
- rotatedFiles.push(archivedPath);
234
- totalRotated += size;
235
- filesRotated++;
236
- } catch {
237
- // Ignore empty files
238
- }
239
- }
240
- }
241
-
242
- if (rotatedFiles.length > 0) {
243
- console.log(chalk.dim(` ${server.id}: ${rotatedFiles.length} file${rotatedFiles.length !== 1 ? 's' : ''}`));
244
- }
245
- }
246
-
247
- console.log();
248
- console.log(chalk.green(`✅ Rotated ${filesRotated} log file${filesRotated !== 1 ? 's' : ''}`));
249
- console.log(chalk.dim(` Total archived: ${formatFileSize(totalRotated)}`));
250
- }
251
- }