mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-02 21:50:52 +00:00
feat(vscode-ide-companion): support /insight command (#2593)
* feat(vscode-ide-companion): support /insight command Add ACP support for /insight progress streaming and report opening in the VSCode companion. Resolves #2023 * fix(cli): defer insight command runtime deps * test(cli): cover acp slash command allowlist * Revert "test(cli): cover acp slash command allowlist" This reverts commit3209274ab6. * Revert "fix(cli): defer insight command runtime deps" This reverts commit3b08491e46. * Reapply "fix(cli): defer insight command runtime deps" This reverts commit386c5c67d3. * Reapply "test(cli): cover acp slash command allowlist" This reverts commite2716140dd. * refactor(cli): simplify insight ACP integration - Replace `formatAcpInsightProgress` with `encodeAcpInsightProgress` using JSON payload - Move imports to top-level, no longer defer loading for non-ACP mode - Remove `INSIGHT_READY_MARKER` parsing from Session.ts as it's now handled by WebViewProvider * refactor: extract insight protocol markers to core package Move INSIGHT_PROGRESS_MARKER and INSIGHT_READY_MARKER from cli and vscode-ide-companion packages to @qwen-code/qwen-code-core for better shareability and to avoid duplication. Also extract ACP_ALLOWED_COMMANDS constant in Session.ts to improve readability and maintainability. * refactor(vscode-ide-companion): extract test helper to reduce webview mock duplication Introduce `setupAttachedProvider()` helper in WebViewProvider.test.ts to eliminate ~160 lines of repeated webview mock + provider setup code across 5 insight-related test cases. * feat(cli): 添加ACP执行模式到内置命令 当ACP启用时,将executionMode参数传递给所有内置命令, 使命令能够识别当前运行在ACP模式下并相应地调整行为。 test(cli): 为insight命令添加ACP进度消息流测试 新增测试验证insight命令在ACP模式下能够正确流式传输 进度消息,而不必等待生成完成。测试涵盖了从开始到完 成的整个进度更新过程。 refactor(core): 重构insight协议消息格式 将insight进度和就绪消息从基于标记字符串的格式 改为结构化的JSON格式,提供更好的类型安全和解析 可靠性。 feat(vscode-ide-companion): 支持新的insight消息协议 更新WebViewProvider以支持新的结构化insight消息协 议,能够正确解析和处理来自CLI的进度和就绪消息。 ``` * fix(vscode-ide-companion/insight): streamline insight progress handling Trim redundant CLI insight coverage around the ACP path. Keep the VS Code insight progress flow aligned with normalized slash commands and the updated progress layout. * fix(insight): restore slash commands after webview reload Cache available commands in the VS Code provider so webview restoration still exposes /insight without a manual login. Also remove the unused progress bar markup to keep the UI diff smaller. * Update packages/webui/src/index.ts Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> * fix(webui): remove duplicate insight card export --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
This commit is contained in:
parent
41f71ab7e7
commit
7cded6e0df
17 changed files with 914 additions and 16 deletions
|
|
@ -11,7 +11,12 @@ import type { HistoryItemInsightProgress } from '../types.js';
|
|||
import { t } from '../../i18n/index.js';
|
||||
import { join } from 'path';
|
||||
import { StaticInsightGenerator } from '../../services/insight/generators/StaticInsightGenerator.js';
|
||||
import { createDebugLogger, Storage } from '@qwen-code/qwen-code-core';
|
||||
import {
|
||||
createDebugLogger,
|
||||
encodeInsightProgressMessage,
|
||||
encodeInsightReadyMessage,
|
||||
Storage,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import open from 'open';
|
||||
|
||||
const logger = createDebugLogger('DataProcessor');
|
||||
|
|
@ -36,6 +41,104 @@ export const insightCommand: SlashCommand = {
|
|||
context.services.config,
|
||||
);
|
||||
|
||||
if (context.executionMode === 'acp') {
|
||||
const pendingMessages: Array<{
|
||||
messageType: 'info' | 'error';
|
||||
content: string;
|
||||
}> = [];
|
||||
let isComplete = false;
|
||||
let resume: (() => void) | null = null;
|
||||
|
||||
const flushResume = () => {
|
||||
const resolve = resume;
|
||||
if (!resolve) {
|
||||
return;
|
||||
}
|
||||
resume = null;
|
||||
resolve();
|
||||
};
|
||||
|
||||
const pushMessage = (message: {
|
||||
messageType: 'info' | 'error';
|
||||
content: string;
|
||||
}) => {
|
||||
pendingMessages.push(message);
|
||||
flushResume();
|
||||
};
|
||||
|
||||
const streamMessages = async function* (): AsyncGenerator<
|
||||
{ messageType: 'info' | 'error'; content: string },
|
||||
void,
|
||||
unknown
|
||||
> {
|
||||
while (!isComplete || pendingMessages.length > 0) {
|
||||
if (pendingMessages.length === 0) {
|
||||
await new Promise<void>((resolve) => {
|
||||
resume = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
while (pendingMessages.length > 0) {
|
||||
const message = pendingMessages.shift();
|
||||
if (message) {
|
||||
yield message;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
pushMessage({
|
||||
messageType: 'info',
|
||||
content: t('This may take a couple minutes. Sit tight!'),
|
||||
});
|
||||
pushMessage({
|
||||
messageType: 'info',
|
||||
content: encodeInsightProgressMessage(
|
||||
t('Starting insight generation...'),
|
||||
0,
|
||||
),
|
||||
});
|
||||
|
||||
const outputPath = await insightGenerator.generateStaticInsight(
|
||||
projectsDir,
|
||||
(stage, progress, detail) => {
|
||||
pushMessage({
|
||||
messageType: 'info',
|
||||
content: encodeInsightProgressMessage(
|
||||
stage,
|
||||
progress,
|
||||
detail,
|
||||
),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
pushMessage({
|
||||
messageType: 'info',
|
||||
content: encodeInsightReadyMessage(outputPath),
|
||||
});
|
||||
} catch (error) {
|
||||
pushMessage({
|
||||
messageType: 'error',
|
||||
content: t('Failed to generate insights: {{error}}', {
|
||||
error: (error as Error).message,
|
||||
}),
|
||||
});
|
||||
logger.error('Insight generation error:', error);
|
||||
} finally {
|
||||
isComplete = true;
|
||||
flushResume();
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
type: 'stream_messages',
|
||||
messages: streamMessages(),
|
||||
};
|
||||
}
|
||||
|
||||
const updateProgress = (
|
||||
stage: string,
|
||||
progress: number,
|
||||
|
|
@ -60,16 +163,13 @@ export const insightCommand: SlashCommand = {
|
|||
Date.now(),
|
||||
);
|
||||
|
||||
// Initial progress
|
||||
updateProgress(t('Starting insight generation...'), 0);
|
||||
|
||||
// Generate the static insight HTML file
|
||||
const outputPath = await insightGenerator.generateStaticInsight(
|
||||
projectsDir,
|
||||
updateProgress,
|
||||
);
|
||||
|
||||
// Clear pending item
|
||||
context.ui.setPendingItem(null);
|
||||
|
||||
context.ui.addItem(
|
||||
|
|
@ -80,7 +180,6 @@ export const insightCommand: SlashCommand = {
|
|||
Date.now(),
|
||||
);
|
||||
|
||||
// Open the file in the default browser
|
||||
try {
|
||||
await open(outputPath);
|
||||
|
||||
|
|
@ -111,8 +210,8 @@ export const insightCommand: SlashCommand = {
|
|||
}
|
||||
|
||||
context.ui.setDebugMessage(t('Insights ready.'));
|
||||
return;
|
||||
} catch (error) {
|
||||
// Clear pending item on error
|
||||
context.ui.setPendingItem(null);
|
||||
|
||||
context.ui.addItem(
|
||||
|
|
@ -126,6 +225,7 @@ export const insightCommand: SlashCommand = {
|
|||
);
|
||||
|
||||
logger.error('Insight generation error:', error);
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue