mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-20 19:03:51 +08:00
chore: bump version to 7.2.7
- Enhance smart-search with advanced MCP integration - Add GEMINI_API_KEY configuration support in codexlens - Update MCP server with new tool handlers - Add tests for smart-search MCP usage - Update documentation
This commit is contained in:
@@ -955,6 +955,9 @@ export async function handleCodexLensConfigRoutes(ctx: RouteContext): Promise<bo
|
||||
if (settings.embedding?.use_gpu !== undefined) {
|
||||
settingsDefaults['CODEXLENS_USE_GPU'] = String(settings.embedding.use_gpu);
|
||||
}
|
||||
if (settings.embedding?.auto_embed_missing !== undefined) {
|
||||
settingsDefaults['CODEXLENS_AUTO_EMBED_MISSING'] = String(settings.embedding.auto_embed_missing);
|
||||
}
|
||||
if (settings.embedding?.strategy) {
|
||||
settingsDefaults['CODEXLENS_EMBEDDING_STRATEGY'] = settings.embedding.strategy;
|
||||
}
|
||||
@@ -1219,6 +1222,7 @@ export async function handleCodexLensConfigRoutes(ctx: RouteContext): Promise<bo
|
||||
'CODEXLENS_EMBEDDING_BACKEND': { path: ['embedding', 'backend'] },
|
||||
'CODEXLENS_EMBEDDING_MODEL': { path: ['embedding', 'model'] },
|
||||
'CODEXLENS_USE_GPU': { path: ['embedding', 'use_gpu'], transform: v => v === 'true' },
|
||||
'CODEXLENS_AUTO_EMBED_MISSING': { path: ['embedding', 'auto_embed_missing'], transform: v => v === 'true' },
|
||||
'CODEXLENS_EMBEDDING_STRATEGY': { path: ['embedding', 'strategy'] },
|
||||
'CODEXLENS_EMBEDDING_COOLDOWN': { path: ['embedding', 'cooldown'], transform: v => parseFloat(v) },
|
||||
'CODEXLENS_RERANKER_BACKEND': { path: ['reranker', 'backend'] },
|
||||
|
||||
@@ -20,6 +20,7 @@ const SERVER_VERSION = '6.2.0';
|
||||
// Environment variable names for documentation
|
||||
const ENV_PROJECT_ROOT = 'CCW_PROJECT_ROOT';
|
||||
const ENV_ALLOWED_DIRS = 'CCW_ALLOWED_DIRS';
|
||||
const STDIO_DISCONNECT_ERROR_CODES = new Set(['EPIPE', 'ERR_STREAM_DESTROYED']);
|
||||
|
||||
// Default enabled tools (core set - file operations, core memory, and smart search)
|
||||
const DEFAULT_TOOLS: string[] = ['write_file', 'edit_file', 'read_file', 'read_many_files', 'read_outline', 'core_memory', 'smart_search'];
|
||||
@@ -67,6 +68,47 @@ function formatToolResult(result: unknown): string {
|
||||
return String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect broken stdio pipes so orphaned MCP processes can terminate cleanly.
|
||||
*/
|
||||
function isStdioDisconnectError(error: unknown): error is NodeJS.ErrnoException {
|
||||
if (error && typeof error === 'object') {
|
||||
const maybeErrnoError = error as NodeJS.ErrnoException;
|
||||
if (typeof maybeErrnoError.code === 'string' && STDIO_DISCONNECT_ERROR_CODES.has(maybeErrnoError.code)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return error instanceof Error && /broken pipe/i.test(error.message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort logging for teardown paths where stderr may already be gone.
|
||||
*/
|
||||
function safeStderrWrite(message: string): void {
|
||||
try {
|
||||
if (process.stderr.destroyed || !process.stderr.writable) {
|
||||
return;
|
||||
}
|
||||
|
||||
process.stderr.write(`${message}\n`);
|
||||
} catch {
|
||||
// Ignore logging failures while stdio is tearing down.
|
||||
}
|
||||
}
|
||||
|
||||
function safeLogError(prefix: string, error: unknown): void {
|
||||
if (error instanceof Error) {
|
||||
safeStderrWrite(`${prefix}: ${error.message}`);
|
||||
if (error.stack) {
|
||||
safeStderrWrite(error.stack);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
safeStderrWrite(`${prefix}: ${String(error)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure the MCP server
|
||||
*/
|
||||
@@ -151,28 +193,77 @@ function createServer(): Server {
|
||||
async function main(): Promise<void> {
|
||||
const server = createServer();
|
||||
const transport = new StdioServerTransport();
|
||||
let shutdownPromise: Promise<void> | null = null;
|
||||
|
||||
const shutdown = (reason: string, exitCode = 0, error?: unknown): Promise<void> => {
|
||||
if (shutdownPromise) {
|
||||
return shutdownPromise;
|
||||
}
|
||||
|
||||
if (error && !isStdioDisconnectError(error)) {
|
||||
safeLogError(`[${SERVER_NAME}] ${reason}`, error);
|
||||
}
|
||||
|
||||
shutdownPromise = (async () => {
|
||||
try {
|
||||
await server.close();
|
||||
} catch (closeError) {
|
||||
if (!isStdioDisconnectError(closeError)) {
|
||||
safeLogError(`[${SERVER_NAME}] Failed to close server`, closeError);
|
||||
}
|
||||
}
|
||||
|
||||
process.exit(exitCode);
|
||||
})();
|
||||
|
||||
return shutdownPromise;
|
||||
};
|
||||
|
||||
const handleStreamClose = (streamName: string) => () => {
|
||||
void shutdown(`${streamName} disconnected`);
|
||||
};
|
||||
|
||||
const handleStreamError = (streamName: string) => (error: unknown) => {
|
||||
const exitCode = isStdioDisconnectError(error) ? 0 : 1;
|
||||
void shutdown(`${streamName} stream error`, exitCode, error);
|
||||
};
|
||||
|
||||
// Connect server to transport
|
||||
await server.connect(transport);
|
||||
|
||||
// Error handling - prevent process crashes from closing transport
|
||||
process.stdin.once('end', handleStreamClose('stdin'));
|
||||
process.stdin.once('close', handleStreamClose('stdin'));
|
||||
process.stdin.once('error', handleStreamError('stdin'));
|
||||
process.stdout.once('close', handleStreamClose('stdout'));
|
||||
process.stdout.once('error', handleStreamError('stdout'));
|
||||
process.stderr.once('close', handleStreamClose('stderr'));
|
||||
process.stderr.once('error', handleStreamError('stderr'));
|
||||
|
||||
// Error handling - stdio disconnects should terminate, other errors stay logged.
|
||||
process.on('uncaughtException', (error) => {
|
||||
console.error(`[${SERVER_NAME}] Uncaught exception:`, error.message);
|
||||
console.error(error.stack);
|
||||
if (isStdioDisconnectError(error)) {
|
||||
void shutdown('Uncaught stdio disconnect', 0, error);
|
||||
return;
|
||||
}
|
||||
|
||||
safeLogError(`[${SERVER_NAME}] Uncaught exception`, error);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', (reason) => {
|
||||
console.error(`[${SERVER_NAME}] Unhandled rejection:`, reason);
|
||||
if (isStdioDisconnectError(reason)) {
|
||||
void shutdown('Unhandled stdio disconnect', 0, reason);
|
||||
return;
|
||||
}
|
||||
|
||||
safeLogError(`[${SERVER_NAME}] Unhandled rejection`, reason);
|
||||
});
|
||||
|
||||
process.on('SIGINT', async () => {
|
||||
await server.close();
|
||||
process.exit(0);
|
||||
await shutdown('Received SIGINT');
|
||||
});
|
||||
|
||||
process.on('SIGTERM', async () => {
|
||||
await server.close();
|
||||
process.exit(0);
|
||||
await shutdown('Received SIGTERM');
|
||||
});
|
||||
|
||||
// Log server start (to stderr to not interfere with stdio protocol)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user