@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.
- package/CHANGELOG.md +20 -0
- package/MONITORING-ACCURACY-FIX.md +199 -0
- package/PER-PROCESS-METRICS.md +190 -0
- package/README.md +124 -9
- package/dist/cli.js +32 -7
- 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 +12 -4
- 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/monitor.d.ts.map +1 -1
- package/dist/commands/monitor.js +51 -1
- package/dist/commands/monitor.js.map +1 -1
- package/dist/commands/ps.d.ts +3 -1
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +75 -5
- package/dist/commands/ps.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 +30 -3
- package/dist/commands/server-show.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +34 -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/lib/history-manager.d.ts +46 -0
- package/dist/lib/history-manager.d.ts.map +1 -0
- package/dist/lib/history-manager.js +157 -0
- package/dist/lib/history-manager.js.map +1 -0
- package/dist/lib/metrics-aggregator.d.ts +2 -1
- package/dist/lib/metrics-aggregator.d.ts.map +1 -1
- package/dist/lib/metrics-aggregator.js +15 -4
- package/dist/lib/metrics-aggregator.js.map +1 -1
- package/dist/lib/system-collector.d.ts +9 -4
- package/dist/lib/system-collector.d.ts.map +1 -1
- package/dist/lib/system-collector.js +29 -28
- package/dist/lib/system-collector.js.map +1 -1
- package/dist/tui/HistoricalMonitorApp.d.ts +5 -0
- package/dist/tui/HistoricalMonitorApp.d.ts.map +1 -0
- package/dist/tui/HistoricalMonitorApp.js +490 -0
- package/dist/tui/HistoricalMonitorApp.js.map +1 -0
- package/dist/tui/MonitorApp.d.ts.map +1 -1
- package/dist/tui/MonitorApp.js +84 -62
- package/dist/tui/MonitorApp.js.map +1 -1
- package/dist/tui/MultiServerMonitorApp.d.ts +1 -1
- package/dist/tui/MultiServerMonitorApp.d.ts.map +1 -1
- package/dist/tui/MultiServerMonitorApp.js +293 -77
- package/dist/tui/MultiServerMonitorApp.js.map +1 -1
- package/dist/types/history-types.d.ts +30 -0
- package/dist/types/history-types.d.ts.map +1 -0
- package/dist/types/history-types.js +11 -0
- package/dist/types/history-types.js.map +1 -0
- package/dist/types/monitor-types.d.ts +1 -0
- package/dist/types/monitor-types.d.ts.map +1 -1
- package/dist/types/server-config.d.ts +1 -0
- package/dist/types/server-config.d.ts.map +1 -1
- package/dist/types/server-config.js.map +1 -1
- package/dist/utils/downsample-utils.d.ts +35 -0
- package/dist/utils/downsample-utils.d.ts.map +1 -0
- package/dist/utils/downsample-utils.js +107 -0
- package/dist/utils/downsample-utils.js.map +1 -0
- package/dist/utils/file-utils.d.ts +6 -0
- package/dist/utils/file-utils.d.ts.map +1 -1
- package/dist/utils/file-utils.js +38 -0
- package/dist/utils/file-utils.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/dist/utils/process-utils.d.ts +19 -1
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +79 -1
- package/dist/utils/process-utils.js.map +1 -1
- package/docs/images/.gitkeep +1 -0
- package/package.json +3 -1
- package/src/cli.ts +32 -7
- package/src/commands/config.ts +15 -1
- package/src/commands/create.ts +14 -5
- 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/monitor.ts +21 -1
- package/src/commands/ps.ts +88 -5
- package/src/commands/rm.ts +5 -12
- package/src/commands/server-show.ts +35 -3
- package/src/commands/start.ts +35 -7
- package/src/commands/stop.ts +3 -3
- package/src/lib/history-manager.ts +172 -0
- package/src/lib/metrics-aggregator.ts +18 -5
- package/src/lib/system-collector.ts +31 -28
- package/src/tui/HistoricalMonitorApp.ts +548 -0
- package/src/tui/MonitorApp.ts +89 -64
- package/src/tui/MultiServerMonitorApp.ts +348 -103
- package/src/types/history-types.ts +39 -0
- package/src/types/monitor-types.ts +1 -0
- package/src/types/server-config.ts +1 -0
- package/src/utils/downsample-utils.ts +128 -0
- package/src/utils/file-utils.ts +40 -0
- package/src/utils/log-utils.ts +178 -0
- package/src/utils/process-utils.ts +85 -1
- package/test-load.sh +100 -0
- package/dist/tui/components/ErrorState.d.ts +0 -8
- package/dist/tui/components/ErrorState.d.ts.map +0 -1
- package/dist/tui/components/ErrorState.js +0 -22
- package/dist/tui/components/ErrorState.js.map +0 -1
- package/dist/tui/components/LoadingState.d.ts +0 -8
- package/dist/tui/components/LoadingState.d.ts.map +0 -1
- package/dist/tui/components/LoadingState.js +0 -21
- 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
|
|
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":";;;AASA,kCAGC;AAKD,0CAMC;AAKD,sCAOC;AAKD,4CAOC;AAKD,kCAOC;AAOD,kDAyEC;AAYD,sDAmEC;
|
|
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.
|
|
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('
|
|
47
|
-
.
|
|
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
|
|
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);
|
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
|
@@ -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
|
-
|
|
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
|
-
//
|
|
173
|
+
// 14. Save server config
|
|
165
174
|
await stateManager.saveServerConfig(updatedConfig);
|
|
166
175
|
|
|
167
|
-
//
|
|
176
|
+
// 15. Display success message
|
|
168
177
|
console.log();
|
|
169
178
|
console.log(chalk.green('✅ Server created and started successfully!'));
|
|
170
179
|
console.log();
|
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
|
+
}
|