diff --git a/.claude/workflows/cli-tools-usage.md b/.claude/workflows/cli-tools-usage.md index 071ab5df..f88d6387 100644 --- a/.claude/workflows/cli-tools-usage.md +++ b/.claude/workflows/cli-tools-usage.md @@ -14,7 +14,7 @@ ### Configuration File -**Path**: `.claude/cli-tools.json` +**Path**: `~/.claude/cli-tools.json` All tool availability, model selection, and routing are defined in this configuration file. diff --git a/ccw/src/core/routes/claude-routes.ts b/ccw/src/core/routes/claude-routes.ts index e90678f1..5bec67c2 100644 --- a/ccw/src/core/routes/claude-routes.ts +++ b/ccw/src/core/routes/claude-routes.ts @@ -1002,7 +1002,6 @@ export async function handleClaudeRoutes(ctx: RouteContext): Promise { if (isCodex) { // Codex: Direct content concatenation (does not support @ references) const chineseSectionPattern = /\n*## 中文回复\n[\s\S]*?(?=\n## |$)/; - const cliToolsSectionPattern = /\n*## CLI \u5de5\u5177\u8c03\u7528\n[\s\S]*?(?=\n## |$)/; if (enabled) { // Check if section already exists @@ -1013,34 +1012,12 @@ export async function handleClaudeRoutes(ctx: RouteContext): Promise { // Read chinese-response.md content const chineseResponseContent = readFileSync(userGuidelinesPath, 'utf8'); - // Read cli-tools-usage.md content - const cliToolsUsagePath = join(homedir(), '.claude', 'workflows', 'cli-tools-usage.md'); - let cliToolsUsageContent = ''; - if (existsSync(cliToolsUsagePath)) { - cliToolsUsageContent = readFileSync(cliToolsUsagePath, 'utf8'); - } - - // Read and format cli-tools.json - const cliToolsJsonPath = join(homedir(), '.claude', 'cli-tools.json'); - let cliToolsJsonContent = ''; - if (existsSync(cliToolsJsonPath)) { - const cliToolsJson = JSON.parse(readFileSync(cliToolsJsonPath, 'utf8')); - cliToolsJsonContent = `\n### CLI Tools Configuration\n\n\`\`\`json\n${JSON.stringify(cliToolsJson, null, 2)}\n\`\`\`\n`; - } - - // Add Chinese response section - let newSection = `\n## 中文回复\n\n${chineseResponseContent}\n`; - - // Add CLI tools section if usage content exists - if (cliToolsUsageContent) { - newSection += `\n## CLI 工具调用\n\n${cliToolsUsageContent}\n${cliToolsJsonContent}`; - } - + // Add Chinese response section only + const newSection = `\n## 中文回复\n\n${chineseResponseContent}\n`; content = content.trimEnd() + '\n' + newSection; } else { - // Remove both sections + // Remove Chinese response section content = content.replace(chineseSectionPattern, '\n'); - content = content.replace(cliToolsSectionPattern, '\n'); content = content.replace(/\n{3,}/g, '\n\n').trim(); if (content) content += '\n'; } @@ -1082,6 +1059,120 @@ export async function handleClaudeRoutes(ctx: RouteContext): Promise { return true; } + // API: Get Codex CLI Enhancement setting status + if (pathname === '/api/language/codex-cli-enhancement' && req.method === 'GET') { + try { + const userCodexPath = join(homedir(), '.codex', 'AGENTS.md'); + const cliEnhancementSectionPattern = /## CLI 工具调用/; // For Codex CLI enhancement + + let enabled = false; + let guidelinesPath = ''; + + // Check if user AGENTS.md exists and contains CLI enhancement section + if (existsSync(userCodexPath)) { + const content = readFileSync(userCodexPath, 'utf8'); + enabled = cliEnhancementSectionPattern.test(content); + } + + // Find guidelines file path + const userGuidelinesPath = join(homedir(), '.claude', 'workflows', 'cli-tools-usage.md'); + + if (existsSync(userGuidelinesPath)) { + guidelinesPath = userGuidelinesPath; + } + + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ + enabled, + guidelinesPath, + guidelinesExists: !!guidelinesPath, + userCodexAgentsExists: existsSync(userCodexPath) + })); + return true; + } catch (error) { + res.writeHead(500, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ error: (error as Error).message })); + return true; + } + } + + // API: Toggle Codex CLI Enhancement setting + if (pathname === '/api/language/codex-cli-enhancement' && req.method === 'POST') { + handlePostRequest(req, res, async (body: any) => { + const { enabled } = body; + + if (typeof enabled !== 'boolean') { + return { error: 'Missing or invalid enabled parameter', status: 400 }; + } + + try { + const targetDir = join(homedir(), '.codex'); + const targetFile = join(targetDir, 'AGENTS.md'); + + // Ensure target directory exists + if (!existsSync(targetDir)) { + mkdirSync(targetDir, { recursive: true }); + } + + let content = ''; + if (existsSync(targetFile)) { + content = readFileSync(targetFile, 'utf8'); + } else { + // Create new file with minimal header + content = '# Codex Code Guidelines\n\n'; + } + + const cliEnhancementSectionPattern = /\n*## CLI 工具调用\n[\s\S]*?(?=\n## |$)/; + + if (enabled) { + // Check if section already exists + if (cliEnhancementSectionPattern.test(content)) { + return { success: true, message: 'Already enabled' }; + } + + // Read cli-tools-usage.md content + const cliToolsUsagePath = join(homedir(), '.claude', 'workflows', 'cli-tools-usage.md'); + let cliToolsUsageContent = ''; + if (existsSync(cliToolsUsagePath)) { + cliToolsUsageContent = readFileSync(cliToolsUsagePath, 'utf8'); + } else { + return { error: 'CLI tools usage guidelines file not found at ~/.claude/workflows/cli-tools-usage.md', status: 404 }; + } + + // Read and format cli-tools.json + const cliToolsJsonPath = join(homedir(), '.claude', 'cli-tools.json'); + let cliToolsJsonContent = ''; + if (existsSync(cliToolsJsonPath)) { + const cliToolsJson = JSON.parse(readFileSync(cliToolsJsonPath, 'utf8')); + cliToolsJsonContent = `\n### CLI Tools Configuration\n\n\`\`\`json\n${JSON.stringify(cliToolsJson, null, 2)}\n\`\`\`\n`; + } + + // Add CLI enhancement section + const newSection = `\n## CLI 工具调用\n\n${cliToolsUsageContent}\n${cliToolsJsonContent}`; + content = content.trimEnd() + '\n' + newSection; + } else { + // Remove CLI enhancement section + content = content.replace(cliEnhancementSectionPattern, '\n'); + content = content.replace(/\n{3,}/g, '\n\n').trim(); + if (content) content += '\n'; + } + + writeFileSync(targetFile, content, 'utf8'); + + // Broadcast update + broadcastToClients({ + type: 'CLI_ENHANCEMENT_SETTING_CHANGED', + data: { cliEnhancement: enabled } + }); + + return { success: true, enabled }; + } catch (error) { + return { error: (error as Error).message, status: 500 }; + } + }); + return true; + } + // API: Get Windows platform setting status if (pathname === '/api/language/windows-platform' && req.method === 'GET') { try { diff --git a/ccw/src/templates/dashboard-js/views/cli-manager.js b/ccw/src/templates/dashboard-js/views/cli-manager.js index 53753b34..c89536f0 100644 --- a/ccw/src/templates/dashboard-js/views/cli-manager.js +++ b/ccw/src/templates/dashboard-js/views/cli-manager.js @@ -1613,6 +1613,8 @@ var chineseResponseEnabled = false; var chineseResponseLoading = false; var codexChineseResponseEnabled = false; var codexChineseResponseLoading = false; +var codexCliEnhancementEnabled = false; +var codexCliEnhancementLoading = false; var windowsPlatformEnabled = false; var windowsPlatformLoading = false; @@ -1647,6 +1649,20 @@ async function loadWindowsPlatformSettings() { } } +async function loadCodexCliEnhancementSettings() { + try { + var response = await fetch('/api/language/codex-cli-enhancement'); + if (!response.ok) throw new Error('Failed to load Codex CLI enhancement settings'); + var data = await response.json(); + codexCliEnhancementEnabled = data.enabled || false; + return data; + } catch (err) { + console.error('Failed to load Codex CLI enhancement settings:', err); + codexCliEnhancementEnabled = false; + return { enabled: false, guidelinesExists: false }; + } +} + async function toggleChineseResponse(enabled, target) { // target: 'claude' (default) or 'codex' target = target || 'claude'; @@ -1763,6 +1779,55 @@ async function toggleWindowsPlatform(enabled) { } } +async function toggleCodexCliEnhancement(enabled) { + if (codexCliEnhancementLoading) return; + + // Pre-check: verify CCW workflows are installed (only when enabling) + if (enabled && typeof ccwInstallStatus !== 'undefined' && !ccwInstallStatus.installed) { + var missingFile = ccwInstallStatus.missingFiles.find(function(f) { return f === 'cli-tools-usage.md'; }); + if (missingFile) { + showRefreshToast(t('lang.installRequired'), 'warning'); + return; + } + } + + codexCliEnhancementLoading = true; + + try { + var response = await fetch('/api/language/codex-cli-enhancement', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ enabled: enabled }) + }); + + if (!response.ok) { + var errData = await response.json(); + // Show specific error message from backend + var errorMsg = errData.error || 'Failed to update setting'; + if (errorMsg.includes('not found')) { + showRefreshToast(t('lang.installRequired'), 'warning'); + } else { + showRefreshToast((enabled ? t('lang.enableFailed') : t('lang.disableFailed')) + ': ' + errorMsg, 'error'); + } + throw new Error(errorMsg); + } + + var data = await response.json(); + codexCliEnhancementEnabled = data.enabled; + + // Update UI + renderLanguageSettingsSection(); + + // Show toast + showRefreshToast('Codex CLI Enhancement: ' + (enabled ? t('lang.enableSuccess') : t('lang.disableSuccess')), 'success'); + } catch (err) { + console.error('Failed to toggle Codex CLI enhancement:', err); + // Error already shown in the !response.ok block + } finally { + codexCliEnhancementLoading = false; + } +} + async function renderLanguageSettingsSection() { var container = document.getElementById('language-settings-section'); if (!container) return; @@ -1774,6 +1839,9 @@ async function renderLanguageSettingsSection() { if (!windowsPlatformEnabled && !windowsPlatformLoading) { await loadWindowsPlatformSettings(); } + if (!codexCliEnhancementEnabled && !codexCliEnhancementLoading) { + await loadCodexCliEnhancementSettings(); + } var settingsHtml = '
' + '
' + @@ -1832,6 +1900,23 @@ async function renderLanguageSettingsSection() { '
' + '

' + t('lang.windowsDesc') + '

' + '
' + + // CLI Enhancement - Codex + '
' + + '' + + '
' + + '' + + '' + + (codexCliEnhancementEnabled ? t('lang.enabled') : t('lang.disabled')) + + '' + + '
' + + '

为 Codex 启用多 CLI 工具调用功能,自动拼接 cli-tools-usage.md 和 cli-tools.json 配置

' + + '
' + ''; container.innerHTML = settingsHtml;