@appkit/llamacpp-cli 1.8.0 → 1.9.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 +42 -0
- package/README.md +80 -0
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/router/config.d.ts +10 -0
- package/dist/commands/router/config.d.ts.map +1 -0
- package/dist/commands/router/config.js +95 -0
- package/dist/commands/router/config.js.map +1 -0
- package/dist/commands/router/restart.d.ts +2 -0
- package/dist/commands/router/restart.d.ts.map +1 -0
- package/dist/commands/router/restart.js +39 -0
- package/dist/commands/router/restart.js.map +1 -0
- package/dist/commands/router/start.d.ts +2 -0
- package/dist/commands/router/start.d.ts.map +1 -0
- package/dist/commands/router/start.js +60 -0
- package/dist/commands/router/start.js.map +1 -0
- package/dist/commands/router/status.d.ts +2 -0
- package/dist/commands/router/status.d.ts.map +1 -0
- package/dist/commands/router/status.js +116 -0
- package/dist/commands/router/status.js.map +1 -0
- package/dist/commands/router/stop.d.ts +2 -0
- package/dist/commands/router/stop.d.ts.map +1 -0
- package/dist/commands/router/stop.js +36 -0
- package/dist/commands/router/stop.js.map +1 -0
- package/dist/lib/router-manager.d.ts +103 -0
- package/dist/lib/router-manager.d.ts.map +1 -0
- package/dist/lib/router-manager.js +393 -0
- package/dist/lib/router-manager.js.map +1 -0
- package/dist/lib/router-server.d.ts +52 -0
- package/dist/lib/router-server.d.ts.map +1 -0
- package/dist/lib/router-server.js +373 -0
- package/dist/lib/router-server.js.map +1 -0
- package/dist/types/router-config.d.ts +18 -0
- package/dist/types/router-config.d.ts.map +1 -0
- package/dist/types/router-config.js +3 -0
- package/dist/types/router-config.js.map +1 -0
- package/package.json +1 -1
- package/src/cli.ts +80 -0
- package/src/commands/router/config.ts +109 -0
- package/src/commands/router/restart.ts +36 -0
- package/src/commands/router/start.ts +60 -0
- package/src/commands/router/status.ts +119 -0
- package/src/commands/router/stop.ts +33 -0
- package/src/lib/router-manager.ts +413 -0
- package/src/lib/router-server.ts +407 -0
- package/src/types/router-config.ts +24 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.routerStatusCommand = routerStatusCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const router_manager_1 = require("../../lib/router-manager");
|
|
9
|
+
const state_manager_1 = require("../../lib/state-manager");
|
|
10
|
+
async function routerStatusCommand() {
|
|
11
|
+
try {
|
|
12
|
+
// Get router status
|
|
13
|
+
const result = await router_manager_1.routerManager.getStatus();
|
|
14
|
+
if (!result) {
|
|
15
|
+
console.log(chalk_1.default.yellow('Router not configured'));
|
|
16
|
+
console.log();
|
|
17
|
+
console.log(chalk_1.default.dim('Create and start router:'));
|
|
18
|
+
console.log(chalk_1.default.dim(' llamacpp router start'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const { config, status } = result;
|
|
22
|
+
// Calculate uptime if running
|
|
23
|
+
let uptime = 'N/A';
|
|
24
|
+
if (status.isRunning && config.lastStarted) {
|
|
25
|
+
const startTime = new Date(config.lastStarted).getTime();
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
const uptimeSeconds = Math.floor((now - startTime) / 1000);
|
|
28
|
+
const hours = Math.floor(uptimeSeconds / 3600);
|
|
29
|
+
const minutes = Math.floor((uptimeSeconds % 3600) / 60);
|
|
30
|
+
const seconds = uptimeSeconds % 60;
|
|
31
|
+
if (hours > 0) {
|
|
32
|
+
uptime = `${hours}h ${minutes}m`;
|
|
33
|
+
}
|
|
34
|
+
else if (minutes > 0) {
|
|
35
|
+
uptime = `${minutes}m ${seconds}s`;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
uptime = `${seconds}s`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Get running servers
|
|
42
|
+
const servers = await state_manager_1.stateManager.getAllServers();
|
|
43
|
+
const runningServers = servers.filter(s => s.status === 'running');
|
|
44
|
+
// Display status
|
|
45
|
+
console.log();
|
|
46
|
+
console.log(chalk_1.default.bold('Router Status'));
|
|
47
|
+
console.log(chalk_1.default.dim('─'.repeat(50)));
|
|
48
|
+
console.log();
|
|
49
|
+
// Status badge
|
|
50
|
+
const statusColor = status.isRunning ? chalk_1.default.green : chalk_1.default.gray;
|
|
51
|
+
const statusBadge = status.isRunning ? '● RUN' : '○ OFF';
|
|
52
|
+
console.log(`Status: ${statusColor(statusBadge)}`);
|
|
53
|
+
if (status.isRunning) {
|
|
54
|
+
console.log(`PID: ${status.pid || 'N/A'}`);
|
|
55
|
+
console.log(`Uptime: ${uptime}`);
|
|
56
|
+
}
|
|
57
|
+
console.log(`Port: ${config.port}`);
|
|
58
|
+
console.log(`Host: ${config.host}`);
|
|
59
|
+
console.log(`Endpoint: http://${config.host}:${config.port}`);
|
|
60
|
+
console.log();
|
|
61
|
+
// Available models
|
|
62
|
+
console.log(chalk_1.default.bold('Available Models'));
|
|
63
|
+
console.log(chalk_1.default.dim('─'.repeat(50)));
|
|
64
|
+
console.log();
|
|
65
|
+
if (runningServers.length === 0) {
|
|
66
|
+
console.log(chalk_1.default.dim('No running servers found'));
|
|
67
|
+
console.log();
|
|
68
|
+
console.log(chalk_1.default.yellow('⚠️ Start a server first:'));
|
|
69
|
+
console.log(chalk_1.default.dim(' llamacpp server create <model>'));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
runningServers.forEach(server => {
|
|
73
|
+
console.log(` ${chalk_1.default.green('●')} ${server.modelName}`);
|
|
74
|
+
console.log(chalk_1.default.dim(` Port: ${server.port}`));
|
|
75
|
+
console.log(chalk_1.default.dim(` Backend: http://${server.host}:${server.port}`));
|
|
76
|
+
console.log();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// Configuration
|
|
80
|
+
console.log(chalk_1.default.bold('Configuration'));
|
|
81
|
+
console.log(chalk_1.default.dim('─'.repeat(50)));
|
|
82
|
+
console.log();
|
|
83
|
+
console.log(`Health Check Interval: ${config.healthCheckInterval}ms`);
|
|
84
|
+
console.log(`Request Timeout: ${config.requestTimeout}ms`);
|
|
85
|
+
console.log();
|
|
86
|
+
// System paths
|
|
87
|
+
console.log(chalk_1.default.bold('System Paths'));
|
|
88
|
+
console.log(chalk_1.default.dim('─'.repeat(50)));
|
|
89
|
+
console.log();
|
|
90
|
+
console.log(chalk_1.default.dim(`Config: ${config.plistPath.replace(config.label + '.plist', 'router.json').replace('LaunchAgents', '.llamacpp')}`));
|
|
91
|
+
console.log(chalk_1.default.dim(`Plist: ${config.plistPath}`));
|
|
92
|
+
console.log(chalk_1.default.dim(`Stdout: ${config.stdoutPath}`));
|
|
93
|
+
console.log(chalk_1.default.dim(`Stderr: ${config.stderrPath}`));
|
|
94
|
+
console.log();
|
|
95
|
+
// Quick commands
|
|
96
|
+
console.log(chalk_1.default.bold('Quick Commands'));
|
|
97
|
+
console.log(chalk_1.default.dim('─'.repeat(50)));
|
|
98
|
+
console.log();
|
|
99
|
+
if (status.isRunning) {
|
|
100
|
+
console.log(chalk_1.default.dim(' Stop: llamacpp router stop'));
|
|
101
|
+
console.log(chalk_1.default.dim(' Restart: llamacpp router restart'));
|
|
102
|
+
console.log(chalk_1.default.dim(` Logs: tail -f ${config.stderrPath}`));
|
|
103
|
+
console.log(chalk_1.default.dim(' Config: llamacpp router config --port <port> --restart'));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.log(chalk_1.default.dim(' Start: llamacpp router start'));
|
|
107
|
+
console.log(chalk_1.default.dim(' Config: llamacpp router config --port <port>'));
|
|
108
|
+
console.log(chalk_1.default.dim(` Logs: cat ${config.stderrPath}`));
|
|
109
|
+
}
|
|
110
|
+
console.log();
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
throw new Error(`Failed to get router status: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/router/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../../src/commands/router/stop.ts"],"names":[],"mappings":"AAGA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA6BvD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.routerStopCommand = routerStopCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const router_manager_1 = require("../../lib/router-manager");
|
|
9
|
+
async function routerStopCommand() {
|
|
10
|
+
console.log(chalk_1.default.blue('⏹️ Stopping router...'));
|
|
11
|
+
try {
|
|
12
|
+
// Check if router exists
|
|
13
|
+
const config = await router_manager_1.routerManager.loadConfig();
|
|
14
|
+
if (!config) {
|
|
15
|
+
throw new Error('Router configuration not found. Use "llamacpp router start" to create it.');
|
|
16
|
+
}
|
|
17
|
+
// Check if already stopped
|
|
18
|
+
if (config.status !== 'running') {
|
|
19
|
+
console.log(chalk_1.default.yellow('⚠️ Router is not running'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Stop router
|
|
23
|
+
await router_manager_1.routerManager.stop();
|
|
24
|
+
// Display success
|
|
25
|
+
console.log();
|
|
26
|
+
console.log(chalk_1.default.green('✅ Router stopped successfully'));
|
|
27
|
+
console.log();
|
|
28
|
+
console.log(chalk_1.default.dim('Quick commands:'));
|
|
29
|
+
console.log(chalk_1.default.dim(' Start: llamacpp router start'));
|
|
30
|
+
console.log(chalk_1.default.dim(' Status: llamacpp router status'));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new Error(`Failed to stop router: ${error.message}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../../../src/commands/router/stop.ts"],"names":[],"mappings":";;;;;AAGA,8CA6BC;AAhCD,kDAA0B;AAC1B,6DAAyD;AAElD,KAAK,UAAU,iBAAiB;IACrC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAElD,IAAI,CAAC;QACH,yBAAyB;QACzB,MAAM,MAAM,GAAG,MAAM,8BAAa,CAAC,UAAU,EAAE,CAAC;QAChD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;QAC/F,CAAC;QAED,2BAA2B;QAC3B,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC;YACvD,OAAO;QACT,CAAC;QAED,cAAc;QACd,MAAM,8BAAa,CAAC,IAAI,EAAE,CAAC;QAE3B,kBAAkB;QAClB,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,0BAA2B,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { RouterConfig } from '../types/router-config';
|
|
2
|
+
export interface RouterServiceStatus {
|
|
3
|
+
isRunning: boolean;
|
|
4
|
+
pid: number | null;
|
|
5
|
+
exitCode: number | null;
|
|
6
|
+
lastExitReason?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class RouterManager {
|
|
9
|
+
private configDir;
|
|
10
|
+
private logsDir;
|
|
11
|
+
private configPath;
|
|
12
|
+
private launchAgentsDir;
|
|
13
|
+
constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Initialize router directories
|
|
16
|
+
*/
|
|
17
|
+
initialize(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Get default router configuration
|
|
20
|
+
*/
|
|
21
|
+
getDefaultConfig(): RouterConfig;
|
|
22
|
+
/**
|
|
23
|
+
* Load router configuration
|
|
24
|
+
*/
|
|
25
|
+
loadConfig(): Promise<RouterConfig | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Save router configuration
|
|
28
|
+
*/
|
|
29
|
+
saveConfig(config: RouterConfig): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Update router configuration with partial changes
|
|
32
|
+
*/
|
|
33
|
+
updateConfig(updates: Partial<RouterConfig>): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Delete router configuration
|
|
36
|
+
*/
|
|
37
|
+
deleteConfig(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Generate plist XML content for the router
|
|
40
|
+
*/
|
|
41
|
+
generatePlist(config: RouterConfig): string;
|
|
42
|
+
/**
|
|
43
|
+
* Create and write plist file
|
|
44
|
+
*/
|
|
45
|
+
createPlist(config: RouterConfig): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Delete plist file
|
|
48
|
+
*/
|
|
49
|
+
deletePlist(config: RouterConfig): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Load service (register with launchctl)
|
|
52
|
+
*/
|
|
53
|
+
loadService(plistPath: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Unload service (unregister from launchctl)
|
|
56
|
+
*/
|
|
57
|
+
unloadService(plistPath: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Start service
|
|
60
|
+
*/
|
|
61
|
+
startService(label: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Stop service
|
|
64
|
+
*/
|
|
65
|
+
stopService(label: string): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Get service status from launchctl
|
|
68
|
+
*/
|
|
69
|
+
getServiceStatus(label: string): Promise<RouterServiceStatus>;
|
|
70
|
+
/**
|
|
71
|
+
* Interpret exit code to human-readable reason
|
|
72
|
+
*/
|
|
73
|
+
private interpretExitCode;
|
|
74
|
+
/**
|
|
75
|
+
* Wait for service to start (with timeout)
|
|
76
|
+
*/
|
|
77
|
+
waitForServiceStart(label: string, timeoutMs?: number): Promise<boolean>;
|
|
78
|
+
/**
|
|
79
|
+
* Wait for service to stop (with timeout)
|
|
80
|
+
*/
|
|
81
|
+
waitForServiceStop(label: string, timeoutMs?: number): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* Start router service
|
|
84
|
+
*/
|
|
85
|
+
start(): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Stop router service
|
|
88
|
+
*/
|
|
89
|
+
stop(): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Restart router service
|
|
92
|
+
*/
|
|
93
|
+
restart(): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Get router status
|
|
96
|
+
*/
|
|
97
|
+
getStatus(): Promise<{
|
|
98
|
+
config: RouterConfig;
|
|
99
|
+
status: RouterServiceStatus;
|
|
100
|
+
} | null>;
|
|
101
|
+
}
|
|
102
|
+
export declare const routerManager: RouterManager;
|
|
103
|
+
//# sourceMappingURL=router-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-manager.d.ts","sourceRoot":"","sources":["../../src/lib/router-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAatD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,eAAe,CAAS;;IAShC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;OAEG;IACH,gBAAgB,IAAI,YAAY;IAgBhC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAOhD;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;IACG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IASjE;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAMnC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM;IAkE3C;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtD;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtD;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrD;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;OAEG;IACG,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAyCnE;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAY5E;;OAEG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAY3E;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoD5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB3B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,mBAAmB,CAAA;KAAE,GAAG,IAAI,CAAC;CASzF;AAGD,eAAO,MAAM,aAAa,eAAsB,CAAC"}
|
|
@@ -0,0 +1,393 @@
|
|
|
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.routerManager = exports.RouterManager = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs = __importStar(require("fs/promises"));
|
|
39
|
+
const process_utils_1 = require("../utils/process-utils");
|
|
40
|
+
const file_utils_1 = require("../utils/file-utils");
|
|
41
|
+
class RouterManager {
|
|
42
|
+
constructor() {
|
|
43
|
+
this.configDir = (0, file_utils_1.getConfigDir)();
|
|
44
|
+
this.logsDir = (0, file_utils_1.getLogsDir)();
|
|
45
|
+
this.configPath = path.join(this.configDir, 'router.json');
|
|
46
|
+
this.launchAgentsDir = (0, file_utils_1.getLaunchAgentsDir)();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Initialize router directories
|
|
50
|
+
*/
|
|
51
|
+
async initialize() {
|
|
52
|
+
await (0, file_utils_1.ensureDir)(this.configDir);
|
|
53
|
+
await (0, file_utils_1.ensureDir)(this.logsDir);
|
|
54
|
+
await (0, file_utils_1.ensureDir)(this.launchAgentsDir);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get default router configuration
|
|
58
|
+
*/
|
|
59
|
+
getDefaultConfig() {
|
|
60
|
+
return {
|
|
61
|
+
id: 'router',
|
|
62
|
+
port: 9100,
|
|
63
|
+
host: '127.0.0.1',
|
|
64
|
+
label: 'com.llama.router',
|
|
65
|
+
plistPath: path.join(this.launchAgentsDir, 'com.llama.router.plist'),
|
|
66
|
+
stdoutPath: path.join(this.logsDir, 'router.stdout'),
|
|
67
|
+
stderrPath: path.join(this.logsDir, 'router.stderr'),
|
|
68
|
+
healthCheckInterval: 5000,
|
|
69
|
+
requestTimeout: 120000,
|
|
70
|
+
status: 'stopped',
|
|
71
|
+
createdAt: new Date().toISOString(),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Load router configuration
|
|
76
|
+
*/
|
|
77
|
+
async loadConfig() {
|
|
78
|
+
if (!(await (0, file_utils_1.fileExists)(this.configPath))) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return await (0, file_utils_1.readJson)(this.configPath);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Save router configuration
|
|
85
|
+
*/
|
|
86
|
+
async saveConfig(config) {
|
|
87
|
+
await (0, file_utils_1.writeJsonAtomic)(this.configPath, config);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Update router configuration with partial changes
|
|
91
|
+
*/
|
|
92
|
+
async updateConfig(updates) {
|
|
93
|
+
const existingConfig = await this.loadConfig();
|
|
94
|
+
if (!existingConfig) {
|
|
95
|
+
throw new Error('Router configuration not found');
|
|
96
|
+
}
|
|
97
|
+
const updatedConfig = { ...existingConfig, ...updates };
|
|
98
|
+
await this.saveConfig(updatedConfig);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Delete router configuration
|
|
102
|
+
*/
|
|
103
|
+
async deleteConfig() {
|
|
104
|
+
if (await (0, file_utils_1.fileExists)(this.configPath)) {
|
|
105
|
+
await fs.unlink(this.configPath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Generate plist XML content for the router
|
|
110
|
+
*/
|
|
111
|
+
generatePlist(config) {
|
|
112
|
+
// Find the compiled router-server.js file
|
|
113
|
+
// In dev mode (tsx), __dirname is src/lib/
|
|
114
|
+
// In production, __dirname is dist/lib/
|
|
115
|
+
// Always use the compiled dist version for launchctl
|
|
116
|
+
let routerServerPath;
|
|
117
|
+
if (__dirname.includes('/src/')) {
|
|
118
|
+
// Dev mode - point to dist/lib/router-server.js
|
|
119
|
+
const projectRoot = path.resolve(__dirname, '../..');
|
|
120
|
+
routerServerPath = path.join(projectRoot, 'dist/lib/router-server.js');
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Production mode - already in dist/lib/
|
|
124
|
+
routerServerPath = path.join(__dirname, 'router-server.js');
|
|
125
|
+
}
|
|
126
|
+
// Use the current Node.js executable path (resolves symlinks)
|
|
127
|
+
const nodePath = process.execPath;
|
|
128
|
+
const args = [
|
|
129
|
+
nodePath,
|
|
130
|
+
routerServerPath,
|
|
131
|
+
'--config', this.configPath,
|
|
132
|
+
];
|
|
133
|
+
const argsXml = args.map(arg => ` <string>${arg}</string>`).join('\n');
|
|
134
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
135
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
136
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
137
|
+
<plist version="1.0">
|
|
138
|
+
<dict>
|
|
139
|
+
<key>Label</key>
|
|
140
|
+
<string>${config.label}</string>
|
|
141
|
+
|
|
142
|
+
<key>ProgramArguments</key>
|
|
143
|
+
<array>
|
|
144
|
+
${argsXml}
|
|
145
|
+
</array>
|
|
146
|
+
|
|
147
|
+
<key>RunAtLoad</key>
|
|
148
|
+
<false/>
|
|
149
|
+
|
|
150
|
+
<key>KeepAlive</key>
|
|
151
|
+
<dict>
|
|
152
|
+
<key>Crashed</key>
|
|
153
|
+
<true/>
|
|
154
|
+
<key>SuccessfulExit</key>
|
|
155
|
+
<false/>
|
|
156
|
+
</dict>
|
|
157
|
+
|
|
158
|
+
<key>StandardOutPath</key>
|
|
159
|
+
<string>${config.stdoutPath}</string>
|
|
160
|
+
|
|
161
|
+
<key>StandardErrorPath</key>
|
|
162
|
+
<string>${config.stderrPath}</string>
|
|
163
|
+
|
|
164
|
+
<key>WorkingDirectory</key>
|
|
165
|
+
<string>/tmp</string>
|
|
166
|
+
|
|
167
|
+
<key>ThrottleInterval</key>
|
|
168
|
+
<integer>10</integer>
|
|
169
|
+
</dict>
|
|
170
|
+
</plist>
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Create and write plist file
|
|
175
|
+
*/
|
|
176
|
+
async createPlist(config) {
|
|
177
|
+
const plistContent = this.generatePlist(config);
|
|
178
|
+
await (0, file_utils_1.writeFileAtomic)(config.plistPath, plistContent);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Delete plist file
|
|
182
|
+
*/
|
|
183
|
+
async deletePlist(config) {
|
|
184
|
+
if (await (0, file_utils_1.fileExists)(config.plistPath)) {
|
|
185
|
+
await fs.unlink(config.plistPath);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Load service (register with launchctl)
|
|
190
|
+
*/
|
|
191
|
+
async loadService(plistPath) {
|
|
192
|
+
await (0, process_utils_1.execCommand)(`launchctl load "${plistPath}"`);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Unload service (unregister from launchctl)
|
|
196
|
+
*/
|
|
197
|
+
async unloadService(plistPath) {
|
|
198
|
+
try {
|
|
199
|
+
await (0, process_utils_1.execCommand)(`launchctl unload "${plistPath}"`);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
// Ignore errors if service is not loaded
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Start service
|
|
207
|
+
*/
|
|
208
|
+
async startService(label) {
|
|
209
|
+
await (0, process_utils_1.execCommand)(`launchctl start ${label}`);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Stop service
|
|
213
|
+
*/
|
|
214
|
+
async stopService(label) {
|
|
215
|
+
await (0, process_utils_1.execCommand)(`launchctl stop ${label}`);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get service status from launchctl
|
|
219
|
+
*/
|
|
220
|
+
async getServiceStatus(label) {
|
|
221
|
+
try {
|
|
222
|
+
const { stdout } = await (0, process_utils_1.execAsync)(`launchctl list | grep ${label}`);
|
|
223
|
+
const lines = stdout.trim().split('\n');
|
|
224
|
+
for (const line of lines) {
|
|
225
|
+
const parts = line.split(/\s+/);
|
|
226
|
+
if (parts.length >= 3) {
|
|
227
|
+
const pidStr = parts[0].trim();
|
|
228
|
+
const exitCodeStr = parts[1].trim();
|
|
229
|
+
const serviceLabel = parts[2].trim();
|
|
230
|
+
if (serviceLabel === label) {
|
|
231
|
+
const pid = pidStr !== '-' ? parseInt(pidStr, 10) : null;
|
|
232
|
+
const exitCode = exitCodeStr !== '-' ? parseInt(exitCodeStr, 10) : null;
|
|
233
|
+
const isRunning = pid !== null;
|
|
234
|
+
return {
|
|
235
|
+
isRunning,
|
|
236
|
+
pid,
|
|
237
|
+
exitCode,
|
|
238
|
+
lastExitReason: this.interpretExitCode(exitCode),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
isRunning: false,
|
|
245
|
+
pid: null,
|
|
246
|
+
exitCode: null,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
return {
|
|
251
|
+
isRunning: false,
|
|
252
|
+
pid: null,
|
|
253
|
+
exitCode: null,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Interpret exit code to human-readable reason
|
|
259
|
+
*/
|
|
260
|
+
interpretExitCode(code) {
|
|
261
|
+
if (code === null || code === 0)
|
|
262
|
+
return undefined;
|
|
263
|
+
if (code === -9)
|
|
264
|
+
return 'Force killed (SIGKILL)';
|
|
265
|
+
if (code === -15)
|
|
266
|
+
return 'Terminated (SIGTERM)';
|
|
267
|
+
return `Exit code: ${code}`;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Wait for service to start (with timeout)
|
|
271
|
+
*/
|
|
272
|
+
async waitForServiceStart(label, timeoutMs = 5000) {
|
|
273
|
+
const startTime = Date.now();
|
|
274
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
275
|
+
const status = await this.getServiceStatus(label);
|
|
276
|
+
if (status.isRunning) {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Wait for service to stop (with timeout)
|
|
285
|
+
*/
|
|
286
|
+
async waitForServiceStop(label, timeoutMs = 5000) {
|
|
287
|
+
const startTime = Date.now();
|
|
288
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
289
|
+
const status = await this.getServiceStatus(label);
|
|
290
|
+
if (!status.isRunning) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
294
|
+
}
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Start router service
|
|
299
|
+
*/
|
|
300
|
+
async start() {
|
|
301
|
+
await this.initialize();
|
|
302
|
+
let config = await this.loadConfig();
|
|
303
|
+
if (!config) {
|
|
304
|
+
// Create default config
|
|
305
|
+
config = this.getDefaultConfig();
|
|
306
|
+
await this.saveConfig(config);
|
|
307
|
+
}
|
|
308
|
+
// Check if already running
|
|
309
|
+
if (config.status === 'running') {
|
|
310
|
+
throw new Error('Router is already running');
|
|
311
|
+
}
|
|
312
|
+
// Check for throttled state (exit code 78)
|
|
313
|
+
const currentStatus = await this.getServiceStatus(config.label);
|
|
314
|
+
if (currentStatus.exitCode === 78) {
|
|
315
|
+
// Service is throttled - clean up and start fresh
|
|
316
|
+
await this.unloadService(config.plistPath);
|
|
317
|
+
await this.deletePlist(config);
|
|
318
|
+
// Give launchd a moment to clean up
|
|
319
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
320
|
+
}
|
|
321
|
+
// Create plist
|
|
322
|
+
await this.createPlist(config);
|
|
323
|
+
// Load and start service
|
|
324
|
+
try {
|
|
325
|
+
await this.loadService(config.plistPath);
|
|
326
|
+
}
|
|
327
|
+
catch (error) {
|
|
328
|
+
// May already be loaded
|
|
329
|
+
}
|
|
330
|
+
await this.startService(config.label);
|
|
331
|
+
// Wait for startup
|
|
332
|
+
const started = await this.waitForServiceStart(config.label, 5000);
|
|
333
|
+
if (!started) {
|
|
334
|
+
throw new Error('Router failed to start');
|
|
335
|
+
}
|
|
336
|
+
// Update config
|
|
337
|
+
const status = await this.getServiceStatus(config.label);
|
|
338
|
+
await this.updateConfig({
|
|
339
|
+
status: 'running',
|
|
340
|
+
pid: status.pid || undefined,
|
|
341
|
+
lastStarted: new Date().toISOString(),
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Stop router service
|
|
346
|
+
*/
|
|
347
|
+
async stop() {
|
|
348
|
+
const config = await this.loadConfig();
|
|
349
|
+
if (!config) {
|
|
350
|
+
throw new Error('Router configuration not found');
|
|
351
|
+
}
|
|
352
|
+
if (config.status !== 'running') {
|
|
353
|
+
throw new Error('Router is not running');
|
|
354
|
+
}
|
|
355
|
+
// Unload service
|
|
356
|
+
await this.unloadService(config.plistPath);
|
|
357
|
+
// Wait for shutdown
|
|
358
|
+
await this.waitForServiceStop(config.label, 5000);
|
|
359
|
+
// Update config
|
|
360
|
+
await this.updateConfig({
|
|
361
|
+
status: 'stopped',
|
|
362
|
+
pid: undefined,
|
|
363
|
+
lastStopped: new Date().toISOString(),
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Restart router service
|
|
368
|
+
*/
|
|
369
|
+
async restart() {
|
|
370
|
+
try {
|
|
371
|
+
await this.stop();
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
// May not be running
|
|
375
|
+
}
|
|
376
|
+
await this.start();
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Get router status
|
|
380
|
+
*/
|
|
381
|
+
async getStatus() {
|
|
382
|
+
const config = await this.loadConfig();
|
|
383
|
+
if (!config) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
const status = await this.getServiceStatus(config.label);
|
|
387
|
+
return { config, status };
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
exports.RouterManager = RouterManager;
|
|
391
|
+
// Export singleton instance
|
|
392
|
+
exports.routerManager = new RouterManager();
|
|
393
|
+
//# sourceMappingURL=router-manager.js.map
|