From 4fe7f6cde6a746a2a1c103958e41903da4e5a83d Mon Sep 17 00:00:00 2001 From: catlog22 Date: Tue, 13 Jan 2026 23:51:46 +0800 Subject: [PATCH] feat: enhance CLI discussion agent and multi-CLI planning with JSON string support; improve error handling and internationalization --- .claude/agents/cli-discuss-agent.md | 26 ++++++++++++++++--- .claude/commands/workflow/multi-cli-plan.md | 14 +++++----- .../dashboard-css/21-cli-toolmgmt.css | 22 ++++++++++++++-- ccw/src/templates/dashboard-js/i18n.js | 4 +++ .../dashboard-js/views/cli-manager.js | 23 ++++++++++++++-- 5 files changed, 75 insertions(+), 14 deletions(-) diff --git a/.claude/agents/cli-discuss-agent.md b/.claude/agents/cli-discuss-agent.md index a9173738..cf4c9c03 100644 --- a/.claude/agents/cli-discuss-agent.md +++ b/.claude/agents/cli-discuss-agent.md @@ -24,21 +24,25 @@ You are a multi-CLI collaborative discussion agent. You orchestrate multiple CLI task_description: string, // User's task or requirement round_number: number, // Current discussion round (1, 2, 3...) session: { id, folder }, // Session metadata - ace_context: { // From ACE semantic search + ace_context: { // From ACE semantic search (may be JSON string from orchestrator) relevant_files: string[], detected_patterns: string[], architecture_insights: string }, // Optional - previous_rounds: RoundResult[], // Results from previous rounds + previous_rounds: RoundResult[], // Results from previous rounds (may be JSON string from orchestrator) user_feedback: string | null, // User's feedback/clarification from last round - cli_config: { + cli_config: { // CLI configuration (may be JSON string from orchestrator) tools: string[], // CLI tools to use (default: ['gemini', 'codex']) timeout: number, // CLI timeout in ms fallback_chain: string[] // Fallback order } } + +// NOTE: When called from orchestrator, ace_context, previous_rounds, and cli_config +// may be passed as JSON strings (via JSON.stringify). The execute function parses +// these automatically - see "Input Parsing" section in Main Execution. ``` ## Output Schema @@ -475,7 +479,21 @@ function createDegradedAnalysis() { ```javascript async function execute(input) { const startTime = Date.now() - const { task_description, round_number, session, ace_context, previous_rounds, user_feedback, cli_config } = input + const { task_description, round_number, session, user_feedback, cli_config: cli_config_raw } = input + + // === Input Parsing === + // Parse stringified inputs from orchestrator (may be passed as JSON.stringify'd strings) + const ace_context = typeof input.ace_context === 'string' + ? JSON.parse(input.ace_context) + : (input.ace_context || {}) + + const previous_rounds = typeof input.previous_rounds === 'string' + ? JSON.parse(input.previous_rounds) + : (input.previous_rounds || []) + + const cli_config = typeof cli_config_raw === 'string' + ? JSON.parse(cli_config_raw) + : (cli_config_raw || { tools: ['gemini', 'codex'], timeout: 600000, fallback_chain: ['gemini', 'codex', 'qwen'] }) const roundFolder = `${session.folder}/rounds/${round_number}` Bash(`mkdir -p ${roundFolder}`) diff --git a/.claude/commands/workflow/multi-cli-plan.md b/.claude/commands/workflow/multi-cli-plan.md index eedb24ca..89509868 100644 --- a/.claude/commands/workflow/multi-cli-plan.md +++ b/.claude/commands/workflow/multi-cli-plan.md @@ -206,16 +206,18 @@ ${JSON.stringify(contextPackage, null, 2)} ## Previous Rounds ${analysisResults.length > 0 - ? analysisResults.map(r => `Round ${r.round}: ${r.summary}`).join('\n') + ? JSON.stringify(analysisResults, null, 2) : 'None (first round)'} ## User Feedback ${userFeedback || 'None'} ## CLI Configuration -- Tools: ${effectiveTools.join(', ')} -- Timeout: 600000ms -- Fallback Chain: gemini → codex → qwen +${JSON.stringify({ + tools: effectiveTools, + timeout: 600000, + fallback_chain: ['gemini', 'codex', 'qwen'] +}, null, 2)} ## Output Requirements Write: ${sessionFolder}/rounds/${currentRound}/synthesis.json @@ -461,7 +463,7 @@ const planningContext = { task_description: taskDescription, selected_solution: selectedSolution, analysis_rounds: analysisResults, - consensus_points: finalSynthesis.consensus_points, + consensus_points: finalSynthesis._internal?.cross_verification?.agreements || [], user_constraints: userDecision.constraints || null, ace_context: contextPackage, clarifications: sessionState.user_decisions @@ -514,7 +516,7 @@ ${selectedSolution.cons.map(c => `- ${c}`).join('\n')} ${selectedSolution.affected_files.map(f => `- ${f.file}:${f.line} - ${f.reason}`).join('\n')} ### Analysis Consensus -${finalSynthesis.consensus_points.map(p => `- ${p}`).join('\n')} +${(finalSynthesis._internal?.cross_verification?.agreements || []).map(p => `- ${p}`).join('\n')} ### User Constraints ${userDecision.constraints ? JSON.stringify(userDecision.constraints) : 'None specified'} diff --git a/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css b/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css index f5452109..c18f0a21 100644 --- a/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +++ b/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css @@ -746,8 +746,7 @@ } .file-browser-loading, -.file-browser-empty, -.file-browser-error { +.file-browser-empty { display: flex; align-items: center; justify-content: center; @@ -758,9 +757,28 @@ } .file-browser-error { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + min-height: 200px; + font-size: 0.875rem; + text-align: center; + padding: 1rem; + gap: 0.5rem; +} + +.file-browser-error p { + margin: 0; color: hsl(var(--destructive)); } +.file-browser-hint { + color: hsl(var(--muted-foreground)); + font-size: 0.8rem; +} + .file-browser-item { display: flex; align-items: center; diff --git a/ccw/src/templates/dashboard-js/i18n.js b/ccw/src/templates/dashboard-js/i18n.js index 46ad486d..5ea39135 100644 --- a/ccw/src/templates/dashboard-js/i18n.js +++ b/ccw/src/templates/dashboard-js/i18n.js @@ -278,6 +278,8 @@ const i18n = { 'cli.fileBrowserUp': 'Parent Directory', 'cli.fileBrowserHome': 'Home', 'cli.fileBrowserShowHidden': 'Show hidden files', + 'cli.fileBrowserApiError': 'Server restart required to enable file browser', + 'cli.fileBrowserManualHint': 'Type the full path above and click Select (e.g., C:\\Users\\name\\.gemini)', // CodexLens Configuration 'codexlens.config': 'CodexLens Configuration', @@ -2517,6 +2519,8 @@ const i18n = { 'cli.fileBrowserUp': '上级目录', 'cli.fileBrowserHome': '主目录', 'cli.fileBrowserShowHidden': '显示隐藏文件', + 'cli.fileBrowserApiError': '需要重启服务器以启用文件浏览器', + 'cli.fileBrowserManualHint': '请在上方输入完整路径后点击选择(如 C:\\Users\\用户名\\.gemini)', // CodexLens 配置 'codexlens.config': 'CodexLens 配置', diff --git a/ccw/src/templates/dashboard-js/views/cli-manager.js b/ccw/src/templates/dashboard-js/views/cli-manager.js index 1516fcf5..fae4e824 100644 --- a/ccw/src/templates/dashboard-js/views/cli-manager.js +++ b/ccw/src/templates/dashboard-js/views/cli-manager.js @@ -659,7 +659,17 @@ async function loadFileBrowserDirectory(path) { } catch (err) { console.error('Failed to load directory:', err); if (listContainer) { - listContainer.innerHTML = '
Failed to load directory
'; + listContainer.innerHTML = '
' + + '

' + t('cli.fileBrowserApiError') + '

' + + '

' + t('cli.fileBrowserManualHint') + '

' + + '
'; + } + // Enable manual path entry mode - enable select button when path is typed + var selectBtn = document.getElementById('fileBrowserSelectBtn'); + var pathInput = document.getElementById('fileBrowserPathInput'); + if (selectBtn && pathInput) { + selectBtn.disabled = false; + pathInput.focus(); } } } @@ -744,8 +754,17 @@ function initFileBrowserEvents() { var selectBtn = document.getElementById('fileBrowserSelectBtn'); if (selectBtn) { selectBtn.onclick = function() { + // First try selected path from list, then fall back to path input var path = selectBtn.getAttribute('data-selected-path'); - closeFileBrowserModal(path); + if (!path) { + var pathInput = document.getElementById('fileBrowserPathInput'); + if (pathInput && pathInput.value.trim()) { + path = pathInput.value.trim(); + } + } + if (path) { + closeFileBrowserModal(path); + } }; }