From e8b9bcae923d2743a34aa5b15a8728f86adc75aa Mon Sep 17 00:00:00 2001 From: catlog22 Date: Thu, 25 Dec 2025 18:29:57 +0800 Subject: [PATCH] feat: Add ccw-litellm uninstall button and fix npm install path resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix ccw-litellm path lookup for npm distribution by adding PACKAGE_ROOT - Add uninstall button to API Settings page for ccw-litellm - Add /api/litellm-api/ccw-litellm/uninstall endpoint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- ccw/src/core/routes/litellm-api-routes.ts | 50 +++++++++++++++++++ .../dashboard-js/views/api-settings.js | 44 ++++++++++++++++ package.json | 2 +- 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/ccw/src/core/routes/litellm-api-routes.ts b/ccw/src/core/routes/litellm-api-routes.ts index b452809e..3343e21b 100644 --- a/ccw/src/core/routes/litellm-api-routes.ts +++ b/ccw/src/core/routes/litellm-api-routes.ts @@ -4,6 +4,15 @@ * Handles LiteLLM provider management, endpoint configuration, and cache management */ import type { IncomingMessage, ServerResponse } from 'http'; +import { fileURLToPath } from 'url'; +import { dirname, join as pathJoin } from 'path'; + +// Get current module path for package-relative lookups +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +// Package root: routes -> core -> src -> ccw -> package root +const PACKAGE_ROOT = pathJoin(__dirname, '..', '..', '..', '..'); + import { getAllProviders, getProvider, @@ -813,6 +822,7 @@ export async function handleLiteLLMApiRoutes(ctx: RouteContext): Promise { + try { + const { spawn } = await import('child_process'); + + return new Promise((resolve) => { + const proc = spawn('pip', ['uninstall', '-y', 'ccw-litellm'], { shell: true, timeout: 120000 }); + let output = ''; + let error = ''; + proc.stdout?.on('data', (data) => { output += data.toString(); }); + proc.stderr?.on('data', (data) => { error += data.toString(); }); + proc.on('close', (code) => { + // Clear status cache after uninstallation attempt + clearCcwLitellmStatusCache(); + + if (code === 0) { + broadcastToClients({ + type: 'CCW_LITELLM_UNINSTALLED', + payload: { timestamp: new Date().toISOString() } + }); + resolve({ success: true, message: 'ccw-litellm uninstalled successfully' }); + } else { + // Check if package was not installed + if (error.includes('not installed') || output.includes('not installed')) { + resolve({ success: true, message: 'ccw-litellm was not installed' }); + } else { + resolve({ success: false, error: error || output || 'Uninstallation failed' }); + } + } + }); + proc.on('error', (err) => resolve({ success: false, error: err.message })); + }); + } catch (err) { + return { success: false, error: (err as Error).message }; + } + }); + return true; + } + return false; } diff --git a/ccw/src/templates/dashboard-js/views/api-settings.js b/ccw/src/templates/dashboard-js/views/api-settings.js index 0a9fc282..2869567c 100644 --- a/ccw/src/templates/dashboard-js/views/api-settings.js +++ b/ccw/src/templates/dashboard-js/views/api-settings.js @@ -3245,6 +3245,9 @@ function renderCcwLitellmStatusCard() { '' + 'ccw-litellm ' + (status.version || '') + '' + + '' + ''; } else { container.innerHTML = @@ -3299,10 +3302,51 @@ async function installCcwLitellm() { } } +/** + * Uninstall ccw-litellm package + */ +async function uninstallCcwLitellm() { + if (!confirm('Are you sure you want to uninstall ccw-litellm? This will disable LiteLLM features.')) { + return; + } + + var container = document.getElementById('ccwLitellmStatusContainer'); + if (container) { + container.innerHTML = + '
' + + '
' + + 'Uninstalling ccw-litellm...' + + '
'; + } + + try { + var response = await fetch('/api/litellm-api/ccw-litellm/uninstall', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({}) + }); + + var result = await response.json(); + + if (result.success) { + showRefreshToast('ccw-litellm uninstalled successfully!', 'success'); + await checkCcwLitellmStatus(true); + renderCcwLitellmStatusCard(); + } else { + showRefreshToast('Failed to uninstall ccw-litellm: ' + result.error, 'error'); + renderCcwLitellmStatusCard(); + } + } catch (e) { + showRefreshToast('Uninstall error: ' + e.message, 'error'); + renderCcwLitellmStatusCard(); + } +} + // Make functions globally accessible window.checkCcwLitellmStatus = checkCcwLitellmStatus; window.renderCcwLitellmStatusCard = renderCcwLitellmStatusCard; window.installCcwLitellm = installCcwLitellm; +window.uninstallCcwLitellm = uninstallCcwLitellm; // ========== Utility Functions ========== diff --git a/package.json b/package.json index 3c62613a..4cf02771 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-code-workflow", - "version": "6.2.9", + "version": "6.3.0", "description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution", "type": "module", "main": "ccw/src/index.js",