mirror of
https://github.com/musistudio/claude-code-router.git
synced 2026-09-01 14:52:19 +08:00
support to lib
This commit is contained in:
+8
-6
@@ -9,12 +9,14 @@ console.log('Building Claude Code Router...');
|
||||
try {
|
||||
// Build the main CLI application
|
||||
console.log('Building CLI application...');
|
||||
execSync('esbuild src/cli.ts --bundle --platform=node --outfile=dist/cli.js', { stdio: 'inherit' });
|
||||
|
||||
execSync('esbuild src/index.ts --bundle --platform=node --outfile=dist/index.js --minify', { stdio: 'inherit' });
|
||||
execSync('esbuild src/cli.ts --bundle --platform=node --outfile=dist/cli.js --external:./index --minify', { stdio: 'inherit' });
|
||||
|
||||
|
||||
// Copy the tiktoken WASM file
|
||||
console.log('Copying tiktoken WASM file...');
|
||||
execSync('shx cp node_modules/tiktoken/tiktoken_bg.wasm dist/tiktoken_bg.wasm', { stdio: 'inherit' });
|
||||
|
||||
|
||||
// Build the UI
|
||||
console.log('Building UI...');
|
||||
// Check if node_modules exists in ui directory, if not install dependencies
|
||||
@@ -23,13 +25,13 @@ try {
|
||||
execSync('cd ui && npm install', { stdio: 'inherit' });
|
||||
}
|
||||
execSync('cd ui && npm run build', { stdio: 'inherit' });
|
||||
|
||||
|
||||
// Copy the built UI index.html to dist
|
||||
console.log('Copying UI build artifacts...');
|
||||
execSync('shx cp ui/dist/index.html dist/index.html', { stdio: 'inherit' });
|
||||
|
||||
|
||||
console.log('Build completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('Build failed:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ export const PID_FILE = path.join(HOME_DIR, '.claude-code-router.pid');
|
||||
|
||||
export const REFERENCE_COUNT_FILE = path.join(os.tmpdir(), "claude-code-reference-count.txt");
|
||||
|
||||
|
||||
export const DEFAULT_CONFIG = {
|
||||
LOG: false,
|
||||
OPENAI_API_KEY: "",
|
||||
|
||||
+15
-259
@@ -1,11 +1,9 @@
|
||||
import { existsSync } from "fs";
|
||||
import { writeFile } from "fs/promises";
|
||||
import { homedir } from "os";
|
||||
import path, { join } from "path";
|
||||
import { join } from "path";
|
||||
import { initConfig, initDir, cleanupLogFiles } from "./utils";
|
||||
import { createServer } from "./server";
|
||||
import { router } from "./utils/router";
|
||||
import { apiKeyAuth } from "./middleware/auth";
|
||||
import {
|
||||
cleanupPidFile,
|
||||
isServiceRunning,
|
||||
@@ -14,16 +12,7 @@ import {
|
||||
import { CONFIG_FILE } from "./constants";
|
||||
import { createStream } from 'rotating-file-stream';
|
||||
import { HOME_DIR } from "./constants";
|
||||
import { sessionUsageCache } from "./utils/cache";
|
||||
import {SSEParserTransform} from "./utils/SSEParser.transform";
|
||||
import {SSESerializerTransform} from "./utils/SSESerializer.transform";
|
||||
import {rewriteStream} from "./utils/rewriteStream";
|
||||
import JSON5 from "json5";
|
||||
import { IAgent } from "./agents/type";
|
||||
import agentsManager from "./agents";
|
||||
import { EventEmitter } from "node:events";
|
||||
|
||||
const event = new EventEmitter()
|
||||
export { isServiceRunning } from "./utils/processCheck";
|
||||
|
||||
async function initializeClaudeConfig() {
|
||||
const homeDir = homedir();
|
||||
@@ -34,11 +23,9 @@ async function initializeClaudeConfig() {
|
||||
() => Math.random().toString(16)[2]
|
||||
).join("");
|
||||
const configContent = {
|
||||
numStartups: 184,
|
||||
autoUpdaterStatus: "enabled",
|
||||
userID,
|
||||
hasCompletedOnboarding: true,
|
||||
lastOnboardingVersion: "1.0.17",
|
||||
projects: {},
|
||||
};
|
||||
await writeFile(configPath, JSON.stringify(configContent, null, 2));
|
||||
@@ -49,21 +36,13 @@ interface RunOptions {
|
||||
port?: number;
|
||||
}
|
||||
|
||||
async function run(options: RunOptions = {}) {
|
||||
// Check if service is already running
|
||||
const isRunning = await isServiceRunning()
|
||||
if (isRunning) {
|
||||
console.log("✅ Service is already running in the background.");
|
||||
return;
|
||||
}
|
||||
|
||||
export async function getServer(options: RunOptions = {}) {
|
||||
await initializeClaudeConfig();
|
||||
await initDir();
|
||||
// Clean up old log files, keeping only the 10 most recent ones
|
||||
await cleanupLogFiles();
|
||||
const config = await initConfig();
|
||||
|
||||
|
||||
let HOST = config.HOST || "127.0.0.1";
|
||||
|
||||
if (config.HOST && !config.APIKEY) {
|
||||
@@ -71,7 +50,7 @@ async function run(options: RunOptions = {}) {
|
||||
console.warn("⚠️ API key is not set. HOST is forced to 127.0.0.1.");
|
||||
}
|
||||
|
||||
const port = config.PORT || 3456;
|
||||
const port = options.port || config.PORT || 3456;
|
||||
|
||||
// Save the PID of the background process
|
||||
savePid(process.pid);
|
||||
@@ -136,7 +115,7 @@ async function run(options: RunOptions = {}) {
|
||||
),
|
||||
},
|
||||
logger: loggerConfig,
|
||||
});
|
||||
}, config);
|
||||
|
||||
// Add global error handlers to prevent the service from crashing
|
||||
process.on("uncaughtException", (err) => {
|
||||
@@ -146,239 +125,16 @@ async function run(options: RunOptions = {}) {
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
server.logger.error("Unhandled rejection at:", promise, "reason:", reason);
|
||||
});
|
||||
// Add async preHandler hook for authentication
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const done = (err?: Error) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
};
|
||||
// Call the async auth function
|
||||
apiKeyAuth(config)(req, reply, done).catch(reject);
|
||||
});
|
||||
});
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
if (req.url.startsWith("/v1/messages")) {
|
||||
const useAgents = []
|
||||
|
||||
for (const agent of agentsManager.getAllAgents()) {
|
||||
if (agent.shouldHandle(req, config)) {
|
||||
// 设置agent标识
|
||||
useAgents.push(agent.name)
|
||||
|
||||
// change request body
|
||||
agent.reqHandler(req, config);
|
||||
|
||||
// append agent tools
|
||||
if (agent.tools.size) {
|
||||
if (!req.body?.tools?.length) {
|
||||
req.body.tools = []
|
||||
}
|
||||
req.body.tools.unshift(...Array.from(agent.tools.values()).map(item => {
|
||||
return {
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
input_schema: item.input_schema
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useAgents.length) {
|
||||
req.agents = useAgents;
|
||||
}
|
||||
await router(req, reply, {
|
||||
config,
|
||||
event
|
||||
});
|
||||
}
|
||||
});
|
||||
server.addHook("onError", async (request, reply, error) => {
|
||||
event.emit('onError', request, reply, error);
|
||||
})
|
||||
server.addHook("onSend", (req, reply, payload, done) => {
|
||||
if (req.sessionId && req.url.startsWith("/v1/messages")) {
|
||||
if (payload instanceof ReadableStream) {
|
||||
if (req.agents) {
|
||||
const abortController = new AbortController();
|
||||
const eventStream = payload.pipeThrough(new SSEParserTransform())
|
||||
let currentAgent: undefined | IAgent;
|
||||
let currentToolIndex = -1
|
||||
let currentToolName = ''
|
||||
let currentToolArgs = ''
|
||||
let currentToolId = ''
|
||||
const toolMessages: any[] = []
|
||||
const assistantMessages: any[] = []
|
||||
// 存储Anthropic格式的消息体,区分文本和工具类型
|
||||
return done(null, rewriteStream(eventStream, async (data, controller) => {
|
||||
try {
|
||||
// 检测工具调用开始
|
||||
if (data.event === 'content_block_start' && data?.data?.content_block?.name) {
|
||||
const agent = req.agents.find((name: string) => agentsManager.getAgent(name)?.tools.get(data.data.content_block.name))
|
||||
if (agent) {
|
||||
currentAgent = agentsManager.getAgent(agent)
|
||||
currentToolIndex = data.data.index
|
||||
currentToolName = data.data.content_block.name
|
||||
currentToolId = data.data.content_block.id
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// 收集工具参数
|
||||
if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data?.delta?.type === 'input_json_delta') {
|
||||
currentToolArgs += data.data?.delta?.partial_json;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 工具调用完成,处理agent调用
|
||||
if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data.type === 'content_block_stop') {
|
||||
try {
|
||||
const args = JSON5.parse(currentToolArgs);
|
||||
assistantMessages.push({
|
||||
type: "tool_use",
|
||||
id: currentToolId,
|
||||
name: currentToolName,
|
||||
input: args
|
||||
})
|
||||
const toolResult = await currentAgent?.tools.get(currentToolName)?.handler(args, {
|
||||
req,
|
||||
config
|
||||
});
|
||||
toolMessages.push({
|
||||
"tool_use_id": currentToolId,
|
||||
"type": "tool_result",
|
||||
"content": toolResult
|
||||
})
|
||||
currentAgent = undefined
|
||||
currentToolIndex = -1
|
||||
currentToolName = ''
|
||||
currentToolArgs = ''
|
||||
currentToolId = ''
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (data.event === 'message_delta' && toolMessages.length) {
|
||||
req.body.messages.push({
|
||||
role: 'assistant',
|
||||
content: assistantMessages
|
||||
})
|
||||
req.body.messages.push({
|
||||
role: 'user',
|
||||
content: toolMessages
|
||||
})
|
||||
const response = await fetch(`http://127.0.0.1:${config.PORT}/v1/messages`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'x-api-key': config.APIKEY,
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(req.body),
|
||||
})
|
||||
if (!response.ok) {
|
||||
return undefined;
|
||||
}
|
||||
const stream = response.body!.pipeThrough(new SSEParserTransform())
|
||||
const reader = stream.getReader()
|
||||
while (true) {
|
||||
try {
|
||||
const {value, done} = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
if (['message_start', 'message_stop'].includes(value.event)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查流是否仍然可写
|
||||
if (!controller.desiredSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
controller.enqueue(value)
|
||||
}catch (readError: any) {
|
||||
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||
abortController.abort(); // 中止所有相关操作
|
||||
break;
|
||||
}
|
||||
throw readError;
|
||||
}
|
||||
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
return data
|
||||
}catch (error: any) {
|
||||
console.error('Unexpected error in stream processing:', error);
|
||||
|
||||
// 处理流提前关闭的错误
|
||||
if (error.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||
abortController.abort();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 其他错误仍然抛出
|
||||
throw error;
|
||||
}
|
||||
}).pipeThrough(new SSESerializerTransform()))
|
||||
}
|
||||
|
||||
const [originalStream, clonedStream] = payload.tee();
|
||||
const read = async (stream: ReadableStream) => {
|
||||
const reader = stream.getReader();
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
// Process the value if needed
|
||||
const dataStr = new TextDecoder().decode(value);
|
||||
if (!dataStr.startsWith("event: message_delta")) {
|
||||
continue;
|
||||
}
|
||||
const str = dataStr.slice(27);
|
||||
try {
|
||||
const message = JSON.parse(str);
|
||||
sessionUsageCache.put(req.sessionId, message.usage);
|
||||
} catch {}
|
||||
}
|
||||
} catch (readError: any) {
|
||||
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||
console.error('Background read stream closed prematurely');
|
||||
} else {
|
||||
console.error('Error in background stream reading:', readError);
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
}
|
||||
read(clonedStream);
|
||||
return done(null, originalStream)
|
||||
}
|
||||
sessionUsageCache.put(req.sessionId, payload.usage);
|
||||
if (typeof payload ==='object') {
|
||||
if (payload.error) {
|
||||
return done(payload.error, null)
|
||||
} else {
|
||||
return done(payload, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof payload ==='object' && payload.error) {
|
||||
return done(payload.error, null)
|
||||
}
|
||||
done(null, payload)
|
||||
});
|
||||
server.addHook("onSend", async (req, reply, payload) => {
|
||||
event.emit('onSend', req, reply, payload);
|
||||
return payload;
|
||||
})
|
||||
|
||||
|
||||
server.start();
|
||||
return server;
|
||||
}
|
||||
|
||||
export { run };
|
||||
// run();
|
||||
export async function run(options: RunOptions = {}) {
|
||||
const isRunning = await isServiceRunning()
|
||||
if (isRunning) {
|
||||
console.log("✅ Service is already running in the background.");
|
||||
return;
|
||||
}
|
||||
const server = await getServer(options);
|
||||
server.start();
|
||||
}
|
||||
|
||||
+244
-1
@@ -5,8 +5,21 @@ import { join } from "path";
|
||||
import fastifyStatic from "@fastify/static";
|
||||
import { readdirSync, statSync, readFileSync, writeFileSync, existsSync } from "fs";
|
||||
import { homedir } from "os";
|
||||
import { router } from "./utils/router";
|
||||
import { apiKeyAuth } from "./middleware/auth";
|
||||
import { sessionUsageCache } from "./utils/cache";
|
||||
import {SSEParserTransform} from "./utils/SSEParser.transform";
|
||||
import {SSESerializerTransform} from "./utils/SSESerializer.transform";
|
||||
import {rewriteStream} from "./utils/rewriteStream";
|
||||
import JSON5 from "json5";
|
||||
import { IAgent } from "./agents/type";
|
||||
import agentsManager from "./agents";
|
||||
import { EventEmitter } from "node:events";
|
||||
|
||||
export const createServer = (config: any): Server => {
|
||||
|
||||
const event = new EventEmitter();
|
||||
|
||||
export const createServer = (config: any, ccrConfig): Server => {
|
||||
const server = new Server(config);
|
||||
|
||||
// Add endpoint to read config.json with access control
|
||||
@@ -191,5 +204,235 @@ export const createServer = (config: any): Server => {
|
||||
}
|
||||
});
|
||||
|
||||
// Add async preHandler hook for authentication
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const done = (err?: Error) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
};
|
||||
// Call the async auth function
|
||||
apiKeyAuth(config)(req, reply, done).catch(reject);
|
||||
});
|
||||
});
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
if (req.url.startsWith("/v1/messages")) {
|
||||
const useAgents = []
|
||||
|
||||
for (const agent of agentsManager.getAllAgents()) {
|
||||
if (agent.shouldHandle(req, config)) {
|
||||
// 设置agent标识
|
||||
useAgents.push(agent.name)
|
||||
|
||||
// change request body
|
||||
agent.reqHandler(req, config);
|
||||
|
||||
// append agent tools
|
||||
if (agent.tools.size) {
|
||||
if (!req.body?.tools?.length) {
|
||||
req.body.tools = []
|
||||
}
|
||||
req.body.tools.unshift(...Array.from(agent.tools.values()).map(item => {
|
||||
return {
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
input_schema: item.input_schema
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useAgents.length) {
|
||||
req.agents = useAgents;
|
||||
}
|
||||
await router(req, reply, {
|
||||
config,
|
||||
event
|
||||
});
|
||||
}
|
||||
});
|
||||
server.addHook("onError", async (request, reply, error) => {
|
||||
event.emit('onError', request, reply, error);
|
||||
})
|
||||
server.addHook("onSend", (req, reply, payload, done) => {
|
||||
if (req.sessionId && req.url.startsWith("/v1/messages")) {
|
||||
if (payload instanceof ReadableStream) {
|
||||
if (req.agents) {
|
||||
const abortController = new AbortController();
|
||||
const eventStream = payload.pipeThrough(new SSEParserTransform())
|
||||
let currentAgent: undefined | IAgent;
|
||||
let currentToolIndex = -1
|
||||
let currentToolName = ''
|
||||
let currentToolArgs = ''
|
||||
let currentToolId = ''
|
||||
const toolMessages: any[] = []
|
||||
const assistantMessages: any[] = []
|
||||
// 存储Anthropic格式的消息体,区分文本和工具类型
|
||||
return done(null, rewriteStream(eventStream, async (data, controller) => {
|
||||
try {
|
||||
// 检测工具调用开始
|
||||
if (data.event === 'content_block_start' && data?.data?.content_block?.name) {
|
||||
const agent = req.agents.find((name: string) => agentsManager.getAgent(name)?.tools.get(data.data.content_block.name))
|
||||
if (agent) {
|
||||
currentAgent = agentsManager.getAgent(agent)
|
||||
currentToolIndex = data.data.index
|
||||
currentToolName = data.data.content_block.name
|
||||
currentToolId = data.data.content_block.id
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// 收集工具参数
|
||||
if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data?.delta?.type === 'input_json_delta') {
|
||||
currentToolArgs += data.data?.delta?.partial_json;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 工具调用完成,处理agent调用
|
||||
if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data.type === 'content_block_stop') {
|
||||
try {
|
||||
const args = JSON5.parse(currentToolArgs);
|
||||
assistantMessages.push({
|
||||
type: "tool_use",
|
||||
id: currentToolId,
|
||||
name: currentToolName,
|
||||
input: args
|
||||
})
|
||||
const toolResult = await currentAgent?.tools.get(currentToolName)?.handler(args, {
|
||||
req,
|
||||
config
|
||||
});
|
||||
toolMessages.push({
|
||||
"tool_use_id": currentToolId,
|
||||
"type": "tool_result",
|
||||
"content": toolResult
|
||||
})
|
||||
currentAgent = undefined
|
||||
currentToolIndex = -1
|
||||
currentToolName = ''
|
||||
currentToolArgs = ''
|
||||
currentToolId = ''
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (data.event === 'message_delta' && toolMessages.length) {
|
||||
req.body.messages.push({
|
||||
role: 'assistant',
|
||||
content: assistantMessages
|
||||
})
|
||||
req.body.messages.push({
|
||||
role: 'user',
|
||||
content: toolMessages
|
||||
})
|
||||
const response = await fetch(`http://127.0.0.1:${config.PORT}/v1/messages`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'x-api-key': config.APIKEY,
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(req.body),
|
||||
})
|
||||
if (!response.ok) {
|
||||
return undefined;
|
||||
}
|
||||
const stream = response.body!.pipeThrough(new SSEParserTransform())
|
||||
const reader = stream.getReader()
|
||||
while (true) {
|
||||
try {
|
||||
const {value, done} = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
if (['message_start', 'message_stop'].includes(value.event)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查流是否仍然可写
|
||||
if (!controller.desiredSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
controller.enqueue(value)
|
||||
}catch (readError: any) {
|
||||
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||
abortController.abort(); // 中止所有相关操作
|
||||
break;
|
||||
}
|
||||
throw readError;
|
||||
}
|
||||
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
return data
|
||||
}catch (error: any) {
|
||||
console.error('Unexpected error in stream processing:', error);
|
||||
|
||||
// 处理流提前关闭的错误
|
||||
if (error.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||
abortController.abort();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 其他错误仍然抛出
|
||||
throw error;
|
||||
}
|
||||
}).pipeThrough(new SSESerializerTransform()))
|
||||
}
|
||||
|
||||
const [originalStream, clonedStream] = payload.tee();
|
||||
const read = async (stream: ReadableStream) => {
|
||||
const reader = stream.getReader();
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
// Process the value if needed
|
||||
const dataStr = new TextDecoder().decode(value);
|
||||
if (!dataStr.startsWith("event: message_delta")) {
|
||||
continue;
|
||||
}
|
||||
const str = dataStr.slice(27);
|
||||
try {
|
||||
const message = JSON.parse(str);
|
||||
sessionUsageCache.put(req.sessionId, message.usage);
|
||||
} catch {}
|
||||
}
|
||||
} catch (readError: any) {
|
||||
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||
console.error('Background read stream closed prematurely');
|
||||
} else {
|
||||
console.error('Error in background stream reading:', readError);
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
}
|
||||
read(clonedStream);
|
||||
return done(null, originalStream)
|
||||
}
|
||||
sessionUsageCache.put(req.sessionId, payload.usage);
|
||||
if (typeof payload ==='object') {
|
||||
if (payload.error) {
|
||||
return done(payload.error, null)
|
||||
} else {
|
||||
return done(payload, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof payload ==='object' && payload.error) {
|
||||
return done(payload.error, null)
|
||||
}
|
||||
done(null, payload)
|
||||
});
|
||||
server.addHook("onSend", async (req, reply, payload) => {
|
||||
event.emit('onSend', req, reply, payload);
|
||||
return payload;
|
||||
})
|
||||
|
||||
return server;
|
||||
};
|
||||
|
||||
@@ -56,6 +56,8 @@ export async function executeCodeCommand(args: string[] = []) {
|
||||
const stdioConfig: StdioOptions = config.NON_INTERACTIVE_MODE
|
||||
? ["pipe", "inherit", "inherit"] // Pipe stdin for non-interactive
|
||||
: "inherit"; // Default inherited behavior
|
||||
|
||||
console.log(claudePath + (joinedArgs ? ` ${joinedArgs}` : ""))
|
||||
const claudeProcess = spawn(
|
||||
claudePath + (joinedArgs ? ` ${joinedArgs}` : ""),
|
||||
[],
|
||||
|
||||
Reference in New Issue
Block a user