mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix: proper SIGINT handler and output in nonInteractive mode
This commit is contained in:
@@ -5,7 +5,6 @@ export default {
|
||||
commands: 'Commands',
|
||||
configuration: 'Configuration',
|
||||
'configuration-v1': 'Configuration (v1)',
|
||||
'structured-output': 'Structured Output',
|
||||
themes: 'Themes',
|
||||
tutorials: 'Tutorials',
|
||||
'keyboard-shortcuts': 'Keyboard Shortcuts',
|
||||
|
||||
@@ -220,12 +220,6 @@ export async function main() {
|
||||
}
|
||||
|
||||
const isDebugMode = cliConfig.isDebugMode(argv);
|
||||
const consolePatcher = new ConsolePatcher({
|
||||
stderr: true,
|
||||
debugMode: isDebugMode,
|
||||
});
|
||||
consolePatcher.patch();
|
||||
registerCleanup(consolePatcher.cleanup);
|
||||
|
||||
dns.setDefaultResultOrder(
|
||||
validateDnsResolutionOrder(settings.merged.advanced?.dnsResolutionOrder),
|
||||
@@ -350,6 +344,15 @@ export async function main() {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Setup unified ConsolePatcher based on interactive mode
|
||||
const isInteractive = config.isInteractive();
|
||||
const consolePatcher = new ConsolePatcher({
|
||||
stderr: isInteractive,
|
||||
debugMode: isDebugMode,
|
||||
});
|
||||
consolePatcher.patch();
|
||||
registerCleanup(consolePatcher.cleanup);
|
||||
|
||||
const wasRaw = process.stdin.isRaw;
|
||||
let kittyProtocolDetectionComplete: Promise<boolean> | undefined;
|
||||
if (config.isInteractive() && !wasRaw && process.stdin.isTTY) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import type { Config } from '@qwen-code/qwen-code-core';
|
||||
import { ConsolePatcher } from '../ui/utils/ConsolePatcher.js';
|
||||
import { StreamJsonInputReader } from './io/StreamJsonInputReader.js';
|
||||
import { StreamJsonOutputAdapter } from './io/StreamJsonOutputAdapter.js';
|
||||
import { ControlContext } from './control/ControlContext.js';
|
||||
@@ -96,7 +95,6 @@ class SessionManager {
|
||||
private dispatcher: ControlDispatcher | null = null;
|
||||
private controlService: ControlService | null = null;
|
||||
private controlSystemEnabled: boolean | null = null;
|
||||
private consolePatcher: ConsolePatcher;
|
||||
private debugMode: boolean;
|
||||
private shutdownHandler: (() => void) | null = null;
|
||||
private initialPrompt: CLIUserMessage | null = null;
|
||||
@@ -113,11 +111,6 @@ class SessionManager {
|
||||
this.abortController = new AbortController();
|
||||
this.initialPrompt = initialPrompt ?? null;
|
||||
|
||||
this.consolePatcher = new ConsolePatcher({
|
||||
stderr: true,
|
||||
debugMode: this.debugMode,
|
||||
});
|
||||
|
||||
this.inputReader = new StreamJsonInputReader();
|
||||
this.outputAdapter = new StreamJsonOutputAdapter(
|
||||
config,
|
||||
@@ -232,8 +225,6 @@ class SessionManager {
|
||||
*/
|
||||
async run(): Promise<void> {
|
||||
try {
|
||||
this.consolePatcher.patch();
|
||||
|
||||
if (this.debugMode) {
|
||||
console.error('[SessionManager] Starting session', this.sessionId);
|
||||
}
|
||||
@@ -264,7 +255,6 @@ class SessionManager {
|
||||
await this.shutdown();
|
||||
throw error;
|
||||
} finally {
|
||||
this.consolePatcher.cleanup();
|
||||
// Ensure signal handlers are always cleaned up even if shutdown wasn't called
|
||||
this.cleanupSignalHandlers();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import { StreamJsonOutputAdapter } from './nonInteractive/io/StreamJsonOutputAda
|
||||
import type { ControlService } from './nonInteractive/control/ControlService.js';
|
||||
|
||||
import { handleSlashCommand } from './nonInteractiveCliCommands.js';
|
||||
import { ConsolePatcher } from './ui/utils/ConsolePatcher.js';
|
||||
import { handleAtCommand } from './ui/hooks/atCommandProcessor.js';
|
||||
import {
|
||||
handleError,
|
||||
@@ -67,11 +66,6 @@ export async function runNonInteractive(
|
||||
options: RunNonInteractiveOptions = {},
|
||||
): Promise<void> {
|
||||
return promptIdContext.run(prompt_id, async () => {
|
||||
const consolePatcher = new ConsolePatcher({
|
||||
stderr: true,
|
||||
debugMode: config.getDebugMode(),
|
||||
});
|
||||
|
||||
// Create output adapter based on format
|
||||
let adapter: JsonOutputAdapterInterface | undefined;
|
||||
const outputFormat = config.getOutputFormat();
|
||||
@@ -102,12 +96,22 @@ export async function runNonInteractive(
|
||||
}
|
||||
};
|
||||
|
||||
const geminiClient = config.getGeminiClient();
|
||||
const abortController = options.abortController ?? new AbortController();
|
||||
|
||||
// Setup signal handlers for graceful shutdown
|
||||
const shutdownHandler = () => {
|
||||
if (config.getDebugMode()) {
|
||||
console.error('[runNonInteractive] Shutdown signal received');
|
||||
}
|
||||
abortController.abort();
|
||||
};
|
||||
|
||||
try {
|
||||
consolePatcher.patch();
|
||||
process.stdout.on('error', stdoutErrorHandler);
|
||||
|
||||
const geminiClient = config.getGeminiClient();
|
||||
const abortController = options.abortController ?? new AbortController();
|
||||
process.on('SIGINT', shutdownHandler);
|
||||
process.on('SIGTERM', shutdownHandler);
|
||||
|
||||
let initialPartList: PartListUnion | null = extractPartsFromUserMessage(
|
||||
options.userMessage,
|
||||
@@ -362,7 +366,9 @@ export async function runNonInteractive(
|
||||
handleError(error, config);
|
||||
} finally {
|
||||
process.stdout.removeListener('error', stdoutErrorHandler);
|
||||
consolePatcher.cleanup();
|
||||
// Cleanup signal handlers
|
||||
process.removeListener('SIGINT', shutdownHandler);
|
||||
process.removeListener('SIGTERM', shutdownHandler);
|
||||
if (isTelemetrySdkInitialized()) {
|
||||
await shutdownTelemetry(config);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user