@timo972/cc-router 0.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 +96 -0
- package/Dockerfile +42 -0
- package/LICENSE +21 -0
- package/README.md +716 -0
- package/accounts.example.json +25 -0
- package/dist/cli/cmd-accounts.js +248 -0
- package/dist/cli/cmd-client.js +612 -0
- package/dist/cli/cmd-configure.js +145 -0
- package/dist/cli/cmd-docker.js +140 -0
- package/dist/cli/cmd-logs.js +85 -0
- package/dist/cli/cmd-models.js +125 -0
- package/dist/cli/cmd-service.js +193 -0
- package/dist/cli/cmd-setup.js +501 -0
- package/dist/cli/cmd-start.js +318 -0
- package/dist/cli/cmd-status.js +177 -0
- package/dist/cli/cmd-stop.js +100 -0
- package/dist/cli/cmd-telemetry.js +58 -0
- package/dist/cli/cmd-update.js +37 -0
- package/dist/cli/index.js +59 -0
- package/dist/config/manager.js +262 -0
- package/dist/config/paths.js +21 -0
- package/dist/config/telemetry.js +64 -0
- package/dist/daemon/launcher.js +163 -0
- package/dist/daemon/pid.js +98 -0
- package/dist/daemon/service.js +260 -0
- package/dist/interceptor/mitmproxy-manager.js +616 -0
- package/dist/protocol/anthropic-to-openai.js +51 -0
- package/dist/protocol/anthropic-types.js +1 -0
- package/dist/protocol/model-ref.js +36 -0
- package/dist/protocol/model-routing-config.js +30 -0
- package/dist/protocol/openai-response-to-anthropic.js +20 -0
- package/dist/protocol/openai-responses-types.js +1 -0
- package/dist/protocol/openai-stream-to-anthropic.js +75 -0
- package/dist/protocol/openai-to-anthropic.js +61 -0
- package/dist/protocol/sse.js +17 -0
- package/dist/providers/model-discovery.js +71 -0
- package/dist/providers/openai/account-pool.js +11 -0
- package/dist/providers/openai/account-record.js +33 -0
- package/dist/providers/openai/codex-transport.js +36 -0
- package/dist/providers/openai/device-oauth.js +116 -0
- package/dist/providers/openai/token-refresher.js +56 -0
- package/dist/providers/route-selector.js +8 -0
- package/dist/providers/types.js +1 -0
- package/dist/proxy/account-deletion.js +44 -0
- package/dist/proxy/anthropic-proxy.js +26 -0
- package/dist/proxy/anthropic-routing.js +90 -0
- package/dist/proxy/lease-lifecycle.js +68 -0
- package/dist/proxy/logger.js +39 -0
- package/dist/proxy/messages-cross-route.js +179 -0
- package/dist/proxy/models-server.js +150 -0
- package/dist/proxy/provider-routing.js +14 -0
- package/dist/proxy/responses-server.js +91 -0
- package/dist/proxy/server.js +875 -0
- package/dist/proxy/session-router.js +171 -0
- package/dist/proxy/stats.js +25 -0
- package/dist/proxy/stream-lifecycle.js +83 -0
- package/dist/proxy/token-pool.js +407 -0
- package/dist/proxy/token-refresher.js +209 -0
- package/dist/proxy/types.js +29 -0
- package/dist/ui/Dashboard.js +640 -0
- package/dist/ui/accountsApi.js +48 -0
- package/dist/ui/modelsApi.js +47 -0
- package/dist/utils/claude-config.js +185 -0
- package/dist/utils/codex-config.js +62 -0
- package/dist/utils/network.js +16 -0
- package/dist/utils/platform.js +13 -0
- package/dist/utils/self-update.js +239 -0
- package/dist/utils/telemetry.js +88 -0
- package/dist/utils/token-extractor.js +95 -0
- package/dist/utils/token-validator.js +26 -0
- package/docker-compose.yml +63 -0
- package/litellm-config.yaml +44 -0
- package/package.json +69 -0
- package/src/interceptor/addon.py +78 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { execFile } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { detectPlatform } from "../utils/platform.js";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
// Resolve the path to the compiled CLI entry point
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
const CLI_ENTRY = join(__dirname, "index.js");
|
|
12
|
+
export function registerService(program) {
|
|
13
|
+
const service = program
|
|
14
|
+
.command("service")
|
|
15
|
+
.description("Manage cc-router as a system service (auto-start on boot via PM2)");
|
|
16
|
+
service
|
|
17
|
+
.command("install")
|
|
18
|
+
.description("Register cc-router to start automatically on system boot")
|
|
19
|
+
.action(async () => {
|
|
20
|
+
console.log(chalk.cyan("\nInstalling cc-router as a system service...\n"));
|
|
21
|
+
// 1. Verify PM2 is installed
|
|
22
|
+
const pm2Version = await getPm2Version();
|
|
23
|
+
if (!pm2Version) {
|
|
24
|
+
console.log(chalk.yellow("PM2 not found. Installing globally..."));
|
|
25
|
+
try {
|
|
26
|
+
await execFileAsync("npm", ["install", "-g", "pm2"]);
|
|
27
|
+
console.log(chalk.green("✓ PM2 installed"));
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
console.error(chalk.red("✗ Failed to install PM2:"), err.message);
|
|
31
|
+
console.error(chalk.gray(" Try manually: npm install -g pm2"));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.log(chalk.green(`✓ PM2 ${pm2Version} found`));
|
|
37
|
+
}
|
|
38
|
+
// 2. Register cc-router in PM2
|
|
39
|
+
console.log(chalk.gray("\nRegistering cc-router in PM2..."));
|
|
40
|
+
try {
|
|
41
|
+
await execFileAsync("pm2", [
|
|
42
|
+
"start", CLI_ENTRY,
|
|
43
|
+
"--name", "cc-router",
|
|
44
|
+
"--interpreter", process.execPath,
|
|
45
|
+
"--max-memory-restart", "500M", // restart if memory exceeds 500MB
|
|
46
|
+
"--",
|
|
47
|
+
"start",
|
|
48
|
+
]);
|
|
49
|
+
console.log(chalk.green("✓ cc-router registered in PM2"));
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const msg = err.message;
|
|
53
|
+
// PM2 may already have the process — try restart instead
|
|
54
|
+
if (msg.includes("already")) {
|
|
55
|
+
await execFileAsync("pm2", ["restart", "cc-router"]);
|
|
56
|
+
console.log(chalk.green("✓ cc-router restarted in PM2"));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.error(chalk.red("✗ Failed to start in PM2:"), msg);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// 3. Save process list so it survives reboots
|
|
64
|
+
await execFileAsync("pm2", ["save"]);
|
|
65
|
+
console.log(chalk.green("✓ PM2 process list saved"));
|
|
66
|
+
// 4. Generate and apply startup hook
|
|
67
|
+
console.log(chalk.gray("\nConfiguring system startup hook..."));
|
|
68
|
+
console.log(chalk.gray("(may ask for your password on Linux/macOS)\n"));
|
|
69
|
+
try {
|
|
70
|
+
const { stdout, stderr } = await execFileAsync("pm2", ["startup"]);
|
|
71
|
+
const output = stdout + stderr;
|
|
72
|
+
// PM2 prints a sudo command to run if it can't apply it automatically
|
|
73
|
+
const sudoMatch = output.match(/sudo\s+.+/);
|
|
74
|
+
if (sudoMatch) {
|
|
75
|
+
console.log(chalk.yellow("Run this command to complete startup registration:"));
|
|
76
|
+
console.log(chalk.white(` ${sudoMatch[0]}`));
|
|
77
|
+
console.log(chalk.gray("\nThen run: pm2 save"));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log(chalk.green("✓ System startup hook configured"));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const msg = err;
|
|
85
|
+
const combined = (msg.stdout ?? "") + (msg.stderr ?? "");
|
|
86
|
+
const sudoMatch = combined.match(/sudo\s+.+/);
|
|
87
|
+
if (sudoMatch) {
|
|
88
|
+
console.log(chalk.yellow("\nRun this command to complete startup registration:"));
|
|
89
|
+
console.log(chalk.white(` ${sudoMatch[0]}`));
|
|
90
|
+
console.log(chalk.gray("\nThen run: pm2 save"));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(chalk.yellow("⚠ Could not configure startup hook automatically."));
|
|
94
|
+
printManualStartupInstructions();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
printServiceInfo();
|
|
98
|
+
});
|
|
99
|
+
service
|
|
100
|
+
.command("uninstall")
|
|
101
|
+
.description("Remove cc-router from system startup")
|
|
102
|
+
.action(async () => {
|
|
103
|
+
let removed = false;
|
|
104
|
+
try {
|
|
105
|
+
await execFileAsync("pm2", ["stop", "cc-router"]);
|
|
106
|
+
await execFileAsync("pm2", ["delete", "cc-router"]);
|
|
107
|
+
await execFileAsync("pm2", ["save"]);
|
|
108
|
+
console.log(chalk.green("✓ cc-router removed from PM2"));
|
|
109
|
+
removed = true;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
console.log(chalk.gray("cc-router was not registered in PM2."));
|
|
113
|
+
}
|
|
114
|
+
// Remove Claude Code proxy config too
|
|
115
|
+
const { removeClaudeSettings } = await import("../utils/claude-config.js");
|
|
116
|
+
const { readClaudeProxySettings } = await import("../utils/claude-config.js");
|
|
117
|
+
if (readClaudeProxySettings().baseUrl) {
|
|
118
|
+
removeClaudeSettings();
|
|
119
|
+
console.log(chalk.green("✓ Removed proxy settings from ~/.claude/settings.json"));
|
|
120
|
+
removed = true;
|
|
121
|
+
}
|
|
122
|
+
if (removed) {
|
|
123
|
+
console.log(chalk.green("\n✓ Service uninstalled. Claude Code will use normal authentication.\n"));
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.log(chalk.gray("\nNothing to uninstall.\n"));
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
service
|
|
130
|
+
.command("status")
|
|
131
|
+
.description("Show the service status in PM2")
|
|
132
|
+
.action(async () => {
|
|
133
|
+
try {
|
|
134
|
+
const { stdout } = await execFileAsync("pm2", ["info", "cc-router"]);
|
|
135
|
+
console.log(stdout);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
console.log(chalk.yellow("cc-router is not registered as a PM2 service."));
|
|
139
|
+
console.log(chalk.gray(" Install it with: cc-router service install"));
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
service
|
|
143
|
+
.command("logs")
|
|
144
|
+
.description("Tail the proxy logs from PM2")
|
|
145
|
+
.option("--lines <n>", "Number of lines to show", "50")
|
|
146
|
+
.action(async (opts) => {
|
|
147
|
+
try {
|
|
148
|
+
// pm2 logs streams continuously — spawn it directly so it inherits stdio
|
|
149
|
+
const { spawn } = await import("child_process");
|
|
150
|
+
const child = spawn("pm2", ["logs", "cc-router", "--lines", opts.lines], {
|
|
151
|
+
stdio: "inherit",
|
|
152
|
+
});
|
|
153
|
+
child.on("error", () => {
|
|
154
|
+
console.log(chalk.yellow("PM2 not found. Is cc-router installed as a service?"));
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
console.error(chalk.red("Could not tail logs."));
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
163
|
+
async function getPm2Version() {
|
|
164
|
+
try {
|
|
165
|
+
const { stdout } = await execFileAsync("pm2", ["--version"]);
|
|
166
|
+
return stdout.trim();
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function printServiceInfo() {
|
|
173
|
+
console.log(chalk.bold("\n━━━ Service installed ━━━━━━━━━━━━━━━━━━━━━━━━\n"));
|
|
174
|
+
console.log(` Check status: ${chalk.cyan("cc-router service status")}`);
|
|
175
|
+
console.log(` View logs: ${chalk.cyan("cc-router service logs")}`);
|
|
176
|
+
console.log(` Stop & remove: ${chalk.cyan("cc-router service uninstall")}`);
|
|
177
|
+
console.log(` Restart: ${chalk.cyan("pm2 restart cc-router")}`);
|
|
178
|
+
console.log();
|
|
179
|
+
}
|
|
180
|
+
function printManualStartupInstructions() {
|
|
181
|
+
const platform = detectPlatform();
|
|
182
|
+
console.log(chalk.gray("\n To configure auto-start manually:"));
|
|
183
|
+
if (platform === "macos") {
|
|
184
|
+
console.log(chalk.gray(" macOS (launchd): pm2 startup launchd && pm2 save"));
|
|
185
|
+
}
|
|
186
|
+
else if (platform === "linux") {
|
|
187
|
+
console.log(chalk.gray(" Linux (systemd): pm2 startup systemd && pm2 save"));
|
|
188
|
+
console.log(chalk.gray(" Then: sudo systemctl enable pm2-$(whoami)"));
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.log(chalk.gray(" Windows: see https://github.com/jessety/pm2-installer"));
|
|
192
|
+
}
|
|
193
|
+
}
|