@appkit/llamacpp-cli 1.5.0 → 1.7.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 (124) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/MONITORING-ACCURACY-FIX.md +199 -0
  3. package/PER-PROCESS-METRICS.md +190 -0
  4. package/README.md +124 -9
  5. package/dist/cli.js +32 -7
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/config.d.ts.map +1 -1
  8. package/dist/commands/config.js +15 -1
  9. package/dist/commands/config.js.map +1 -1
  10. package/dist/commands/create.d.ts.map +1 -1
  11. package/dist/commands/create.js +12 -4
  12. package/dist/commands/create.js.map +1 -1
  13. package/dist/commands/delete.js +12 -10
  14. package/dist/commands/delete.js.map +1 -1
  15. package/dist/commands/logs-all.d.ts +9 -0
  16. package/dist/commands/logs-all.d.ts.map +1 -0
  17. package/dist/commands/logs-all.js +209 -0
  18. package/dist/commands/logs-all.js.map +1 -0
  19. package/dist/commands/logs.d.ts +4 -0
  20. package/dist/commands/logs.d.ts.map +1 -1
  21. package/dist/commands/logs.js +108 -2
  22. package/dist/commands/logs.js.map +1 -1
  23. package/dist/commands/monitor.d.ts.map +1 -1
  24. package/dist/commands/monitor.js +51 -1
  25. package/dist/commands/monitor.js.map +1 -1
  26. package/dist/commands/ps.d.ts +3 -1
  27. package/dist/commands/ps.d.ts.map +1 -1
  28. package/dist/commands/ps.js +75 -5
  29. package/dist/commands/ps.js.map +1 -1
  30. package/dist/commands/rm.d.ts.map +1 -1
  31. package/dist/commands/rm.js +5 -12
  32. package/dist/commands/rm.js.map +1 -1
  33. package/dist/commands/server-show.d.ts.map +1 -1
  34. package/dist/commands/server-show.js +30 -3
  35. package/dist/commands/server-show.js.map +1 -1
  36. package/dist/commands/start.d.ts.map +1 -1
  37. package/dist/commands/start.js +34 -7
  38. package/dist/commands/start.js.map +1 -1
  39. package/dist/commands/stop.js +3 -3
  40. package/dist/commands/stop.js.map +1 -1
  41. package/dist/lib/history-manager.d.ts +46 -0
  42. package/dist/lib/history-manager.d.ts.map +1 -0
  43. package/dist/lib/history-manager.js +157 -0
  44. package/dist/lib/history-manager.js.map +1 -0
  45. package/dist/lib/metrics-aggregator.d.ts +2 -1
  46. package/dist/lib/metrics-aggregator.d.ts.map +1 -1
  47. package/dist/lib/metrics-aggregator.js +15 -4
  48. package/dist/lib/metrics-aggregator.js.map +1 -1
  49. package/dist/lib/system-collector.d.ts +9 -4
  50. package/dist/lib/system-collector.d.ts.map +1 -1
  51. package/dist/lib/system-collector.js +29 -28
  52. package/dist/lib/system-collector.js.map +1 -1
  53. package/dist/tui/HistoricalMonitorApp.d.ts +5 -0
  54. package/dist/tui/HistoricalMonitorApp.d.ts.map +1 -0
  55. package/dist/tui/HistoricalMonitorApp.js +490 -0
  56. package/dist/tui/HistoricalMonitorApp.js.map +1 -0
  57. package/dist/tui/MonitorApp.d.ts.map +1 -1
  58. package/dist/tui/MonitorApp.js +84 -62
  59. package/dist/tui/MonitorApp.js.map +1 -1
  60. package/dist/tui/MultiServerMonitorApp.d.ts +1 -1
  61. package/dist/tui/MultiServerMonitorApp.d.ts.map +1 -1
  62. package/dist/tui/MultiServerMonitorApp.js +293 -77
  63. package/dist/tui/MultiServerMonitorApp.js.map +1 -1
  64. package/dist/types/history-types.d.ts +30 -0
  65. package/dist/types/history-types.d.ts.map +1 -0
  66. package/dist/types/history-types.js +11 -0
  67. package/dist/types/history-types.js.map +1 -0
  68. package/dist/types/monitor-types.d.ts +1 -0
  69. package/dist/types/monitor-types.d.ts.map +1 -1
  70. package/dist/types/server-config.d.ts +1 -0
  71. package/dist/types/server-config.d.ts.map +1 -1
  72. package/dist/types/server-config.js.map +1 -1
  73. package/dist/utils/downsample-utils.d.ts +35 -0
  74. package/dist/utils/downsample-utils.d.ts.map +1 -0
  75. package/dist/utils/downsample-utils.js +107 -0
  76. package/dist/utils/downsample-utils.js.map +1 -0
  77. package/dist/utils/file-utils.d.ts +6 -0
  78. package/dist/utils/file-utils.d.ts.map +1 -1
  79. package/dist/utils/file-utils.js +38 -0
  80. package/dist/utils/file-utils.js.map +1 -1
  81. package/dist/utils/log-utils.d.ts +43 -0
  82. package/dist/utils/log-utils.d.ts.map +1 -0
  83. package/dist/utils/log-utils.js +190 -0
  84. package/dist/utils/log-utils.js.map +1 -0
  85. package/dist/utils/process-utils.d.ts +19 -1
  86. package/dist/utils/process-utils.d.ts.map +1 -1
  87. package/dist/utils/process-utils.js +79 -1
  88. package/dist/utils/process-utils.js.map +1 -1
  89. package/docs/images/.gitkeep +1 -0
  90. package/package.json +3 -1
  91. package/src/cli.ts +32 -7
  92. package/src/commands/config.ts +15 -1
  93. package/src/commands/create.ts +14 -5
  94. package/src/commands/delete.ts +10 -10
  95. package/src/commands/logs-all.ts +251 -0
  96. package/src/commands/logs.ts +138 -2
  97. package/src/commands/monitor.ts +21 -1
  98. package/src/commands/ps.ts +88 -5
  99. package/src/commands/rm.ts +5 -12
  100. package/src/commands/server-show.ts +35 -3
  101. package/src/commands/start.ts +35 -7
  102. package/src/commands/stop.ts +3 -3
  103. package/src/lib/history-manager.ts +172 -0
  104. package/src/lib/metrics-aggregator.ts +18 -5
  105. package/src/lib/system-collector.ts +31 -28
  106. package/src/tui/HistoricalMonitorApp.ts +548 -0
  107. package/src/tui/MonitorApp.ts +89 -64
  108. package/src/tui/MultiServerMonitorApp.ts +348 -103
  109. package/src/types/history-types.ts +39 -0
  110. package/src/types/monitor-types.ts +1 -0
  111. package/src/types/server-config.ts +1 -0
  112. package/src/utils/downsample-utils.ts +128 -0
  113. package/src/utils/file-utils.ts +40 -0
  114. package/src/utils/log-utils.ts +178 -0
  115. package/src/utils/process-utils.ts +85 -1
  116. package/test-load.sh +100 -0
  117. package/dist/tui/components/ErrorState.d.ts +0 -8
  118. package/dist/tui/components/ErrorState.d.ts.map +0 -1
  119. package/dist/tui/components/ErrorState.js +0 -22
  120. package/dist/tui/components/ErrorState.js.map +0 -1
  121. package/dist/tui/components/LoadingState.d.ts +0 -8
  122. package/dist/tui/components/LoadingState.d.ts.map +0 -1
  123. package/dist/tui/components/LoadingState.js +0 -21
  124. package/dist/tui/components/LoadingState.js.map +0 -1
@@ -9,6 +9,8 @@ exports.isPortInUse = isPortInUse;
9
9
  exports.spawnAndReadOneLine = spawnAndReadOneLine;
10
10
  exports.getBatchProcessMemory = getBatchProcessMemory;
11
11
  exports.getProcessMemory = getProcessMemory;
12
+ exports.getBatchProcessCpu = getBatchProcessCpu;
13
+ exports.getProcessCpu = getProcessCpu;
12
14
  const child_process_1 = require("child_process");
13
15
  const util_1 = require("util");
14
16
  exports.execAsync = (0, util_1.promisify)(child_process_1.exec);
@@ -205,14 +207,90 @@ async function getBatchProcessMemory(pids) {
205
207
  }
206
208
  /**
207
209
  * Get memory usage for a single process in bytes
208
- * Uses 'top' on macOS which includes GPU/Metal memory (more accurate for llama-server)
210
+ * Uses 'top' on macOS which reports CPU memory only (NOT GPU/Metal memory)
209
211
  * Returns null if process not found or error occurs
210
212
  * Caches results for 3 seconds to prevent spawning too many top processes
211
213
  *
214
+ * Note: For llama-server processes with GPU offloading, use ServerConfig.metalMemoryMB
215
+ * to get GPU memory allocation (parsed from logs during server startup)
216
+ *
212
217
  * Note: For multiple PIDs, use getBatchProcessMemory() instead - much more efficient
213
218
  */
214
219
  async function getProcessMemory(pid) {
215
220
  const result = await getBatchProcessMemory([pid]);
216
221
  return result.get(pid) ?? null;
217
222
  }
223
+ // Process CPU cache to prevent spawning too many 'ps' processes
224
+ // Cache per PID with 3-second TTL
225
+ const processCpuCache = new Map();
226
+ const PROCESS_CPU_CACHE_TTL = 3000; // 3 seconds
227
+ /**
228
+ * Batch get CPU usage for multiple processes in one ps call
229
+ * Much more efficient than calling getProcessCpu() multiple times
230
+ * Returns Map<pid, percentage> for all requested PIDs
231
+ */
232
+ async function getBatchProcessCpu(pids) {
233
+ const result = new Map();
234
+ const now = Date.now();
235
+ // Check cache and collect PIDs that need fetching
236
+ const pidsToFetch = [];
237
+ for (const pid of pids) {
238
+ const cached = processCpuCache.get(pid);
239
+ if (cached && (now - cached.timestamp) < PROCESS_CPU_CACHE_TTL) {
240
+ result.set(pid, cached.value);
241
+ }
242
+ else {
243
+ pidsToFetch.push(pid);
244
+ }
245
+ }
246
+ // If all PIDs were cached, return early
247
+ if (pidsToFetch.length === 0) {
248
+ return result;
249
+ }
250
+ try {
251
+ // Build ps command with all PIDs: ps -p X,Y,Z -o pid=,%cpu=
252
+ const pidList = pidsToFetch.join(',');
253
+ const output = await execCommand(`ps -p ${pidList} -o pid=,%cpu= 2>/dev/null`);
254
+ // Parse output: each line is "PID %CPU" (e.g., "1438 45.2")
255
+ const lines = output.split('\n');
256
+ for (const line of lines) {
257
+ const match = line.trim().match(/^(\d+)\s+([\d.]+)\s*$/);
258
+ if (!match)
259
+ continue;
260
+ const pid = parseInt(match[1], 10);
261
+ const cpuPercent = parseFloat(match[2]);
262
+ // Cache and store result
263
+ processCpuCache.set(pid, { value: cpuPercent, timestamp: now });
264
+ result.set(pid, cpuPercent);
265
+ }
266
+ // For any PIDs that weren't in the output, cache null (process not running)
267
+ for (const pid of pidsToFetch) {
268
+ if (!result.has(pid)) {
269
+ processCpuCache.set(pid, { value: null, timestamp: now });
270
+ result.set(pid, null);
271
+ }
272
+ }
273
+ return result;
274
+ }
275
+ catch {
276
+ // On error, cache null for all requested PIDs
277
+ for (const pid of pidsToFetch) {
278
+ processCpuCache.set(pid, { value: null, timestamp: now });
279
+ result.set(pid, null);
280
+ }
281
+ return result;
282
+ }
283
+ }
284
+ /**
285
+ * Get CPU usage for a single process as percentage (0-100+)
286
+ * Uses 'ps -o %cpu' on macOS
287
+ * Returns null if process not found or error occurs
288
+ * Caches results for 3 seconds to prevent spawning too many ps processes
289
+ *
290
+ * Note: For multiple PIDs, use getBatchProcessCpu() instead - much more efficient
291
+ */
292
+ async function getProcessCpu(pid) {
293
+ const result = await getBatchProcessCpu([pid]);
294
+ return result.get(pid) ?? null;
295
+ }
218
296
  //# sourceMappingURL=process-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-utils.js","sourceRoot":"","sources":["../../src/utils/process-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"process-utils.js","sourceRoot":"","sources":["../../src/utils/process-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ # Screenshots directory
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appkit/llamacpp-cli",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "CLI tool to manage local llama.cpp servers on macOS",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
@@ -40,12 +40,14 @@
40
40
  "url": "https://github.com/appkitstudio/llamacpp-cli/issues"
41
41
  },
42
42
  "dependencies": {
43
+ "asciichart": "^1.5.25",
43
44
  "blessed": "^0.1.81",
44
45
  "chalk": "^4.1.2",
45
46
  "cli-table3": "^0.6.5",
46
47
  "commander": "^13.0.0"
47
48
  },
48
49
  "devDependencies": {
50
+ "@types/asciichart": "^1.5.8",
49
51
  "@types/blessed": "^0.1.27",
50
52
  "@types/node": "^20.12.7",
51
53
  "commit-and-tag-version": "^12.6.1",
package/src/cli.ts CHANGED
@@ -12,6 +12,7 @@ import { deleteCommand } from './commands/delete';
12
12
  import { pullCommand } from './commands/pull';
13
13
  import { rmCommand } from './commands/rm';
14
14
  import { logsCommand } from './commands/logs';
15
+ import { logsAllCommand } from './commands/logs-all';
15
16
  import { searchCommand } from './commands/search';
16
17
  import { showCommand } from './commands/show';
17
18
  import { serverShowCommand } from './commands/server-show';
@@ -25,7 +26,7 @@ const program = new Command();
25
26
  program
26
27
  .name('llamacpp')
27
28
  .description('CLI tool to manage local llama.cpp servers on macOS')
28
- .version(packageJson.version);
29
+ .version(packageJson.version, '-v, --version', 'Output the version number');
29
30
 
30
31
  // List models
31
32
  program
@@ -42,11 +43,29 @@ program
42
43
 
43
44
  // List running servers
44
45
  program
45
- .command('ps')
46
- .description('List all servers with status')
47
- .action(async () => {
46
+ .command('ps [identifier]')
47
+ .description('Interactive server monitoring dashboard')
48
+ .option('--table', 'Show static table instead of TUI (for scripting)')
49
+ .action(async (identifier?: string, options?: { table?: boolean }) => {
50
+ try {
51
+ await psCommand(identifier, options);
52
+ } catch (error) {
53
+ console.error(chalk.red('❌ Error:'), (error as Error).message);
54
+ process.exit(1);
55
+ }
56
+ });
57
+
58
+ // View all server logs
59
+ program
60
+ .command('logs')
61
+ .description('View log sizes for all servers (with batch operations)')
62
+ .option('--clear', 'Clear current logs for all servers')
63
+ .option('--clear-archived', 'Delete only archived logs for all servers')
64
+ .option('--clear-all', 'Clear current + delete archived logs for all servers')
65
+ .option('--rotate', 'Rotate logs for all servers with timestamps')
66
+ .action(async (options) => {
48
67
  try {
49
- await psCommand();
68
+ await logsAllCommand(options);
50
69
  } catch (error) {
51
70
  console.error(chalk.red('❌ Error:'), (error as Error).message);
52
71
  process.exit(1);
@@ -260,6 +279,10 @@ server
260
279
  .option('--verbose', 'Show all messages including debug internals')
261
280
  .option('--filter <pattern>', 'Custom grep pattern for filtering')
262
281
  .option('--stdout', 'Show stdout instead of stderr (rarely needed)')
282
+ .option('--clear', 'Clear (truncate) log file to zero bytes')
283
+ .option('--clear-archived', 'Delete only archived logs (preserves current logs)')
284
+ .option('--clear-all', 'Clear current logs AND delete all archived logs')
285
+ .option('--rotate', 'Rotate log file with timestamp (preserves old logs)')
263
286
  .action(async (identifier: string, options) => {
264
287
  try {
265
288
  await logsCommand(identifier, options);
@@ -269,12 +292,14 @@ server
269
292
  }
270
293
  });
271
294
 
272
- // Monitor server
295
+ // Monitor server (deprecated - redirects to ps)
273
296
  server
274
297
  .command('monitor [identifier]')
275
- .description('Monitor server with real-time metrics TUI')
298
+ .description('Monitor server with real-time metrics TUI (deprecated: use "llamacpp ps" instead)')
276
299
  .action(async (identifier?: string) => {
277
300
  try {
301
+ console.log(chalk.yellow('⚠️ The "monitor" command is deprecated and will be removed in a future version.'));
302
+ console.log(chalk.dim(' Please use "llamacpp ps" instead for the same functionality.\n'));
278
303
  await monitorCommand(identifier);
279
304
  } catch (error) {
280
305
  console.error(chalk.red('❌ Error:'), (error as Error).message);
@@ -3,6 +3,7 @@ import { stateManager } from '../lib/state-manager';
3
3
  import { statusChecker } from '../lib/status-checker';
4
4
  import { launchctlManager } from '../lib/launchctl-manager';
5
5
  import { configGenerator } from '../lib/config-generator';
6
+ import { autoRotateIfNeeded } from '../utils/log-utils';
6
7
 
7
8
  export interface ConfigUpdateOptions {
8
9
  host?: string;
@@ -109,7 +110,6 @@ export async function serverConfigCommand(
109
110
  // Unload service if running and restart flag is set (forces plist re-read)
110
111
  if (wasRunning && options.restart) {
111
112
  console.log(chalk.dim('Stopping server...'));
112
- await launchctlManager.stopService(server.label);
113
113
  await launchctlManager.unloadService(server.plistPath);
114
114
 
115
115
  // Wait a moment for clean shutdown
@@ -146,6 +146,20 @@ export async function serverConfigCommand(
146
146
 
147
147
  // Restart server if it was running and restart flag is set
148
148
  if (wasRunning && options.restart) {
149
+ // Auto-rotate logs if they exceed 100MB
150
+ try {
151
+ const result = await autoRotateIfNeeded(updatedConfig.stdoutPath, updatedConfig.stderrPath, 100);
152
+ if (result.rotated) {
153
+ console.log(chalk.dim('Auto-rotated large log files:'));
154
+ for (const file of result.files) {
155
+ console.log(chalk.dim(` → ${file}`));
156
+ }
157
+ }
158
+ } catch (error) {
159
+ // Non-fatal, just warn
160
+ console.log(chalk.yellow(`⚠️ Failed to rotate logs: ${(error as Error).message}`));
161
+ }
162
+
149
163
  console.log(chalk.dim('Starting server with new configuration...'));
150
164
  await launchctlManager.loadService(updatedConfig.plistPath);
151
165
  await launchctlManager.startService(updatedConfig.label);
@@ -9,7 +9,7 @@ import { launchctlManager } from '../lib/launchctl-manager';
9
9
  import { statusChecker } from '../lib/status-checker';
10
10
  import { commandExists } from '../utils/process-utils';
11
11
  import { formatBytes } from '../utils/format-utils';
12
- import { ensureDir } from '../utils/file-utils';
12
+ import { ensureDir, parseMetalMemoryFromLog } from '../utils/file-utils';
13
13
  import { ensureModelsDirectory } from '../lib/models-dir-setup';
14
14
 
15
15
  interface CreateOptions {
@@ -152,19 +152,28 @@ export async function createCommand(model: string, options: CreateOptions): Prom
152
152
 
153
153
  if (!started) {
154
154
  // Clean up if startup fails
155
- await launchctlManager.stopService(config.label);
156
155
  await launchctlManager.unloadService(config.plistPath);
157
156
  await launchctlManager.deletePlist(config.plistPath);
158
157
  throw new Error('Server failed to start. Check logs with: llamacpp server logs --errors');
159
158
  }
160
159
 
161
160
  // 12. Update config with running status
162
- const updatedConfig = await statusChecker.updateServerStatus(config);
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
+ }
163
172
 
164
- // 13. Save server config
173
+ // 14. Save server config
165
174
  await stateManager.saveServerConfig(updatedConfig);
166
175
 
167
- // 14. Display success message
176
+ // 15. Display success message
168
177
  console.log();
169
178
  console.log(chalk.green('✅ Server created and started successfully!'));
170
179
  console.log();
@@ -24,21 +24,21 @@ export async function deleteCommand(identifier: string): Promise<void> {
24
24
  console.log();
25
25
  console.log(chalk.blue(`🗑️ Deleting server ${server.modelName}...`));
26
26
 
27
- // Stop server if running
27
+ // Unload service (stops and removes from launchd)
28
28
  if (server.status === 'running') {
29
- console.log(chalk.dim('Stopping server...'));
30
- try {
31
- await launchctlManager.stopService(server.label);
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') {
32
36
  await launchctlManager.waitForServiceStop(server.label, 5000);
33
- } catch (error) {
34
- console.log(chalk.yellow('⚠️ Failed to stop server gracefully'));
35
37
  }
38
+ } catch (error) {
39
+ console.log(chalk.yellow('⚠️ Failed to unload service gracefully'));
36
40
  }
37
41
 
38
- // Unload service
39
- console.log(chalk.dim('Unloading launchctl service...'));
40
- await launchctlManager.unloadService(server.plistPath);
41
-
42
42
  // Delete plist
43
43
  console.log(chalk.dim('Deleting plist file...'));
44
44
  await launchctlManager.deletePlist(server.plistPath);
@@ -0,0 +1,251 @@
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
+ }