@appkit/llamacpp-cli 1.6.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.
- package/CHANGELOG.md +7 -0
- package/README.md +67 -1
- package/dist/cli.js +23 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +15 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +0 -1
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/delete.js +12 -10
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/logs-all.d.ts +9 -0
- package/dist/commands/logs-all.d.ts.map +1 -0
- package/dist/commands/logs-all.js +209 -0
- package/dist/commands/logs-all.js.map +1 -0
- package/dist/commands/logs.d.ts +4 -0
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +108 -2
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/rm.d.ts.map +1 -1
- package/dist/commands/rm.js +5 -12
- package/dist/commands/rm.js.map +1 -1
- package/dist/commands/server-show.d.ts.map +1 -1
- package/dist/commands/server-show.js +20 -0
- package/dist/commands/server-show.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +22 -7
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/stop.js +3 -3
- package/dist/commands/stop.js.map +1 -1
- package/dist/utils/log-utils.d.ts +43 -0
- package/dist/utils/log-utils.d.ts.map +1 -0
- package/dist/utils/log-utils.js +190 -0
- package/dist/utils/log-utils.js.map +1 -0
- package/package.json +1 -1
- package/src/cli.ts +23 -1
- package/src/commands/config.ts +15 -1
- package/src/commands/create.ts +0 -1
- package/src/commands/delete.ts +10 -10
- package/src/commands/logs-all.ts +251 -0
- package/src/commands/logs.ts +138 -2
- package/src/commands/rm.ts +5 -12
- package/src/commands/server-show.ts +25 -0
- package/src/commands/start.ts +22 -7
- package/src/commands/stop.ts +3 -3
- package/src/utils/log-utils.ts +178 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getFileSize = getFileSize;
|
|
37
|
+
exports.formatFileSize = formatFileSize;
|
|
38
|
+
exports.rotateLogFile = rotateLogFile;
|
|
39
|
+
exports.clearLogFile = clearLogFile;
|
|
40
|
+
exports.autoRotateIfNeeded = autoRotateIfNeeded;
|
|
41
|
+
exports.getArchivedLogInfo = getArchivedLogInfo;
|
|
42
|
+
exports.deleteArchivedLogs = deleteArchivedLogs;
|
|
43
|
+
const fs = __importStar(require("fs/promises"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const file_utils_1 = require("./file-utils");
|
|
46
|
+
/**
|
|
47
|
+
* Get the size of a file in bytes
|
|
48
|
+
*/
|
|
49
|
+
async function getFileSize(filePath) {
|
|
50
|
+
try {
|
|
51
|
+
const stats = await fs.stat(filePath);
|
|
52
|
+
return stats.size;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Format bytes to human-readable size
|
|
60
|
+
*/
|
|
61
|
+
function formatFileSize(bytes) {
|
|
62
|
+
if (bytes === 0)
|
|
63
|
+
return '0 B';
|
|
64
|
+
const k = 1024;
|
|
65
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
66
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
67
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Rotate a log file with timestamp
|
|
71
|
+
* Renames current log to <name>.YYYY-MM-DD-HH-MM-SS.<ext>
|
|
72
|
+
* Returns the new archived filename
|
|
73
|
+
*/
|
|
74
|
+
async function rotateLogFile(logPath) {
|
|
75
|
+
if (!(await (0, file_utils_1.fileExists)(logPath))) {
|
|
76
|
+
throw new Error(`Log file does not exist: ${logPath}`);
|
|
77
|
+
}
|
|
78
|
+
// Get file size before rotation
|
|
79
|
+
const size = await getFileSize(logPath);
|
|
80
|
+
if (size === 0) {
|
|
81
|
+
throw new Error('Log file is empty, nothing to rotate');
|
|
82
|
+
}
|
|
83
|
+
// Generate timestamp
|
|
84
|
+
const timestamp = new Date()
|
|
85
|
+
.toISOString()
|
|
86
|
+
.replace(/T/, '-')
|
|
87
|
+
.replace(/:/g, '-')
|
|
88
|
+
.replace(/\..+/, '');
|
|
89
|
+
// Parse path components
|
|
90
|
+
const dir = path.dirname(logPath);
|
|
91
|
+
const ext = path.extname(logPath);
|
|
92
|
+
const basename = path.basename(logPath, ext);
|
|
93
|
+
// New archived filename
|
|
94
|
+
const archivedPath = path.join(dir, `${basename}.${timestamp}${ext}`);
|
|
95
|
+
// Rename current log to archived version
|
|
96
|
+
await fs.rename(logPath, archivedPath);
|
|
97
|
+
return archivedPath;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clear (truncate) a log file to zero bytes
|
|
101
|
+
*/
|
|
102
|
+
async function clearLogFile(logPath) {
|
|
103
|
+
if (!(await (0, file_utils_1.fileExists)(logPath))) {
|
|
104
|
+
throw new Error(`Log file does not exist: ${logPath}`);
|
|
105
|
+
}
|
|
106
|
+
// Truncate file to 0 bytes
|
|
107
|
+
await fs.truncate(logPath, 0);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Auto-rotate log files if they exceed threshold
|
|
111
|
+
* Returns true if rotation occurred, false otherwise
|
|
112
|
+
*/
|
|
113
|
+
async function autoRotateIfNeeded(stdoutPath, stderrPath, thresholdMB = 100) {
|
|
114
|
+
const thresholdBytes = thresholdMB * 1024 * 1024;
|
|
115
|
+
const rotatedFiles = [];
|
|
116
|
+
// Check stdout
|
|
117
|
+
if (await (0, file_utils_1.fileExists)(stdoutPath)) {
|
|
118
|
+
const stdoutSize = await getFileSize(stdoutPath);
|
|
119
|
+
if (stdoutSize > thresholdBytes) {
|
|
120
|
+
const archived = await rotateLogFile(stdoutPath);
|
|
121
|
+
rotatedFiles.push(archived);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Check stderr
|
|
125
|
+
if (await (0, file_utils_1.fileExists)(stderrPath)) {
|
|
126
|
+
const stderrSize = await getFileSize(stderrPath);
|
|
127
|
+
if (stderrSize > thresholdBytes) {
|
|
128
|
+
const archived = await rotateLogFile(stderrPath);
|
|
129
|
+
rotatedFiles.push(archived);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
rotated: rotatedFiles.length > 0,
|
|
134
|
+
files: rotatedFiles,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get information about archived log files for a server
|
|
139
|
+
* Returns count and total size of timestamped archived logs
|
|
140
|
+
*/
|
|
141
|
+
async function getArchivedLogInfo(serverId) {
|
|
142
|
+
const logsDir = (0, file_utils_1.getLogsDir)();
|
|
143
|
+
let count = 0;
|
|
144
|
+
let totalSize = 0;
|
|
145
|
+
try {
|
|
146
|
+
const files = await fs.readdir(logsDir);
|
|
147
|
+
// Pattern matches: server-id.YYYY-MM-DD-HH-MM-SS.{stdout,stderr}
|
|
148
|
+
const pattern = new RegExp(`^${serverId}\\.(\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2})\\.(stdout|stderr)$`);
|
|
149
|
+
for (const file of files) {
|
|
150
|
+
if (pattern.test(file)) {
|
|
151
|
+
count++;
|
|
152
|
+
const filePath = path.join(logsDir, file);
|
|
153
|
+
totalSize += await getFileSize(filePath);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
// Directory doesn't exist or can't be read
|
|
159
|
+
return { count: 0, totalSize: 0 };
|
|
160
|
+
}
|
|
161
|
+
return { count, totalSize };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Delete all archived log files for a server
|
|
165
|
+
* Returns count and total size of deleted files
|
|
166
|
+
*/
|
|
167
|
+
async function deleteArchivedLogs(serverId) {
|
|
168
|
+
const logsDir = (0, file_utils_1.getLogsDir)();
|
|
169
|
+
let count = 0;
|
|
170
|
+
let totalSize = 0;
|
|
171
|
+
try {
|
|
172
|
+
const files = await fs.readdir(logsDir);
|
|
173
|
+
// Pattern matches: server-id.YYYY-MM-DD-HH-MM-SS.{stdout,stderr}
|
|
174
|
+
const pattern = new RegExp(`^${serverId}\\.(\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2})\\.(stdout|stderr)$`);
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
if (pattern.test(file)) {
|
|
177
|
+
const filePath = path.join(logsDir, file);
|
|
178
|
+
const size = await getFileSize(filePath);
|
|
179
|
+
await fs.unlink(filePath);
|
|
180
|
+
count++;
|
|
181
|
+
totalSize += size;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
throw new Error(`Failed to delete archived logs: ${error.message}`);
|
|
187
|
+
}
|
|
188
|
+
return { count, totalSize };
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=log-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-utils.js","sourceRoot":"","sources":["../../src/utils/log-utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
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
|
|
@@ -54,6 +55,23 @@ program
|
|
|
54
55
|
}
|
|
55
56
|
});
|
|
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) => {
|
|
67
|
+
try {
|
|
68
|
+
await logsAllCommand(options);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(chalk.red('❌ Error:'), (error as Error).message);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
57
75
|
// Search for models
|
|
58
76
|
program
|
|
59
77
|
.command('search')
|
|
@@ -261,6 +279,10 @@ server
|
|
|
261
279
|
.option('--verbose', 'Show all messages including debug internals')
|
|
262
280
|
.option('--filter <pattern>', 'Custom grep pattern for filtering')
|
|
263
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)')
|
|
264
286
|
.action(async (identifier: string, options) => {
|
|
265
287
|
try {
|
|
266
288
|
await logsCommand(identifier, options);
|
package/src/commands/config.ts
CHANGED
|
@@ -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);
|
package/src/commands/create.ts
CHANGED
|
@@ -152,7 +152,6 @@ 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');
|
package/src/commands/delete.ts
CHANGED
|
@@ -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
|
-
//
|
|
27
|
+
// Unload service (stops and removes from launchd)
|
|
28
28
|
if (server.status === 'running') {
|
|
29
|
-
console.log(chalk.dim('Stopping
|
|
30
|
-
|
|
31
|
-
|
|
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
|
+
}
|