-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathproxy.ts
More file actions
113 lines (99 loc) · 3.78 KB
/
Copy pathproxy.ts
File metadata and controls
113 lines (99 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/env node
import { loadConfig, fetchLatestCliVersion } from "@/config.js";
import { createServer } from "@/server.js";
import { saveApiKey, promptForApiKey, readAuthKey, deleteAuth } from "@/auth.js";
import { setupOpenCodeConfig } from "@/setup/opencode.js";
import { setupClaudeCodeConfig } from "@/setup/claude-code.js";
import { logger, initLogger } from "@/logger.js";
const args = process.argv.slice(2);
if (args[0] === "auth") {
const sub = args[1];
if (sub === "login") {
const force = args.includes("--force");
const existing = readAuthKey();
if (existing && !force) {
console.log("\n You are already logged in. Use `auth login --force` to overwrite.\n");
process.exit(0);
}
console.log("\n Get your API key from https://commandcode.ai/settings\n");
const key = await promptForApiKey();
if (!key) {
console.error(" FATAL: API key is required.\n");
process.exit(1);
}
saveApiKey(key);
console.log(" ✓ API key saved to ~/.config/commandcode-api-proxy/auth.json\n");
} else if (sub === "logout") {
deleteAuth();
console.log("\n ✓ API key removed\n");
} else {
console.error("\n Usage: commandcode-api-proxy auth <login|logout>\n");
}
process.exit(0);
}
if (args.includes("--setup-opencode")) {
await setupOpenCodeConfig();
process.exit(0);
}
if (args.includes("--setup-claude-code")) {
const force = args.includes("--force");
await setupClaudeCodeConfig(force);
process.exit(0);
}
const config = loadConfig();
initLogger(config.logLevel);
logger.info(
`API key source: ${process.env.CC_API_KEY ? "env CC_API_KEY" : config.apiKey ? "auth.json" : "none"} (length: ${config.apiKey?.length ?? 0})`,
);
if (!process.env.CC_CLI_VERSION) {
const latest = await fetchLatestCliVersion();
if (latest) config.ccVersion = latest;
}
if (!config.apiKey) {
console.log("\n No Command Code API key found.");
console.log(" You can get one from https://commandcode.ai/settings\n");
const key = await promptForApiKey();
if (!key) {
console.error(" FATAL: API key is required.\n");
process.exit(1);
}
saveApiKey(key);
config.apiKey = key;
console.log(" ✓ API key saved to ~/.config/commandcode-api-proxy/auth.json\n");
}
const server = createServer(config);
server.listen(config.port, config.host, () => {
console.log(`\n Command Code API Proxy v${process.env.npm_package_version ?? "0.1.0"}`);
console.log(` ${"=".repeat(50)}`);
console.log(` Listening on http://${config.host}:${config.port}`);
console.log(` Auth: ${config.apiKey ? "ENABLED (Bearer token or x-api-key)" : "DISABLED"}`);
console.log("");
console.log(" Endpoints:");
console.log(" GET /health");
console.log(" GET /v1/models");
console.log(" POST /v1/chat/completions (OpenAI format)");
console.log(" POST /v1/messages (Anthropic format)");
console.log(" POST /v1/messages/count_tokens (Anthropic format)");
console.log("");
console.log(" Press Ctrl+C to stop\n");
});
// Never let an unexpected async error crash the proxy silently — log and keep
// serving. (Route handlers already catch their own errors; this is a backstop.)
process.on("unhandledRejection", (reason) => {
logger.error("[fatal] Unhandled promise rejection:", reason);
});
process.on("uncaughtException", (err) => {
logger.error("[fatal] Uncaught exception:", err);
});
const shutdown = (signal: string): void => {
logger.info(`Received ${signal}, shutting down...`);
// Don't hang forever waiting on a stuck streaming connection.
const force = setTimeout(() => {
logger.warn("Forcing shutdown after 10s timeout");
process.exit(1);
}, 10_000);
force.unref();
server.close(() => process.exit(0));
};
process.on("SIGINT", () => shutdown("SIGINT"));
process.on("SIGTERM", () => shutdown("SIGTERM"));