mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-04 22:51:08 +00:00
Merge remote-tracking branch 'origin/main' into feat/npm-extension-installation
This commit is contained in:
commit
2c1432a23a
47 changed files with 1056 additions and 253 deletions
|
|
@ -54,7 +54,7 @@ export function generateCodingPlanTemplate(
|
|||
return [
|
||||
{
|
||||
id: 'qwen3.5-plus',
|
||||
name: '[Bailian Coding Plan] qwen3.5-plus',
|
||||
name: '[ModelStudio Coding Plan] qwen3.5-plus',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -66,7 +66,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'glm-5',
|
||||
name: '[Bailian Coding Plan] glm-5',
|
||||
name: '[ModelStudio Coding Plan] glm-5',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -78,7 +78,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'kimi-k2.5',
|
||||
name: '[Bailian Coding Plan] kimi-k2.5',
|
||||
name: '[ModelStudio Coding Plan] kimi-k2.5',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -90,7 +90,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'MiniMax-M2.5',
|
||||
name: '[Bailian Coding Plan] MiniMax-M2.5',
|
||||
name: '[ModelStudio Coding Plan] MiniMax-M2.5',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -102,7 +102,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'qwen3-coder-plus',
|
||||
name: '[Bailian Coding Plan] qwen3-coder-plus',
|
||||
name: '[ModelStudio Coding Plan] qwen3-coder-plus',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -111,7 +111,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'qwen3-coder-next',
|
||||
name: '[Bailian Coding Plan] qwen3-coder-next',
|
||||
name: '[ModelStudio Coding Plan] qwen3-coder-next',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -120,7 +120,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'qwen3-max-2026-01-23',
|
||||
name: '[Bailian Coding Plan] qwen3-max-2026-01-23',
|
||||
name: '[ModelStudio Coding Plan] qwen3-max-2026-01-23',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -132,7 +132,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'glm-4.7',
|
||||
name: '[Bailian Coding Plan] glm-4.7',
|
||||
name: '[ModelStudio Coding Plan] glm-4.7',
|
||||
baseUrl: 'https://coding.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -145,11 +145,11 @@ export function generateCodingPlanTemplate(
|
|||
];
|
||||
}
|
||||
|
||||
// Global region uses Bailian Coding Plan branding for Global/Intl
|
||||
// Global region uses ModelStudio Coding Plan branding for Global/Intl
|
||||
return [
|
||||
{
|
||||
id: 'qwen3.5-plus',
|
||||
name: '[Bailian Coding Plan for Global/Intl] qwen3.5-plus',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] qwen3.5-plus',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -161,7 +161,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'qwen3-coder-plus',
|
||||
name: '[Bailian Coding Plan for Global/Intl] qwen3-coder-plus',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] qwen3-coder-plus',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -170,7 +170,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'qwen3-coder-next',
|
||||
name: '[Bailian Coding Plan for Global/Intl] qwen3-coder-next',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] qwen3-coder-next',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -179,7 +179,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'qwen3-max-2026-01-23',
|
||||
name: '[Bailian Coding Plan for Global/Intl] qwen3-max-2026-01-23',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] qwen3-max-2026-01-23',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -191,7 +191,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'glm-4.7',
|
||||
name: '[Bailian Coding Plan for Global/Intl] glm-4.7',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] glm-4.7',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -203,7 +203,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'glm-5',
|
||||
name: '[Bailian Coding Plan for Global/Intl] glm-5',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] glm-5',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -215,7 +215,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'MiniMax-M2.5',
|
||||
name: '[Bailian Coding Plan for Global/Intl] MiniMax-M2.5',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] MiniMax-M2.5',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
@ -227,7 +227,7 @@ export function generateCodingPlanTemplate(
|
|||
},
|
||||
{
|
||||
id: 'kimi-k2.5',
|
||||
name: '[Bailian Coding Plan for Global/Intl] kimi-k2.5',
|
||||
name: '[ModelStudio Coding Plan for Global/Intl] kimi-k2.5',
|
||||
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/v1',
|
||||
envKey: CODING_PLAN_ENV_KEY,
|
||||
generationConfig: {
|
||||
|
|
|
|||
|
|
@ -1784,8 +1784,8 @@ export default {
|
|||
// Auth Dialog - View Titles and Labels
|
||||
// ============================================================================
|
||||
'Coding Plan': 'Coding Plan',
|
||||
"Paste your api key of Bailian Coding Plan and you're all set!":
|
||||
'Fügen Sie Ihren Bailian Coding Plan API-Schlüssel ein und Sie sind bereit!',
|
||||
"Paste your api key of ModelStudio Coding Plan and you're all set!":
|
||||
'Fügen Sie Ihren ModelStudio Coding Plan API-Schlüssel ein und Sie sind bereit!',
|
||||
Custom: 'Benutzerdefiniert',
|
||||
'More instructions about configuring `modelProviders` manually.':
|
||||
'Weitere Anweisungen zur manuellen Konfiguration von `modelProviders`.',
|
||||
|
|
|
|||
|
|
@ -1833,8 +1833,8 @@ export default {
|
|||
// Auth Dialog - View Titles and Labels
|
||||
// ============================================================================
|
||||
'Coding Plan': 'Coding Plan',
|
||||
"Paste your api key of Bailian Coding Plan and you're all set!":
|
||||
"Paste your api key of Bailian Coding Plan and you're all set!",
|
||||
"Paste your api key of ModelStudio Coding Plan and you're all set!":
|
||||
"Paste your api key of ModelStudio Coding Plan and you're all set!",
|
||||
Custom: 'Custom',
|
||||
'More instructions about configuring `modelProviders` manually.':
|
||||
'More instructions about configuring `modelProviders` manually.',
|
||||
|
|
|
|||
|
|
@ -1285,8 +1285,8 @@ export default {
|
|||
// Auth Dialog - View Titles and Labels
|
||||
// ============================================================================
|
||||
'Coding Plan': 'Coding Plan',
|
||||
"Paste your api key of Bailian Coding Plan and you're all set!":
|
||||
'Bailian Coding PlanのAPIキーを貼り付けるだけで準備完了です!',
|
||||
"Paste your api key of ModelStudio Coding Plan and you're all set!":
|
||||
'ModelStudio Coding PlanのAPIキーを貼り付けるだけで準備完了です!',
|
||||
Custom: 'カスタム',
|
||||
'More instructions about configuring `modelProviders` manually.':
|
||||
'`modelProviders`を手動で設定する方法の詳細はこちら。',
|
||||
|
|
|
|||
|
|
@ -1777,8 +1777,8 @@ export default {
|
|||
// Auth Dialog - View Titles and Labels
|
||||
// ============================================================================
|
||||
'Coding Plan': 'Coding Plan',
|
||||
"Paste your api key of Bailian Coding Plan and you're all set!":
|
||||
'Cole sua chave de API do Bailian Coding Plan e pronto!',
|
||||
"Paste your api key of ModelStudio Coding Plan and you're all set!":
|
||||
'Cole sua chave de API do ModelStudio Coding Plan e pronto!',
|
||||
Custom: 'Personalizado',
|
||||
'More instructions about configuring `modelProviders` manually.':
|
||||
'Mais instruções sobre como configurar `modelProviders` manualmente.',
|
||||
|
|
|
|||
|
|
@ -1711,8 +1711,8 @@ export default {
|
|||
// Auth Dialog - View Titles and Labels
|
||||
// ============================================================================
|
||||
'Coding Plan': 'Coding Plan',
|
||||
"Paste your api key of Bailian Coding Plan and you're all set!":
|
||||
'Вставьте ваш API-ключ Bailian Coding Plan и всё готово!',
|
||||
"Paste your api key of ModelStudio Coding Plan and you're all set!":
|
||||
'Вставьте ваш API-ключ ModelStudio Coding Plan и всё готово!',
|
||||
Custom: 'Пользовательский',
|
||||
'More instructions about configuring `modelProviders` manually.':
|
||||
'Дополнительные инструкции по ручной настройке `modelProviders`.',
|
||||
|
|
|
|||
|
|
@ -1650,7 +1650,7 @@ export default {
|
|||
// ============================================================================
|
||||
'API-KEY': 'API-KEY',
|
||||
'Coding Plan': 'Coding Plan',
|
||||
"Paste your api key of Bailian Coding Plan and you're all set!":
|
||||
"Paste your api key of ModelStudio Coding Plan and you're all set!":
|
||||
'粘贴您的百炼 Coding Plan API Key,即可完成设置!',
|
||||
Custom: '自定义',
|
||||
'More instructions about configuring `modelProviders` manually.':
|
||||
|
|
|
|||
|
|
@ -558,121 +558,4 @@ describe('AuthDialog', () => {
|
|||
expect(handleAuthSelect).toHaveBeenCalledWith(undefined);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('shows API Key subtype menu and opens custom info', async () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
originalSettings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: {},
|
||||
originalSettings: {},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
originalSettings: {
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
originalSettings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { stdin, lastFrame, unmount } = renderAuthDialog(settings);
|
||||
await wait();
|
||||
|
||||
// Move from Qwen OAuth -> Coding Plan -> API Key, then enter
|
||||
stdin.write('\u001B[B');
|
||||
stdin.write('\u001B[B');
|
||||
stdin.write('\r');
|
||||
await wait();
|
||||
|
||||
expect(lastFrame()).toContain('Select API Key Type');
|
||||
expect(lastFrame()).toContain('Alibaba Cloud ModelStudio Standard API Key');
|
||||
expect(lastFrame()).toContain('Custom API Key');
|
||||
|
||||
// Move to Custom API Key and enter
|
||||
stdin.write('\u001B[B');
|
||||
stdin.write('\r');
|
||||
await wait();
|
||||
|
||||
expect(lastFrame()).toContain('Custom Configuration');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('shows Alibaba Cloud ModelStudio Standard API Key region endpoint', async () => {
|
||||
const settings: LoadedSettings = new LoadedSettings(
|
||||
{
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
originalSettings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: {},
|
||||
originalSettings: {},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
originalSettings: {
|
||||
security: { auth: { selectedType: undefined } },
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
},
|
||||
path: '',
|
||||
},
|
||||
{
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
originalSettings: { ui: { customThemes: {} }, mcpServers: {} },
|
||||
path: '',
|
||||
},
|
||||
true,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const { stdin, lastFrame, unmount } = renderAuthDialog(settings, {}, {});
|
||||
await wait();
|
||||
|
||||
// Main -> API Key
|
||||
stdin.write('\u001B[B');
|
||||
stdin.write('\u001B[B');
|
||||
stdin.write('\r');
|
||||
await wait();
|
||||
|
||||
// API Key type -> Alibaba Cloud ModelStudio Standard API Key (default)
|
||||
stdin.write('\r');
|
||||
await wait();
|
||||
|
||||
// Region -> Singapore
|
||||
stdin.write('\u001B[B');
|
||||
stdin.write('\r');
|
||||
await wait();
|
||||
|
||||
expect(lastFrame()).toContain(
|
||||
'Enter Alibaba Cloud ModelStudio Standard API Key',
|
||||
);
|
||||
expect(lastFrame()).toContain(
|
||||
'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',
|
||||
);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -140,6 +140,71 @@ describe('clearCommand', () => {
|
|||
expect(mockContext.ui.clear).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should clear UI before resetChat for immediate responsiveness', async () => {
|
||||
if (!clearCommand.action) {
|
||||
throw new Error('clearCommand must have an action.');
|
||||
}
|
||||
|
||||
const callOrder: string[] = [];
|
||||
(mockContext.ui.clear as ReturnType<typeof vi.fn>).mockImplementation(
|
||||
() => {
|
||||
callOrder.push('ui.clear');
|
||||
},
|
||||
);
|
||||
mockResetChat.mockImplementation(async () => {
|
||||
callOrder.push('resetChat');
|
||||
});
|
||||
|
||||
await clearCommand.action(mockContext, '');
|
||||
|
||||
// ui.clear should be called before resetChat for immediate UI feedback
|
||||
const clearIndex = callOrder.indexOf('ui.clear');
|
||||
const resetIndex = callOrder.indexOf('resetChat');
|
||||
expect(clearIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(resetIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(clearIndex).toBeLessThan(resetIndex);
|
||||
});
|
||||
|
||||
it('should not await hook events (fire-and-forget)', async () => {
|
||||
if (!clearCommand.action) {
|
||||
throw new Error('clearCommand must have an action.');
|
||||
}
|
||||
|
||||
// Make hooks take a long time - they should not block
|
||||
let sessionEndResolved = false;
|
||||
let sessionStartResolved = false;
|
||||
mockFireSessionEndEvent.mockImplementation(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
sessionEndResolved = true;
|
||||
resolve(undefined);
|
||||
}, 5000);
|
||||
}),
|
||||
);
|
||||
mockFireSessionStartEvent.mockImplementation(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
sessionStartResolved = true;
|
||||
resolve(undefined);
|
||||
}, 5000);
|
||||
}),
|
||||
);
|
||||
|
||||
await clearCommand.action(mockContext, '');
|
||||
|
||||
// The action should complete immediately without waiting for hooks
|
||||
expect(mockContext.ui.clear).toHaveBeenCalledTimes(1);
|
||||
expect(mockResetChat).toHaveBeenCalledTimes(1);
|
||||
// Hooks should have been called but not necessarily resolved
|
||||
expect(mockFireSessionEndEvent).toHaveBeenCalled();
|
||||
expect(mockFireSessionStartEvent).toHaveBeenCalled();
|
||||
// Hooks should NOT have resolved yet since they have 5s timeouts
|
||||
expect(sessionEndResolved).toBe(false);
|
||||
expect(sessionStartResolved).toBe(false);
|
||||
});
|
||||
|
||||
it('should not attempt to reset chat if config service is not available', async () => {
|
||||
if (!clearCommand.action) {
|
||||
throw new Error('clearCommand must have an action.');
|
||||
|
|
|
|||
|
|
@ -27,14 +27,13 @@ export const clearCommand: SlashCommand = {
|
|||
const { config } = context.services;
|
||||
|
||||
if (config) {
|
||||
// Fire SessionEnd event before clearing (current session ends)
|
||||
try {
|
||||
await config
|
||||
.getHookSystem()
|
||||
?.fireSessionEndEvent(SessionEndReason.Clear);
|
||||
} catch (err) {
|
||||
config.getDebugLogger().warn(`SessionEnd hook failed: ${err}`);
|
||||
}
|
||||
// Fire SessionEnd event (non-blocking to avoid UI lag)
|
||||
config
|
||||
.getHookSystem()
|
||||
?.fireSessionEndEvent(SessionEndReason.Clear)
|
||||
.catch((err) => {
|
||||
config.getDebugLogger().warn(`SessionEnd hook failed: ${err}`);
|
||||
});
|
||||
|
||||
const newSessionId = config.startNewSession();
|
||||
|
||||
|
|
@ -54,6 +53,9 @@ export const clearCommand: SlashCommand = {
|
|||
context.session.startNewSession(newSessionId);
|
||||
}
|
||||
|
||||
// Clear UI first for immediate responsiveness
|
||||
context.ui.clear();
|
||||
|
||||
const geminiClient = config.getGeminiClient();
|
||||
if (geminiClient) {
|
||||
context.ui.setDebugMessage(
|
||||
|
|
@ -66,22 +68,20 @@ export const clearCommand: SlashCommand = {
|
|||
context.ui.setDebugMessage(t('Starting a new session and clearing.'));
|
||||
}
|
||||
|
||||
// Fire SessionStart event after clearing (new session starts)
|
||||
try {
|
||||
await config
|
||||
.getHookSystem()
|
||||
?.fireSessionStartEvent(
|
||||
SessionStartSource.Clear,
|
||||
config.getModel() ?? '',
|
||||
String(config.getApprovalMode()) as PermissionMode,
|
||||
);
|
||||
} catch (err) {
|
||||
config.getDebugLogger().warn(`SessionStart hook failed: ${err}`);
|
||||
}
|
||||
// Fire SessionStart event (non-blocking to avoid UI lag)
|
||||
config
|
||||
.getHookSystem()
|
||||
?.fireSessionStartEvent(
|
||||
SessionStartSource.Clear,
|
||||
config.getModel() ?? '',
|
||||
String(config.getApprovalMode()) as PermissionMode,
|
||||
)
|
||||
.catch((err) => {
|
||||
config.getDebugLogger().warn(`SessionStart hook failed: ${err}`);
|
||||
});
|
||||
} else {
|
||||
context.ui.setDebugMessage(t('Starting a new session and clearing.'));
|
||||
context.ui.clear();
|
||||
}
|
||||
|
||||
context.ui.clear();
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -540,7 +540,16 @@ export function KeypressProvider({
|
|||
}
|
||||
};
|
||||
|
||||
// Matches terminal query responses (DA1, DA2, Kitty protocol query)
|
||||
// that may arrive late from startup detection in kittyProtocolDetector.
|
||||
// These are never valid user input.
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const TERMINAL_RESPONSE_RE = /^\x1b\[[?>][\d;]*[uc]$/;
|
||||
|
||||
const handleKeypress = async (_: unknown, key: Key) => {
|
||||
if (TERMINAL_RESPONSE_RE.test(key.sequence)) {
|
||||
return;
|
||||
}
|
||||
if (key.sequence === FOCUS_IN || key.sequence === FOCUS_OUT) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,20 @@ export async function detectAndEnableKittyProtocol(): Promise<boolean> {
|
|||
const onTimeout = () => {
|
||||
timeoutId = undefined;
|
||||
process.stdin.removeListener('data', handleData);
|
||||
if (!originalRawMode) {
|
||||
process.stdin.setRawMode(false);
|
||||
}
|
||||
detectionComplete = true;
|
||||
resolve(false);
|
||||
|
||||
// Keep a drain handler briefly to consume any late-arriving terminal
|
||||
// responses that would otherwise leak into the application input.
|
||||
const drainHandler = () => {};
|
||||
process.stdin.on('data', drainHandler);
|
||||
|
||||
setTimeout(() => {
|
||||
process.stdin.removeListener('data', drainHandler);
|
||||
if (!originalRawMode) {
|
||||
process.stdin.setRawMode(false);
|
||||
}
|
||||
detectionComplete = true;
|
||||
resolve(false);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const handleData = (data: Buffer) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue