@appkit/llamacpp-cli 1.0.0 → 1.1.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 +52 -14
- package/dist/cli.js +8 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/logs.d.ts +4 -0
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +157 -24
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +11 -1
- package/dist/commands/ps.js.map +1 -1
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +4 -0
- package/dist/commands/start.js.map +1 -1
- package/dist/lib/config-generator.d.ts +2 -0
- package/dist/lib/config-generator.d.ts.map +1 -1
- package/dist/lib/config-generator.js +6 -0
- package/dist/lib/config-generator.js.map +1 -1
- package/dist/lib/launchctl-manager.d.ts.map +1 -1
- package/dist/lib/launchctl-manager.js +22 -13
- package/dist/lib/launchctl-manager.js.map +1 -1
- package/dist/types/server-config.d.ts +2 -0
- package/dist/types/server-config.d.ts.map +1 -1
- package/dist/types/server-config.js.map +1 -1
- package/dist/utils/log-parser.d.ts +37 -0
- package/dist/utils/log-parser.d.ts.map +1 -0
- package/dist/utils/log-parser.js +164 -0
- package/dist/utils/log-parser.js.map +1 -0
- package/dist/utils/process-utils.d.ts +6 -0
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +35 -0
- package/dist/utils/process-utils.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +8 -2
- package/src/commands/logs.ts +133 -26
- package/src/commands/ps.ts +13 -2
- package/src/commands/start.ts +6 -0
- package/src/lib/config-generator.ts +8 -0
- package/src/lib/launchctl-manager.ts +22 -13
- package/src/types/server-config.ts +2 -0
- package/src/utils/log-parser.ts +184 -0
- package/src/utils/process-utils.ts +38 -0
|
@@ -42,6 +42,27 @@ class LaunchctlManager {
|
|
|
42
42
|
* Generate plist XML content for a server
|
|
43
43
|
*/
|
|
44
44
|
generatePlist(config) {
|
|
45
|
+
// Build program arguments array
|
|
46
|
+
const args = [
|
|
47
|
+
'/opt/homebrew/bin/llama-server',
|
|
48
|
+
'--model', config.modelPath,
|
|
49
|
+
'--port', config.port.toString(),
|
|
50
|
+
'--threads', config.threads.toString(),
|
|
51
|
+
'--ctx-size', config.ctxSize.toString(),
|
|
52
|
+
'--gpu-layers', config.gpuLayers.toString(),
|
|
53
|
+
];
|
|
54
|
+
// Add flags
|
|
55
|
+
if (config.embeddings)
|
|
56
|
+
args.push('--embeddings');
|
|
57
|
+
if (config.jinja)
|
|
58
|
+
args.push('--jinja');
|
|
59
|
+
if (config.logVerbosity !== undefined) {
|
|
60
|
+
args.push('--log-verbosity', config.logVerbosity.toString());
|
|
61
|
+
}
|
|
62
|
+
if (config.logTimestamps)
|
|
63
|
+
args.push('--log-timestamps');
|
|
64
|
+
// Generate XML array elements
|
|
65
|
+
const argsXml = args.map(arg => ` <string>${arg}</string>`).join('\n');
|
|
45
66
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
46
67
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
47
68
|
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -52,19 +73,7 @@ class LaunchctlManager {
|
|
|
52
73
|
|
|
53
74
|
<key>ProgramArguments</key>
|
|
54
75
|
<array>
|
|
55
|
-
|
|
56
|
-
<string>--model</string>
|
|
57
|
-
<string>${config.modelPath}</string>
|
|
58
|
-
<string>--port</string>
|
|
59
|
-
<string>${config.port}</string>
|
|
60
|
-
<string>--threads</string>
|
|
61
|
-
<string>${config.threads}</string>
|
|
62
|
-
<string>--ctx-size</string>
|
|
63
|
-
<string>${config.ctxSize}</string>
|
|
64
|
-
<string>--gpu-layers</string>
|
|
65
|
-
<string>${config.gpuLayers}</string>
|
|
66
|
-
<string>--embeddings</string>
|
|
67
|
-
<string>--jinja</string>
|
|
76
|
+
${argsXml}
|
|
68
77
|
</array>
|
|
69
78
|
|
|
70
79
|
<key>RunAtLoad</key>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launchctl-manager.js","sourceRoot":"","sources":["../../src/lib/launchctl-manager.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,gDAAkC;AAElC,0DAAgE;AAChE,oDAAkE;AASlE,MAAa,gBAAgB;IAC3B;;OAEG;IACH,aAAa,CAAC,MAAoB;QAChC,OAAO
|
|
1
|
+
{"version":3,"file":"launchctl-manager.js","sourceRoot":"","sources":["../../src/lib/launchctl-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/types/server-config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IAGb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/types/server-config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IAGb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IAGvB,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IAGd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAM3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/types/server-config.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/types/server-config.ts"],"names":[],"mappings":";;AAqCA,8CAMC;AAVD;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,SAAiB;IACjD,OAAO,SAAS;SACb,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAW,yBAAyB;SAC3D,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAI,wCAAwC;SAC1E,WAAW,EAAE,CAAsB,YAAY;SAC/C,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAU,yBAAyB;AAChE,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse and consolidate verbose llama-server logs into compact single-line format
|
|
3
|
+
*/
|
|
4
|
+
export declare class LogParser {
|
|
5
|
+
private buffer;
|
|
6
|
+
private isBuffering;
|
|
7
|
+
/**
|
|
8
|
+
* Process log lines and output compact format
|
|
9
|
+
*/
|
|
10
|
+
processLine(line: string, callback: (compactLine: string) => void): void;
|
|
11
|
+
/**
|
|
12
|
+
* Consolidate buffered request/response lines into single line
|
|
13
|
+
*/
|
|
14
|
+
private consolidateRequest;
|
|
15
|
+
/**
|
|
16
|
+
* Extract timestamp from log line
|
|
17
|
+
*/
|
|
18
|
+
private extractTimestamp;
|
|
19
|
+
/**
|
|
20
|
+
* Extract JSON from log line
|
|
21
|
+
*/
|
|
22
|
+
private extractJson;
|
|
23
|
+
/**
|
|
24
|
+
* Extract first user message from request JSON
|
|
25
|
+
*/
|
|
26
|
+
private extractUserMessage;
|
|
27
|
+
/**
|
|
28
|
+
* Extract response time from response JSON
|
|
29
|
+
*/
|
|
30
|
+
private extractResponseTime;
|
|
31
|
+
/**
|
|
32
|
+
* Format compact log line
|
|
33
|
+
*/
|
|
34
|
+
private formatCompactLine;
|
|
35
|
+
}
|
|
36
|
+
export declare const logParser: LogParser;
|
|
37
|
+
//# sourceMappingURL=log-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-parser.d.ts","sourceRoot":"","sources":["../../src/utils/log-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,WAAW,CAAS;IAE5B;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAwBxE;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiD1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoB3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAa1B;AAGD,eAAO,MAAM,SAAS,WAAkB,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Parse and consolidate verbose llama-server logs into compact single-line format
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.logParser = exports.LogParser = void 0;
|
|
7
|
+
class LogParser {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.buffer = [];
|
|
10
|
+
this.isBuffering = false;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Process log lines and output compact format
|
|
14
|
+
*/
|
|
15
|
+
processLine(line, callback) {
|
|
16
|
+
// Check if this is the start of an HTTP request log
|
|
17
|
+
if (line.includes('log_server_r: request: POST')) {
|
|
18
|
+
this.isBuffering = true;
|
|
19
|
+
this.buffer = [line];
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// If we're buffering, collect lines
|
|
23
|
+
if (this.isBuffering) {
|
|
24
|
+
this.buffer.push(line);
|
|
25
|
+
// Check if we have a complete request (found response line)
|
|
26
|
+
if (line.includes('log_server_r: response:')) {
|
|
27
|
+
const compactLine = this.consolidateRequest(this.buffer);
|
|
28
|
+
if (compactLine) {
|
|
29
|
+
callback(compactLine);
|
|
30
|
+
}
|
|
31
|
+
this.buffer = [];
|
|
32
|
+
this.isBuffering = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Consolidate buffered request/response lines into single line
|
|
38
|
+
*/
|
|
39
|
+
consolidateRequest(lines) {
|
|
40
|
+
try {
|
|
41
|
+
// Parse first line: timestamp and request info
|
|
42
|
+
const firstLine = lines[0];
|
|
43
|
+
const timestamp = this.extractTimestamp(firstLine);
|
|
44
|
+
const requestMatch = firstLine.match(/request: (POST|GET|PUT|DELETE) (\/[^\s]+) ([^\s]+) (\d+)/);
|
|
45
|
+
if (!requestMatch)
|
|
46
|
+
return null;
|
|
47
|
+
const [, method, endpoint, ip, status] = requestMatch;
|
|
48
|
+
// Parse request JSON (second line)
|
|
49
|
+
const requestLine = lines.find((l) => l.includes('log_server_r: request:') && l.includes('{'));
|
|
50
|
+
if (!requestLine)
|
|
51
|
+
return null;
|
|
52
|
+
const requestJson = this.extractJson(requestLine);
|
|
53
|
+
if (!requestJson)
|
|
54
|
+
return null;
|
|
55
|
+
const userMessage = this.extractUserMessage(requestJson);
|
|
56
|
+
// Parse response JSON (last line)
|
|
57
|
+
const responseLine = lines.find((l) => l.includes('log_server_r: response:'));
|
|
58
|
+
if (!responseLine)
|
|
59
|
+
return null;
|
|
60
|
+
const responseJson = this.extractJson(responseLine);
|
|
61
|
+
if (!responseJson)
|
|
62
|
+
return null;
|
|
63
|
+
const tokensIn = responseJson.usage?.prompt_tokens || 0;
|
|
64
|
+
const tokensOut = responseJson.usage?.completion_tokens || 0;
|
|
65
|
+
// Extract response time from verbose timings
|
|
66
|
+
const responseTimeMs = this.extractResponseTime(responseJson);
|
|
67
|
+
// Format compact line
|
|
68
|
+
return this.formatCompactLine({
|
|
69
|
+
timestamp,
|
|
70
|
+
method,
|
|
71
|
+
endpoint,
|
|
72
|
+
ip,
|
|
73
|
+
status: parseInt(status, 10),
|
|
74
|
+
userMessage,
|
|
75
|
+
tokensIn,
|
|
76
|
+
tokensOut,
|
|
77
|
+
responseTimeMs,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Extract timestamp from log line
|
|
86
|
+
*/
|
|
87
|
+
extractTimestamp(line) {
|
|
88
|
+
// Look for timestamp format like [2025-12-09 10:13:45]
|
|
89
|
+
const match = line.match(/\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]/);
|
|
90
|
+
if (match) {
|
|
91
|
+
return match[1]; // Return as-is: 2025-12-09 10:13:45
|
|
92
|
+
}
|
|
93
|
+
// If no timestamp in logs, use current time in same format
|
|
94
|
+
const now = new Date();
|
|
95
|
+
return now.toISOString().substring(0, 19).replace('T', ' '); // 2025-12-09 10:13:45
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Extract JSON from log line
|
|
99
|
+
*/
|
|
100
|
+
extractJson(line) {
|
|
101
|
+
const jsonStart = line.indexOf('{');
|
|
102
|
+
if (jsonStart === -1)
|
|
103
|
+
return null;
|
|
104
|
+
try {
|
|
105
|
+
const jsonStr = line.substring(jsonStart);
|
|
106
|
+
return JSON.parse(jsonStr);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extract first user message from request JSON
|
|
114
|
+
*/
|
|
115
|
+
extractUserMessage(requestJson) {
|
|
116
|
+
const messages = requestJson.messages || [];
|
|
117
|
+
const userMsg = messages.find((m) => m.role === 'user');
|
|
118
|
+
if (!userMsg || !userMsg.content)
|
|
119
|
+
return '';
|
|
120
|
+
// Truncate to first 50 characters
|
|
121
|
+
const content = userMsg.content.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
|
|
122
|
+
return content.length > 50 ? content.substring(0, 47) + '...' : content;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Extract response time from response JSON
|
|
126
|
+
*/
|
|
127
|
+
extractResponseTime(responseJson) {
|
|
128
|
+
// Check __verbose.timings first (has total time)
|
|
129
|
+
const verboseTimings = responseJson.__verbose?.timings;
|
|
130
|
+
if (verboseTimings) {
|
|
131
|
+
const promptMs = verboseTimings.prompt_ms || 0;
|
|
132
|
+
const predictedMs = verboseTimings.predicted_ms || 0;
|
|
133
|
+
return Math.round(promptMs + predictedMs);
|
|
134
|
+
}
|
|
135
|
+
// Fallback to top-level timings
|
|
136
|
+
const timings = responseJson.timings;
|
|
137
|
+
if (timings) {
|
|
138
|
+
const promptMs = timings.prompt_ms || 0;
|
|
139
|
+
const predictedMs = timings.predicted_ms || 0;
|
|
140
|
+
return Math.round(promptMs + predictedMs);
|
|
141
|
+
}
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Format compact log line
|
|
146
|
+
*/
|
|
147
|
+
formatCompactLine(entry) {
|
|
148
|
+
return [
|
|
149
|
+
entry.timestamp,
|
|
150
|
+
entry.method,
|
|
151
|
+
entry.endpoint,
|
|
152
|
+
entry.ip,
|
|
153
|
+
entry.status,
|
|
154
|
+
`"${entry.userMessage}"`,
|
|
155
|
+
entry.tokensIn,
|
|
156
|
+
entry.tokensOut,
|
|
157
|
+
entry.responseTimeMs,
|
|
158
|
+
].join(' ');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.LogParser = LogParser;
|
|
162
|
+
// Export singleton instance
|
|
163
|
+
exports.logParser = new LogParser();
|
|
164
|
+
//# sourceMappingURL=log-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-parser.js","sourceRoot":"","sources":["../../src/utils/log-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,4 +24,10 @@ export declare function isProcessRunning(pid: number): Promise<boolean>;
|
|
|
24
24
|
* Check if a port is in use
|
|
25
25
|
*/
|
|
26
26
|
export declare function isPortInUse(port: number): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Get memory usage for a process in bytes
|
|
29
|
+
* Uses 'top' on macOS which includes GPU/Metal memory (more accurate for llama-server)
|
|
30
|
+
* Returns null if process not found or error occurs
|
|
31
|
+
*/
|
|
32
|
+
export declare function getProcessMemory(pid: number): Promise<number | null>;
|
|
27
33
|
//# sourceMappingURL=process-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-utils.d.ts","sourceRoot":"","sources":["../../src/utils/process-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGrC,eAAO,MAAM,SAAS,2BAAkB,CAAC;AAEzC;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAMlG;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOrE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOpE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOhE"}
|
|
1
|
+
{"version":3,"file":"process-utils.d.ts","sourceRoot":"","sources":["../../src/utils/process-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGrC,eAAO,MAAM,SAAS,2BAAkB,CAAC;AAEzC;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAMlG;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOrE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOpE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOhE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+B1E"}
|
|
@@ -6,6 +6,7 @@ exports.execCommandFull = execCommandFull;
|
|
|
6
6
|
exports.commandExists = commandExists;
|
|
7
7
|
exports.isProcessRunning = isProcessRunning;
|
|
8
8
|
exports.isPortInUse = isPortInUse;
|
|
9
|
+
exports.getProcessMemory = getProcessMemory;
|
|
9
10
|
const child_process_1 = require("child_process");
|
|
10
11
|
const util_1 = require("util");
|
|
11
12
|
exports.execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
@@ -63,4 +64,38 @@ async function isPortInUse(port) {
|
|
|
63
64
|
return false;
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Get memory usage for a process in bytes
|
|
69
|
+
* Uses 'top' on macOS which includes GPU/Metal memory (more accurate for llama-server)
|
|
70
|
+
* Returns null if process not found or error occurs
|
|
71
|
+
*/
|
|
72
|
+
async function getProcessMemory(pid) {
|
|
73
|
+
try {
|
|
74
|
+
// Use top with -l 1 (one sample) to get memory stats
|
|
75
|
+
// MEM column shows resident memory including GPU memory on macOS
|
|
76
|
+
const output = await execCommand(`top -l 1 -pid ${pid} -stats mem`);
|
|
77
|
+
// Get the last non-empty line which contains the memory value
|
|
78
|
+
const lines = output.split('\n').filter((line) => line.trim().length > 0);
|
|
79
|
+
if (lines.length === 0)
|
|
80
|
+
return null;
|
|
81
|
+
const memStr = lines[lines.length - 1].trim();
|
|
82
|
+
// Parse memory string (e.g., "10.5G", "512M", "1024K", "10G")
|
|
83
|
+
const match = memStr.match(/^([\d.]+)([KMGT])$/);
|
|
84
|
+
if (!match)
|
|
85
|
+
return null;
|
|
86
|
+
const value = parseFloat(match[1]);
|
|
87
|
+
const unit = match[2];
|
|
88
|
+
// Convert to bytes
|
|
89
|
+
const multipliers = {
|
|
90
|
+
K: 1024,
|
|
91
|
+
M: 1024 * 1024,
|
|
92
|
+
G: 1024 * 1024 * 1024,
|
|
93
|
+
T: 1024 * 1024 * 1024 * 1024,
|
|
94
|
+
};
|
|
95
|
+
return Math.round(value * multipliers[unit]);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
66
101
|
//# 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;
|
|
1
|
+
{"version":3,"file":"process-utils.js","sourceRoot":"","sources":["../../src/utils/process-utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -123,6 +123,8 @@ server
|
|
|
123
123
|
.option('-t, --threads <number>', 'Thread count (default: auto)', parseInt)
|
|
124
124
|
.option('-c, --ctx-size <number>', 'Context size (default: auto)', parseInt)
|
|
125
125
|
.option('-g, --gpu-layers <number>', 'GPU layers (default: 60)', parseInt)
|
|
126
|
+
.option('-v, --log-verbosity <level>', 'Log verbosity: 0=errors, 1=warnings, 2=info (default), 9=debug, omit for all', parseInt)
|
|
127
|
+
.option('--no-log-timestamps', 'Disable timestamps in log messages')
|
|
126
128
|
.action(async (model: string, options) => {
|
|
127
129
|
try {
|
|
128
130
|
await startCommand(model, options);
|
|
@@ -177,11 +179,15 @@ server
|
|
|
177
179
|
// View logs
|
|
178
180
|
server
|
|
179
181
|
.command('logs')
|
|
180
|
-
.description('View server logs')
|
|
182
|
+
.description('View server logs (default: compact one-line per request)')
|
|
181
183
|
.argument('<identifier>', 'Server identifier: port (9000), server ID (llama-3-2-3b), or partial model name')
|
|
182
184
|
.option('-f, --follow', 'Follow log output in real-time')
|
|
183
185
|
.option('-n, --lines <number>', 'Number of lines to show (default: 50)', parseInt)
|
|
184
|
-
.option('--
|
|
186
|
+
.option('--http', 'Show full HTTP JSON request/response logs')
|
|
187
|
+
.option('--errors', 'Show only error messages')
|
|
188
|
+
.option('--verbose', 'Show all messages including debug internals')
|
|
189
|
+
.option('--filter <pattern>', 'Custom grep pattern for filtering')
|
|
190
|
+
.option('--stdout', 'Show stdout instead of stderr (rarely needed)')
|
|
185
191
|
.action(async (identifier: string, options) => {
|
|
186
192
|
try {
|
|
187
193
|
await logsCommand(identifier, options);
|
package/src/commands/logs.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
|
+
import * as readline from 'readline';
|
|
4
|
+
import * as fs from 'fs';
|
|
3
5
|
import { stateManager } from '../lib/state-manager';
|
|
4
6
|
import { fileExists } from '../utils/file-utils';
|
|
5
7
|
import { execCommand } from '../utils/process-utils';
|
|
8
|
+
import { logParser } from '../utils/log-parser';
|
|
6
9
|
|
|
7
10
|
interface LogsOptions {
|
|
8
11
|
follow?: boolean;
|
|
9
12
|
lines?: number;
|
|
10
13
|
errors?: boolean;
|
|
14
|
+
verbose?: boolean;
|
|
15
|
+
http?: boolean;
|
|
16
|
+
stdout?: boolean;
|
|
17
|
+
filter?: string;
|
|
11
18
|
}
|
|
12
19
|
|
|
13
20
|
export async function logsCommand(identifier: string, options: LogsOptions): Promise<void> {
|
|
@@ -17,9 +24,9 @@ export async function logsCommand(identifier: string, options: LogsOptions): Pro
|
|
|
17
24
|
throw new Error(`Server not found: ${identifier}\n\nUse: llamacpp ps`);
|
|
18
25
|
}
|
|
19
26
|
|
|
20
|
-
// Determine log file
|
|
21
|
-
const logPath = options.
|
|
22
|
-
const logType = options.
|
|
27
|
+
// Determine log file (default to stderr where verbose logs go)
|
|
28
|
+
const logPath = options.stdout ? server.stdoutPath : server.stderrPath;
|
|
29
|
+
const logType = options.stdout ? 'stdout' : 'stderr';
|
|
23
30
|
|
|
24
31
|
// Check if log file exists
|
|
25
32
|
if (!(await fileExists(logPath))) {
|
|
@@ -28,34 +35,134 @@ export async function logsCommand(identifier: string, options: LogsOptions): Pro
|
|
|
28
35
|
return;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
// Determine filter pattern and mode
|
|
39
|
+
let filterPattern: string | null = null;
|
|
40
|
+
let filterDesc = '';
|
|
41
|
+
let useCompactMode = false;
|
|
42
|
+
|
|
43
|
+
if (options.verbose) {
|
|
44
|
+
// Show everything (no filter)
|
|
45
|
+
filterDesc = ' (all messages)';
|
|
46
|
+
} else if (options.errors) {
|
|
47
|
+
// Show only errors
|
|
48
|
+
filterPattern = 'error|Error|ERROR|failed|Failed|FAILED';
|
|
49
|
+
filterDesc = ' (errors only)';
|
|
50
|
+
} else if (options.http) {
|
|
51
|
+
// Full HTTP JSON logs
|
|
52
|
+
filterPattern = 'log_server_r';
|
|
53
|
+
filterDesc = ' (HTTP JSON)';
|
|
54
|
+
} else if (options.filter) {
|
|
55
|
+
// Custom filter
|
|
56
|
+
filterPattern = options.filter;
|
|
57
|
+
filterDesc = ` (filter: ${options.filter})`;
|
|
58
|
+
} else {
|
|
59
|
+
// Default: Compact one-liner format
|
|
60
|
+
filterPattern = 'log_server_r';
|
|
61
|
+
filterDesc = ' (compact)';
|
|
62
|
+
useCompactMode = true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(chalk.blue(`📋 Logs for ${server.modelName} (${logType}${filterDesc})`));
|
|
32
66
|
console.log(chalk.dim(` ${logPath}\n`));
|
|
33
67
|
|
|
34
68
|
if (options.follow) {
|
|
35
|
-
// Follow logs in real-time
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
69
|
+
// Follow logs in real-time with optional filtering
|
|
70
|
+
if (useCompactMode) {
|
|
71
|
+
// Compact mode with follow: parse lines in real-time
|
|
72
|
+
const tailProcess = spawn('tail', ['-f', logPath]);
|
|
73
|
+
const rl = readline.createInterface({
|
|
74
|
+
input: tailProcess.stdout,
|
|
75
|
+
crlfDelay: Infinity,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
rl.on('line', (line) => {
|
|
79
|
+
if (line.includes('log_server_r')) {
|
|
80
|
+
logParser.processLine(line, (compactLine) => {
|
|
81
|
+
console.log(compactLine);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Handle Ctrl+C gracefully
|
|
87
|
+
process.on('SIGINT', () => {
|
|
88
|
+
tailProcess.kill();
|
|
89
|
+
rl.close();
|
|
90
|
+
console.log();
|
|
91
|
+
process.exit(0);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
tailProcess.on('exit', () => {
|
|
95
|
+
process.exit(0);
|
|
96
|
+
});
|
|
97
|
+
} else if (filterPattern) {
|
|
98
|
+
// Use tail piped to grep for filtering
|
|
99
|
+
const grepProcess = spawn('sh', ['-c', `tail -f "${logPath}" | grep --line-buffered -E "${filterPattern}"`], {
|
|
100
|
+
stdio: 'inherit',
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Handle Ctrl+C gracefully
|
|
104
|
+
process.on('SIGINT', () => {
|
|
105
|
+
grepProcess.kill();
|
|
106
|
+
console.log();
|
|
107
|
+
process.exit(0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
grepProcess.on('exit', () => {
|
|
111
|
+
process.exit(0);
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
// No filter, just tail
|
|
115
|
+
const tail = spawn('tail', ['-f', logPath], {
|
|
116
|
+
stdio: 'inherit',
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
process.on('SIGINT', () => {
|
|
120
|
+
tail.kill();
|
|
121
|
+
console.log();
|
|
122
|
+
process.exit(0);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
tail.on('exit', () => {
|
|
126
|
+
process.exit(0);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
51
129
|
} else {
|
|
52
|
-
// Show last N lines
|
|
130
|
+
// Show last N lines with optional filtering
|
|
53
131
|
const lines = options.lines || 50;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
132
|
+
|
|
133
|
+
if (useCompactMode) {
|
|
134
|
+
// Compact mode: read file and parse
|
|
135
|
+
try {
|
|
136
|
+
const command = `tail -n ${lines * 3} "${logPath}" | grep -E "log_server_r"`;
|
|
137
|
+
const output = await execCommand(command);
|
|
138
|
+
const logLines = output.split('\n').filter((l) => l.trim());
|
|
139
|
+
|
|
140
|
+
for (const line of logLines) {
|
|
141
|
+
logParser.processLine(line, (compactLine) => {
|
|
142
|
+
console.log(compactLine);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new Error(`Failed to read logs: ${(error as Error).message}`);
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
// Regular filtering
|
|
150
|
+
try {
|
|
151
|
+
let command: string;
|
|
152
|
+
|
|
153
|
+
if (filterPattern) {
|
|
154
|
+
// Use tail piped to grep
|
|
155
|
+
command = `tail -n ${lines} "${logPath}" | grep -E "${filterPattern}"`;
|
|
156
|
+
} else {
|
|
157
|
+
// No filter
|
|
158
|
+
command = `tail -n ${lines} "${logPath}"`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const output = await execCommand(command);
|
|
162
|
+
console.log(output);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
throw new Error(`Failed to read logs: ${(error as Error).message}`);
|
|
165
|
+
}
|
|
59
166
|
}
|
|
60
167
|
}
|
|
61
168
|
}
|
package/src/commands/ps.ts
CHANGED
|
@@ -2,7 +2,8 @@ import chalk from 'chalk';
|
|
|
2
2
|
import Table from 'cli-table3';
|
|
3
3
|
import { stateManager } from '../lib/state-manager';
|
|
4
4
|
import { statusChecker } from '../lib/status-checker';
|
|
5
|
-
import { formatUptime } from '../utils/format-utils';
|
|
5
|
+
import { formatUptime, formatBytes } from '../utils/format-utils';
|
|
6
|
+
import { getProcessMemory } from '../utils/process-utils';
|
|
6
7
|
|
|
7
8
|
export async function psCommand(): Promise<void> {
|
|
8
9
|
const servers = await stateManager.getAllServers();
|
|
@@ -18,7 +19,7 @@ export async function psCommand(): Promise<void> {
|
|
|
18
19
|
const updated = await statusChecker.updateAllServerStatuses();
|
|
19
20
|
|
|
20
21
|
const table = new Table({
|
|
21
|
-
head: ['SERVER ID', 'MODEL', 'PORT', 'STATUS', 'PID', 'UPTIME'],
|
|
22
|
+
head: ['SERVER ID', 'MODEL', 'PORT', 'STATUS', 'PID', 'MEMORY', 'UPTIME'],
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
let runningCount = 0;
|
|
@@ -51,12 +52,22 @@ export async function psCommand(): Promise<void> {
|
|
|
51
52
|
? formatUptime(server.lastStarted)
|
|
52
53
|
: '-';
|
|
53
54
|
|
|
55
|
+
// Get memory usage for running servers
|
|
56
|
+
let memoryText = '-';
|
|
57
|
+
if (server.status === 'running' && server.pid) {
|
|
58
|
+
const memoryBytes = await getProcessMemory(server.pid);
|
|
59
|
+
if (memoryBytes !== null) {
|
|
60
|
+
memoryText = formatBytes(memoryBytes);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
54
64
|
table.push([
|
|
55
65
|
server.id,
|
|
56
66
|
server.modelName,
|
|
57
67
|
server.port.toString(),
|
|
58
68
|
statusColor(statusText),
|
|
59
69
|
server.pid?.toString() || '-',
|
|
70
|
+
memoryText,
|
|
60
71
|
uptime,
|
|
61
72
|
]);
|
|
62
73
|
}
|