claude-code-relay 0.0.1

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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Wrapper for Claude CLI subprocess calls
3
+ */
4
+ import type { ChatMessage } from "./types.js";
5
+ export interface CLIConfig {
6
+ cliPath: string;
7
+ timeout: number;
8
+ verbose: boolean;
9
+ }
10
+ export declare class ClaudeCLI {
11
+ private config;
12
+ constructor(config?: Partial<CLIConfig>);
13
+ private validateCLI;
14
+ private normalizeModel;
15
+ private buildPrompt;
16
+ complete(messages: ChatMessage[], model?: string, systemPrompt?: string): Promise<string>;
17
+ stream(messages: ChatMessage[], model?: string, systemPrompt?: string): AsyncGenerator<string, void, unknown>;
18
+ }
19
+ //# sourceMappingURL=cli-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-wrapper.d.ts","sourceRoot":"","sources":["../src/cli-wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAaD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IAUvC,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,WAAW;IA4Bb,QAAQ,CACZ,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,SAAW,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC;IAkDX,MAAM,CACX,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,SAAW,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;CAiDzC"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Wrapper for Claude CLI subprocess calls
3
+ */
4
+ import { spawn } from "node:child_process";
5
+ import { which } from "./utils.js";
6
+ const MODEL_MAP = {
7
+ sonnet: "sonnet",
8
+ opus: "opus",
9
+ haiku: "haiku",
10
+ "claude-3-sonnet": "sonnet",
11
+ "claude-3-opus": "opus",
12
+ "claude-3-haiku": "haiku",
13
+ "claude-sonnet-4": "sonnet",
14
+ "claude-opus-4": "opus",
15
+ };
16
+ export class ClaudeCLI {
17
+ config;
18
+ constructor(config) {
19
+ this.config = {
20
+ cliPath: config?.cliPath ?? process.env.CLAUDE_CLI_PATH ?? "claude",
21
+ timeout: config?.timeout ?? parseInt(process.env.CLAUDE_CODE_RELAY_TIMEOUT ?? "300", 10),
22
+ verbose: config?.verbose ?? process.env.CLAUDE_CODE_RELAY_VERBOSE === "1",
23
+ };
24
+ this.validateCLI();
25
+ }
26
+ validateCLI() {
27
+ const cliPath = which(this.config.cliPath);
28
+ if (!cliPath) {
29
+ throw new Error(`Claude CLI not found at '${this.config.cliPath}'. ` +
30
+ "Please install it or set CLAUDE_CLI_PATH.");
31
+ }
32
+ if (this.config.verbose) {
33
+ console.log(`Using Claude CLI at: ${cliPath}`);
34
+ }
35
+ }
36
+ normalizeModel(model) {
37
+ return MODEL_MAP[model.toLowerCase()] ?? "sonnet";
38
+ }
39
+ buildPrompt(messages, systemPrompt) {
40
+ const parts = [];
41
+ // Extract system prompt from messages if not provided
42
+ for (const msg of messages) {
43
+ if (msg.role === "system") {
44
+ systemPrompt = msg.content;
45
+ break;
46
+ }
47
+ }
48
+ if (systemPrompt) {
49
+ parts.push(`System: ${systemPrompt}\n`);
50
+ }
51
+ for (const msg of messages) {
52
+ if (msg.role === "system")
53
+ continue;
54
+ if (msg.role === "user") {
55
+ parts.push(`Human: ${msg.content}\n`);
56
+ }
57
+ else if (msg.role === "assistant") {
58
+ parts.push(`Assistant: ${msg.content}\n`);
59
+ }
60
+ }
61
+ parts.push("Assistant:");
62
+ return parts.join("\n");
63
+ }
64
+ async complete(messages, model = "sonnet", systemPrompt) {
65
+ const prompt = this.buildPrompt(messages, systemPrompt);
66
+ const normalizedModel = this.normalizeModel(model);
67
+ return new Promise((resolve, reject) => {
68
+ const args = ["-p", "--model", normalizedModel, "--output-format", "text"];
69
+ if (this.config.verbose) {
70
+ console.log(`Running: ${this.config.cliPath} ${args.join(" ")}`);
71
+ }
72
+ const proc = spawn(this.config.cliPath, args, {
73
+ stdio: ["pipe", "pipe", "pipe"],
74
+ });
75
+ let stdout = "";
76
+ let stderr = "";
77
+ proc.stdout.on("data", (data) => {
78
+ stdout += data.toString();
79
+ });
80
+ proc.stderr.on("data", (data) => {
81
+ stderr += data.toString();
82
+ });
83
+ proc.on("close", (code) => {
84
+ if (code !== 0) {
85
+ reject(new Error(`Claude CLI failed: ${stderr}`));
86
+ }
87
+ else {
88
+ resolve(stdout.trim());
89
+ }
90
+ });
91
+ proc.on("error", (err) => {
92
+ reject(err);
93
+ });
94
+ // Send prompt and close stdin
95
+ proc.stdin.write(prompt);
96
+ proc.stdin.end();
97
+ // Timeout
98
+ setTimeout(() => {
99
+ proc.kill();
100
+ reject(new Error(`Claude CLI timeout after ${this.config.timeout}s`));
101
+ }, this.config.timeout * 1000);
102
+ });
103
+ }
104
+ async *stream(messages, model = "sonnet", systemPrompt) {
105
+ const prompt = this.buildPrompt(messages, systemPrompt);
106
+ const normalizedModel = this.normalizeModel(model);
107
+ const args = ["-p", "--model", normalizedModel, "--output-format", "stream-json"];
108
+ if (this.config.verbose) {
109
+ console.log(`Running: ${this.config.cliPath} ${args.join(" ")}`);
110
+ }
111
+ const proc = spawn(this.config.cliPath, args, {
112
+ stdio: ["pipe", "pipe", "pipe"],
113
+ });
114
+ // Send prompt
115
+ proc.stdin.write(prompt);
116
+ proc.stdin.end();
117
+ let buffer = "";
118
+ for await (const chunk of proc.stdout) {
119
+ buffer += chunk.toString();
120
+ // Process complete lines
121
+ while (buffer.includes("\n")) {
122
+ const [line, rest] = buffer.split("\n", 2);
123
+ buffer = rest ?? "";
124
+ const trimmed = line.trim();
125
+ if (!trimmed)
126
+ continue;
127
+ try {
128
+ const data = JSON.parse(trimmed);
129
+ if (data.content) {
130
+ yield data.content;
131
+ }
132
+ else if (data.text) {
133
+ yield data.text;
134
+ }
135
+ else if (data.delta?.text) {
136
+ yield data.delta.text;
137
+ }
138
+ }
139
+ catch {
140
+ // Not JSON, might be raw text
141
+ if (!trimmed.startsWith("{")) {
142
+ yield trimmed;
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ //# sourceMappingURL=cli-wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-wrapper.js","sourceRoot":"","sources":["../src/cli-wrapper.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entrypoint for claude-code-relay using native parseArgs
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG"}
package/dist/cli.js ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entrypoint for claude-code-relay using native parseArgs
4
+ */
5
+ import { parseArgs } from "node:util";
6
+ import { runServer } from "./server.js";
7
+ import { which } from "./utils.js";
8
+ const { values, positionals } = parseArgs({
9
+ allowPositionals: true,
10
+ options: {
11
+ port: { type: "string", short: "p", default: process.env.CLAUDE_CODE_RELAY_PORT ?? "52014" },
12
+ host: { type: "string", short: "h", default: process.env.CLAUDE_CODE_RELAY_HOST ?? "127.0.0.1" },
13
+ "claude-path": { type: "string", default: process.env.CLAUDE_CLI_PATH ?? "claude" },
14
+ timeout: { type: "string", default: process.env.CLAUDE_CODE_RELAY_TIMEOUT ?? "300" },
15
+ verbose: { type: "boolean", short: "v", default: false },
16
+ version: { type: "boolean", short: "V", default: false },
17
+ help: { type: "boolean", default: false },
18
+ },
19
+ });
20
+ const command = positionals[0];
21
+ if (values.version) {
22
+ console.log("claude-code-relay 0.0.1");
23
+ process.exit(0);
24
+ }
25
+ if (values.help || (!command && !values.version)) {
26
+ console.log(`
27
+ claude-code-relay - OpenAI-compatible API server for Claude CLI
28
+
29
+ Usage:
30
+ claude-code-relay <command> [options]
31
+
32
+ Commands:
33
+ serve Start the API server
34
+ check Check if Claude CLI is available
35
+
36
+ Options:
37
+ -p, --port <port> Port to listen on (default: 52014)
38
+ -h, --host <host> Host to bind to (default: 127.0.0.1)
39
+ --claude-path <path> Path to Claude CLI binary (default: claude)
40
+ --timeout <seconds> Request timeout in seconds (default: 300)
41
+ -v, --verbose Enable verbose logging
42
+ -V, --version Show version
43
+ --help Show this help
44
+ `);
45
+ process.exit(0);
46
+ }
47
+ if (command === "serve") {
48
+ const port = parseInt(values.port, 10);
49
+ const host = values.host;
50
+ const claudePath = values["claude-path"];
51
+ const timeout = parseInt(values.timeout, 10);
52
+ const verbose = values.verbose;
53
+ // Set environment for CLI wrapper
54
+ process.env.CLAUDE_CLI_PATH = claudePath;
55
+ process.env.CLAUDE_CODE_RELAY_TIMEOUT = String(timeout);
56
+ process.env.CLAUDE_CODE_RELAY_VERBOSE = verbose ? "1" : "";
57
+ console.log("Starting Claude Code Relay server...");
58
+ console.log(` Host: ${host}`);
59
+ console.log(` Port: ${port}`);
60
+ console.log(` Claude CLI: ${claudePath}`);
61
+ console.log(` Timeout: ${timeout}s`);
62
+ console.log();
63
+ console.log(`API endpoint: http://${host}:${port}/v1/chat/completions`);
64
+ console.log();
65
+ runServer(host, port, {
66
+ cli: { cliPath: claudePath, timeout, verbose },
67
+ });
68
+ }
69
+ else if (command === "check") {
70
+ console.log("Checking Claude CLI...");
71
+ const cliPath = values["claude-path"] ?? process.env.CLAUDE_CLI_PATH ?? "claude";
72
+ const resolved = which(cliPath);
73
+ if (resolved) {
74
+ console.log(` CLI path: ${resolved}`);
75
+ console.log(" Status: OK");
76
+ }
77
+ else {
78
+ console.error(` Error: Claude CLI not found at '${cliPath}'`);
79
+ process.exit(1);
80
+ }
81
+ }
82
+ else {
83
+ console.error(`Unknown command: ${command}`);
84
+ console.error("Run 'claude-code-relay --help' for usage");
85
+ process.exit(1);
86
+ }
87
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Claude Code Relay - OpenAI-compatible API server for Claude CLI
3
+ */
4
+ export { createApp, runServer, type AppConfig } from "./server.js";
5
+ export { ClaudeCLI, type CLIConfig } from "./cli-wrapper.js";
6
+ export type { ChatCompletionRequest, ChatCompletionResponse, ChatCompletionChunk, ChatMessage, } from "./types.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EACV,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,GACZ,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Claude Code Relay - OpenAI-compatible API server for Claude CLI
3
+ */
4
+ export { createApp, runServer } from "./server.js";
5
+ export { ClaudeCLI } from "./cli-wrapper.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAkB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,SAAS,EAAkB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * HTTP server with OpenAI-compatible endpoints using native Node.js
3
+ */
4
+ import { IncomingMessage, ServerResponse } from "node:http";
5
+ import { type CLIConfig } from "./cli-wrapper.js";
6
+ export interface AppConfig {
7
+ cli?: Partial<CLIConfig>;
8
+ }
9
+ export declare function createApp(config?: AppConfig): import("node:http").Server<typeof IncomingMessage, typeof ServerResponse>;
10
+ export declare function runServer(host?: string, port?: number, config?: AppConfig): void;
11
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAgB,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAS7D,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CAC1B;AA6JD,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,SAAS,6EAc3C;AAED,wBAAgB,SAAS,CAAC,IAAI,SAAc,EAAE,IAAI,SAAQ,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAKpF"}
package/dist/server.js ADDED
@@ -0,0 +1,168 @@
1
+ /**
2
+ * HTTP server with OpenAI-compatible endpoints using native Node.js
3
+ */
4
+ import { createServer } from "node:http";
5
+ import { ClaudeCLI } from "./cli-wrapper.js";
6
+ import { generateId } from "./utils.js";
7
+ let _cli = null;
8
+ function sendJson(res, data, status = 200) {
9
+ const body = JSON.stringify(data);
10
+ res.writeHead(status, {
11
+ "Content-Type": "application/json",
12
+ "Content-Length": Buffer.byteLength(body),
13
+ "Access-Control-Allow-Origin": "*",
14
+ });
15
+ res.end(body);
16
+ }
17
+ function sendError(res, message, status = 500) {
18
+ sendJson(res, { error: { message, type: "server_error" } }, status);
19
+ }
20
+ function sendSSEChunk(res, data) {
21
+ res.write(`data: ${data}\n\n`);
22
+ }
23
+ async function readBody(req) {
24
+ return new Promise((resolve, reject) => {
25
+ let body = "";
26
+ req.on("data", (chunk) => (body += chunk));
27
+ req.on("end", () => resolve(body));
28
+ req.on("error", reject);
29
+ });
30
+ }
31
+ async function handleRequest(req, res) {
32
+ const url = req.url ?? "/";
33
+ const method = req.method ?? "GET";
34
+ // CORS preflight
35
+ if (method === "OPTIONS") {
36
+ res.writeHead(204, {
37
+ "Access-Control-Allow-Origin": "*",
38
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
39
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
40
+ });
41
+ res.end();
42
+ return;
43
+ }
44
+ // Health check
45
+ if (method === "GET" && url === "/health") {
46
+ sendJson(res, { status: _cli ? "ok" : "degraded", cli_available: _cli !== null });
47
+ return;
48
+ }
49
+ // List models
50
+ if (method === "GET" && url === "/v1/models") {
51
+ const now = Math.floor(Date.now() / 1000);
52
+ const models = {
53
+ object: "list",
54
+ data: [
55
+ { id: "sonnet", object: "model", created: now, owned_by: "anthropic" },
56
+ { id: "opus", object: "model", created: now, owned_by: "anthropic" },
57
+ { id: "haiku", object: "model", created: now, owned_by: "anthropic" },
58
+ ],
59
+ };
60
+ sendJson(res, models);
61
+ return;
62
+ }
63
+ // Chat completions
64
+ if (method === "POST" && url === "/v1/chat/completions") {
65
+ if (!_cli) {
66
+ sendError(res, "Claude CLI not available", 503);
67
+ return;
68
+ }
69
+ let request;
70
+ try {
71
+ const body = await readBody(req);
72
+ request = JSON.parse(body);
73
+ }
74
+ catch {
75
+ sendError(res, "Invalid JSON", 400);
76
+ return;
77
+ }
78
+ const chatId = generateId("chatcmpl");
79
+ const created = Math.floor(Date.now() / 1000);
80
+ if (request.stream) {
81
+ // Streaming response
82
+ res.writeHead(200, {
83
+ "Content-Type": "text/event-stream",
84
+ "Cache-Control": "no-cache",
85
+ Connection: "keep-alive",
86
+ "Access-Control-Allow-Origin": "*",
87
+ "X-Accel-Buffering": "no",
88
+ });
89
+ // Initial chunk
90
+ const initial = {
91
+ id: chatId,
92
+ object: "chat.completion.chunk",
93
+ created,
94
+ model: request.model,
95
+ choices: [{ index: 0, delta: { role: "assistant", content: "" }, finish_reason: null }],
96
+ };
97
+ sendSSEChunk(res, JSON.stringify(initial));
98
+ try {
99
+ for await (const text of _cli.stream(request.messages, request.model)) {
100
+ const chunk = {
101
+ id: chatId,
102
+ object: "chat.completion.chunk",
103
+ created,
104
+ model: request.model,
105
+ choices: [{ index: 0, delta: { content: text }, finish_reason: null }],
106
+ };
107
+ sendSSEChunk(res, JSON.stringify(chunk));
108
+ }
109
+ }
110
+ catch (err) {
111
+ sendSSEChunk(res, JSON.stringify({ error: { message: String(err), type: "server_error" } }));
112
+ }
113
+ // Final chunk
114
+ const final = {
115
+ id: chatId,
116
+ object: "chat.completion.chunk",
117
+ created,
118
+ model: request.model,
119
+ choices: [{ index: 0, delta: {}, finish_reason: "stop" }],
120
+ };
121
+ sendSSEChunk(res, JSON.stringify(final));
122
+ sendSSEChunk(res, "[DONE]");
123
+ res.end();
124
+ return;
125
+ }
126
+ // Non-streaming response
127
+ try {
128
+ const content = await _cli.complete(request.messages, request.model);
129
+ const response = {
130
+ id: chatId,
131
+ object: "chat.completion",
132
+ created,
133
+ model: request.model,
134
+ choices: [{ index: 0, message: { role: "assistant", content }, finish_reason: "stop" }],
135
+ usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
136
+ };
137
+ sendJson(res, response);
138
+ }
139
+ catch (err) {
140
+ sendError(res, String(err));
141
+ }
142
+ return;
143
+ }
144
+ // Not found
145
+ sendError(res, "Not found", 404);
146
+ }
147
+ export function createApp(config) {
148
+ try {
149
+ _cli = new ClaudeCLI(config?.cli);
150
+ }
151
+ catch (err) {
152
+ console.error(`Failed to initialize Claude CLI: ${err}`);
153
+ _cli = null;
154
+ }
155
+ return createServer((req, res) => {
156
+ handleRequest(req, res).catch((err) => {
157
+ console.error("Request error:", err);
158
+ sendError(res, "Internal server error");
159
+ });
160
+ });
161
+ }
162
+ export function runServer(host = "127.0.0.1", port = 52014, config) {
163
+ const server = createApp(config);
164
+ server.listen(port, host, () => {
165
+ console.log(`Server running at http://${host}:${port}`);
166
+ });
167
+ }
168
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * OpenAI-compatible request/response types
3
+ */
4
+ export interface ChatMessage {
5
+ role: "system" | "user" | "assistant";
6
+ content: string;
7
+ }
8
+ export interface ChatCompletionRequest {
9
+ model: string;
10
+ messages: ChatMessage[];
11
+ stream?: boolean;
12
+ temperature?: number;
13
+ max_tokens?: number;
14
+ top_p?: number;
15
+ stop?: string | string[];
16
+ }
17
+ export interface Choice {
18
+ index: number;
19
+ message: ChatMessage;
20
+ finish_reason: "stop" | "length" | "tool_calls" | null;
21
+ }
22
+ export interface Usage {
23
+ prompt_tokens: number;
24
+ completion_tokens: number;
25
+ total_tokens: number;
26
+ }
27
+ export interface ChatCompletionResponse {
28
+ id: string;
29
+ object: "chat.completion";
30
+ created: number;
31
+ model: string;
32
+ choices: Choice[];
33
+ usage: Usage;
34
+ }
35
+ export interface DeltaMessage {
36
+ role?: "assistant";
37
+ content?: string;
38
+ }
39
+ export interface StreamChoice {
40
+ index: number;
41
+ delta: DeltaMessage;
42
+ finish_reason: "stop" | "length" | "tool_calls" | null;
43
+ }
44
+ export interface ChatCompletionChunk {
45
+ id: string;
46
+ object: "chat.completion.chunk";
47
+ created: number;
48
+ model: string;
49
+ choices: StreamChoice[];
50
+ }
51
+ export interface ModelInfo {
52
+ id: string;
53
+ object: "model";
54
+ created: number;
55
+ owned_by: string;
56
+ }
57
+ export interface ModelList {
58
+ object: "list";
59
+ data: ModelInfo[];
60
+ }
61
+ export interface ErrorResponse {
62
+ error: {
63
+ message: string;
64
+ type: string;
65
+ code?: string;
66
+ };
67
+ }
68
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,KAAK;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,uBAAuB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * OpenAI-compatible request/response types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Utility functions
3
+ */
4
+ /**
5
+ * Find executable in PATH (cross-platform which)
6
+ */
7
+ export declare function which(command: string): string | null;
8
+ /**
9
+ * Generate a random ID
10
+ */
11
+ export declare function generateId(prefix?: string): string;
12
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,SAAK,GAAG,MAAM,CAG9C"}
package/dist/utils.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Utility functions
3
+ */
4
+ import { execSync } from "node:child_process";
5
+ import { existsSync } from "node:fs";
6
+ import { platform } from "node:os";
7
+ /**
8
+ * Find executable in PATH (cross-platform which)
9
+ */
10
+ export function which(command) {
11
+ // If it's an absolute path, check if it exists
12
+ if (command.startsWith("/") || command.startsWith("~")) {
13
+ return existsSync(command) ? command : null;
14
+ }
15
+ try {
16
+ const cmd = platform() === "win32" ? "where" : "which";
17
+ const result = execSync(`${cmd} ${command}`, {
18
+ encoding: "utf-8",
19
+ stdio: ["pipe", "pipe", "pipe"],
20
+ });
21
+ return result.trim().split("\n")[0] ?? null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ /**
28
+ * Generate a random ID
29
+ */
30
+ export function generateId(prefix = "") {
31
+ const random = Math.random().toString(36).substring(2, 14);
32
+ return prefix ? `${prefix}-${random}` : random;
33
+ }
34
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe;IACnC,+CAA+C;IAC/C,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QACvD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,GAAG,IAAI,OAAO,EAAE,EAAE;YAC3C,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAM,GAAG,EAAE;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AACjD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "claude-code-relay",
3
+ "version": "0.0.1",
4
+ "description": "Local proxy that exposes Claude CLI as an OpenAI-compatible API server",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "claude-code-relay": "./dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsc --watch",
20
+ "start": "node dist/cli.js serve",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "typecheck": "tsc --noEmit",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "keywords": [
32
+ "claude",
33
+ "openai",
34
+ "proxy",
35
+ "llm",
36
+ "api",
37
+ "cli"
38
+ ],
39
+ "author": "Community",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/DreamTeamMobile/claude-code-relay.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/DreamTeamMobile/claude-code-relay/issues"
47
+ },
48
+ "homepage": "https://github.com/DreamTeamMobile/claude-code-relay#readme",
49
+ "engines": {
50
+ "node": ">=18.0.0"
51
+ },
52
+ "dependencies": {},
53
+ "devDependencies": {
54
+ "@types/node": "^25.0.3",
55
+ "typescript": "^5.9.3",
56
+ "vitest": "^4.0.16"
57
+ }
58
+ }